Skip to content

Conversation

@phernandez
Copy link
Member

Summary\n- add MCP UI resources (search/note preview) with variant switching via BASIC_MEMORY_MCP_UI_VARIANT and variant-specific URIs for the bakeoff\n- scaffold tool-ui React bundle + build script to inline JS/CSS into MCP resource HTML; keep sources under ui/tool-ui-react\n- add ASCII/ANSI output paths for search_notes/read_note plus tests; add MCP-UI SDK embedded resource tools (search_notes_ui, read_note_ui) and doc for bakeoff steps\n- register resources in CLI/tests and document bakeoff/test plan in docs/mcp-ui-bakeoff-instructions.md\n\n## Testing\n- uv run pytest test-int/mcp/test_output_format_ascii_integration.py test-int/mcp/test_ui_sdk_integration.py\n- npm run build (in ui/tool-ui-react)

Signed-off-by: phernandez <paul@basicmachines.co>
@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

Claude finished @phernandez's task in 3m 8s —— View job


PR Review: MCP UI variants and TUI output

I've completed a comprehensive review of this PR against the Basic Memory team checklist. This is a well-structured implementation that adds three UI presentation paths for MCP tools.


✅ Code Quality & Standards

Strengths

  • Python 3.12+ compliance: Full type annotations throughout (src/basic_memory/mcp/formatting.py:15-18, src/basic_memory/mcp/tools/ui_sdk.py:23-37)
  • Async patterns: Proper async/await usage in MCP tools (src/basic_memory/mcp/tools/ui_sdk.py:24-53)
  • FastAPI/Typer conventions: Followed correctly
  • No commented-out code: Clean implementation
  • Import order: Correct (standard lib, third-party, local)
  • Naming conventions: Proper snake_case and PascalCase usage

Issues Found

1. Line Length Violation

Location: src/basic_memory/mcp/formatting.py:87

summary = f"Results: {len(results)} | Page: {result.current_page} | Page size: {result.page_size}"

Issue: 101 characters (exceeds 100-char limit)
Fix: Fix line length →


✅ Testing & Documentation

Test Coverage

  • Integration tests provided: Two test files cover the new functionality
    • test-int/mcp/test_output_format_ascii_integration.py (78 lines) - Tests ASCII/ANSI output formats
    • test-int/mcp/test_ui_sdk_integration.py (70 lines) - Tests MCP-UI SDK embedded resources
  • Test quality: Good coverage of core functionality with proper async patterns
  • Optional dependency handling: pytest.importorskip("mcp_ui_server") correctly used (line 8 of test_ui_sdk_integration.py)

Documentation

  • Excellent documentation: docs/mcp-ui-bakeoff-instructions.md provides comprehensive setup and testing instructions
  • Clear test plan: Documents three presentation paths with expected outputs
  • Build instructions: React build process clearly documented

Coverage Concerns

⚠️ Missing test coverage for error paths:

  1. src/basic_memory/mcp/ui/sdk.py:11-13: ImportError handling for optional mcp_ui_server dependency

    • Lines 11-13 marked with # pragma: no cover - handled by callers
    • However, MissingMCPUIServerError exception path in ui_sdk.py:76-77 should be tested
    • Recommendation: Add a test that verifies the error message when mcp_ui_server is not installed
  2. src/basic_memory/mcp/formatting.py: All new code appears testable

    • ASCII formatting functions have clear inputs/outputs
    • Should have 100% coverage from integration tests
  3. React/TypeScript code: Not covered by Python test suite (expected)

    • Consider adding basic smoke tests for React builds in CI

✅ Basic Memory Architecture

Alignment with Principles

  • MCP tools atomic & composable: ✅ New tools follow existing patterns
  • Local-first architecture: ✅ No cloud dependencies introduced
  • Knowledge graph consistency: ✅ Read-only presentation layer, no data mutations
  • Markdown file integrity: ✅ Only formatting changes, no file modifications

Architecture Decisions

1. Tool Registration (src/basic_memory/mcp/tools/__init__.py:14)

from basic_memory.mcp.tools.ui_sdk import read_note_ui, search_notes_ui

✅ Proper registration of new UI SDK tools

2. Resource Registration (src/basic_memory/mcp/resources/__init__.py)
✅ Clean separation of UI resources with variant-specific URIs:

  • ui://basic-memory/search-results (variant-dependent)
  • ui://basic-memory/search-results/vanilla (explicit vanilla)
  • ui://basic-memory/search-results/tool-ui (explicit tool-ui)
  • ui://basic-memory/search-results/mcp-ui (explicit mcp-ui)

3. Output Format Extension (src/basic_memory/mcp/tools/search.py:209, read_note.py:27)

output_format: Literal["default", "ascii", "ansi"] = "default"

✅ Clean extension of existing tools without breaking changes

4. Formatting Module (src/basic_memory/mcp/formatting.py)
✅ Well-structured helper functions with clear responsibilities:

  • Style application (ANSI codes)
  • Frontmatter stripping
  • Table formatting
  • Result extraction

✅ Security & Performance

Security Review

  • No hardcoded secrets: ✅ Verified
  • Environment variable usage: ✅ Only BASIC_MEMORY_MCP_UI_VARIANT (safe, non-sensitive)
  • Input validation: ✅ Inherited from parent tools (read_note, search_notes)
  • Path traversal protection: ✅ Handled by parent tools
  • Error handling: ✅ Graceful fallback for missing optional dependency

Performance Considerations

  • HTML template loading: Uses Path.read_text() - no caching evident
    • Minor optimization opportunity: Consider caching loaded HTML templates in production
  • React bundle inlining: Single-file HTML with embedded CSS/JS is reasonable for MCP resources
  • ASCII formatting: Simple string operations, no performance concerns

✅ Windows Compatibility

Path Operations

Proper use of pathlib: src/basic_memory/mcp/ui/templates.py:20

path = Path(__file__).parent / "html" / filename
  • Uses Path and / operator which is cross-platform
  • No hardcoded forward slashes in path strings

Console Output

No emoji/unicode in console output in NEW code:

  • Checked: formatting.py, ui/sdk.py, tools/ui_sdk.py, resources/ui.py
  • All ASCII-safe (uses standard characters like +, -, | for tables)
  • ANSI codes used conditionally via color parameter

Note: Existing code in project_management.py and recent_activity.py uses unicode bullets (•) and checkmarks (✓), but these are NOT part of this PR.


React/UI Components Review

Build System (ui/tool-ui-react/build.mjs)

✅ Clean build process:

  • esbuild for bundling
  • Tailwind CSS compilation
  • Inline CSS/JS into single HTML files
  • Output to src/basic_memory/mcp/ui/html/

Component Structure

✅ Well-organized:

  • src/search-results.tsx - Search results table with DataTable component
  • src/note-preview.tsx - Note preview with markdown rendering
  • Shared UI components from Radix UI
  • Proper TypeScript types

Potential Improvements

  • Error boundaries: Present in data-table/error-boundary.tsx
  • Type safety: Uses Zod for schema validation ✅
  • Accessibility: Radix UI components are accessible ✅

Summary & Recommendations

Critical Issues

  1. Line length violation in formatting.py:87 - Must be fixed to meet 100-char limit

Minor Improvements

  1. Test coverage: Add test for MissingMCPUIServerError path in ui_sdk.py
  2. Performance: Consider caching HTML templates if they're loaded frequently
  3. Documentation: Consider adding React component documentation

Architecture Assessment

This PR follows a clean, extensible design:

  • Three presentation paths for flexibility (MCP App resources, MCP-UI SDK, ASCII/ANSI)
  • Variant switching via environment variable is simple and effective
  • No breaking changes to existing tools
  • Proper separation of concerns (formatting, resources, tools)

Overall Quality

Strong implementation that adheres to Basic Memory conventions with one minor line-length issue. The code is well-structured, properly tested (with room for minor coverage improvement), and follows the project's architectural principles.


Checklist Results

  • ✅ Follows Basic Memory's coding conventions in CLAUDE.md

  • ✅ Python 3.12+ type annotations and async patterns

  • ✅ SQLAlchemy 2.0 best practices (N/A - no DB changes)

  • ✅ FastAPI and Typer conventions followed

  • ⚠️ 100-character line length limit - 1 violation found

  • ✅ No commented-out code blocks

  • ✅ Unit tests for new functions/methods

  • ✅ Integration tests for new MCP tools

  • ⚠️ Test coverage for edge cases - Could add MissingMCPUIServerError test

  • ⚠️ 100% test coverage - Optional dependency import path excluded (acceptable with pragma)

  • ✅ Documentation updated (excellent bakeoff instructions)

  • ✅ CLAUDE.md updated (N/A - no convention changes)

  • ✅ MCP tools follow atomic, composable design

  • ✅ Database changes include Alembic migrations (N/A)

  • ✅ Preserves local-first architecture principles

  • ✅ Knowledge graph operations maintain consistency

  • ✅ Markdown file handling preserves integrity

  • ✅ AI-human collaboration patterns followed

  • ✅ No hardcoded secrets or credentials

  • ✅ Input validation for MCP tools

  • ✅ Proper error handling and logging

  • ✅ Performance considerations addressed

  • ✅ No sensitive data in logs or commits

  • ✅ File path comparisons windows compatible (uses pathlib)

  • ✅ Avoid emojis/unicode in console output

Recommendation: Approve after fixing the line-length issue. This is high-quality work that adds valuable UI flexibility to Basic Memory's MCP integration.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5d3fc78c21

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +18 to +22
function stripFrontmatter(text: string): string {
if (!text.startsWith("---")) return text;
const end = text.indexOf("---", 3);
if (end === -1) return text;
return text.slice(end + 3).trim();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard frontmatter stripping against inline '---'

The Tool‑UI stripFrontmatter helper treats the first --- substring after position 3 as the closing delimiter. That means YAML values like title: "foo --- bar" (or any early --- in frontmatter) will be misinterpreted as the end of frontmatter, causing the preview to drop the rest of the note. This truncation only happens when frontmatter contains ---, but it yields incorrect previews in those cases. Consider matching a delimiter on its own line (e.g., \n---\n) instead of indexOf.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant