feat(mcp): add Resources for push-based context delivery#84
Conversation
- Server: replace 409 rejection with context cancellation of active stream - VSCode: abort in-flight request before sending new message - Keybinding: simplify ghost.openEditor to alt+g
Adds two MCP Resources to the Ghost server alongside the existing tools:
- ghost://project/{project_id}/context (ResourceTemplate)
Returns top 20 memories + learned context for a project.
project_id resolves by name or hash ID.
Clients (Claude Code) can pin this resource so it survives
context compaction without requiring a tool call.
- ghost://memories/global (Resource)
Returns all cross-project memories saved via ghost_save_global.
Personal preferences, global conventions, toolchain facts.
Also extracts buildProjectContext() helper for testability.
Adds 5 tests covering: memories, empty state, global inclusion,
learned context, and panic-free registration.
Fixes the core gap: MCP was pull-only (Claude must ask), while
the TUI pushes memories into every prompt via BuildSystemBlocks.
Resources make Ghost's memory reliably available to external
clients after context compaction.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds two MCP resources for project and global memory retrieval, centralizes project-context assembly, registers resources during server init, updates chat streaming to use per-request cancelable contexts that supersede prior streams, and tweaks VS Code extension keybinding and client-side abort behavior. Changes
Sequence DiagramsequenceDiagram
participant Client as MCP Client
participant Server as MCP Server
participant Store as Memory Store
Client->>Server: Request resource ghost://project/{id}/context
activate Server
Server->>Server: Parse URI → project_id
Server->>Store: GetTopMemories(ctx, project_id, 20)
Store-->>Server: Project memories
Server->>Store: GetLearnedContext(ctx, project_id)
Store-->>Server: Learned context
Server->>Server: buildProjectContext() → assembled text
Server-->>Client: Project context resource
deactivate Server
Client->>Server: Request resource ghost://memories/global
activate Server
Server->>Store: GetTopMemories(ctx, "_global", 50)
Store-->>Server: Global memories
Server->>Server: Format memory list
Server-->>Client: Global memories resource
deactivate Server
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
internal/mcpserver/mcpserver_test.go (1)
257-268:TestNew_RegistersResourcesshould assert registration effects, not just construction.This currently overlaps with
TestNew_CreatesServerand won’t fail if resource registration is accidentally removed butNew()still succeeds. Consider asserting a read/discovery path for both resource URIs.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/mcpserver/mcpserver_test.go` around lines 257 - 268, Update TestNew_RegistersResources to verify that New() actually registers resources instead of only constructing the server: after creating store and logger and calling New(store, logger) (symbol New and variable srv), assert that known resource endpoints are discoverable by invoking the server's discovery/read handlers or making test HTTP requests against the server/router for the expected resource URIs (use the same URIs used elsewhere in the package), and check responses/status codes or returned resource metadata to confirm registration; fail the test if the discovery/read path for each expected resource URI is missing or returns an error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/architecture.md`:
- Line 78: The docs reference to internal/mcpserver/server.go is stale; update
the package map entry in docs/architecture.md to point to the actual
implementation file internal/mcpserver/mcpserver.go (replace server.go with
mcpserver.go) so links/navigation resolve correctly and the MCP server entry
matches the real symbol.
In `@internal/mcpserver/mcpserver.go`:
- Line 588: The code currently calls s.store.GetTopMemories(ctx, "_global", 50)
which only returns the top 50 global memories and truncates "all" cross-project
memories; update the handler to retrieve the full set instead of a fixed 50.
Replace the single GetTopMemories call with either (a) a call to a store method
that returns all global memories (e.g., s.store.GetAllMemories(ctx, "_global")
or similarly named method), or (b) implement pagination by repeatedly calling
s.store.GetTopMemories (or a paginated store API) and appending results to the
memories slice until no more results are returned; ensure the variable memories
still holds the complete set before further processing. Reference:
s.store.GetTopMemories and the memories variable in this handler.
- Around line 555-572: The handler currently calls s.buildProjectContext(ctx,
projectID) which swallows datastore/read errors and returns an empty string,
making real errors look like an empty project; change buildProjectContext to
return (string, error) and update the ReadResource handler(s) to check that
error and return a non-OK error (wrapped with context) instead of embedding an
empty Text field—specifically update the anonymous ReadResource func shown and
the analogous handler around lines 611-624 to call buildProjectContext(ctx,
projectID), handle a non-nil error by returning nil, fmt.Errorf("reading project
context %q: %w", projectID, err), and only populate ResourceContents.Text when
err == nil. Ensure you propagate the underlying store error (not mask it) and
keep resolveProjectID usage unchanged.
---
Nitpick comments:
In `@internal/mcpserver/mcpserver_test.go`:
- Around line 257-268: Update TestNew_RegistersResources to verify that New()
actually registers resources instead of only constructing the server: after
creating store and logger and calling New(store, logger) (symbol New and
variable srv), assert that known resource endpoints are discoverable by invoking
the server's discovery/read handlers or making test HTTP requests against the
server/router for the expected resource URIs (use the same URIs used elsewhere
in the package), and check responses/status codes or returned resource metadata
to confirm registration; fail the test if the discovery/read path for each
expected resource URI is missing or returns an error.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6c537d30-7cfc-485e-9209-074f79e97916
📒 Files selected for processing (6)
docs/architecture.mdinternal/mcpserver/mcpserver.gointernal/mcpserver/mcpserver_test.gointernal/server/chat.govscode-ghost/package.jsonvscode-ghost/src/chat-webview.ts
| "toolchain facts. These apply to all projects. " + | ||
| "Add entries via the ghost_save_global tool.", | ||
| }, func(ctx context.Context, req *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) { | ||
| memories, err := s.store.GetTopMemories(ctx, "_global", 50) |
There was a problem hiding this comment.
Global memories resource is capped at 50, not “all.”
The handler fetches only top 50 global memories. If the intended behavior is truly “all cross-project memories,” this truncates output and can drop important pinned context.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@internal/mcpserver/mcpserver.go` at line 588, The code currently calls
s.store.GetTopMemories(ctx, "_global", 50) which only returns the top 50 global
memories and truncates "all" cross-project memories; update the handler to
retrieve the full set instead of a fixed 50. Replace the single GetTopMemories
call with either (a) a call to a store method that returns all global memories
(e.g., s.store.GetAllMemories(ctx, "_global") or similarly named method), or (b)
implement pagination by repeatedly calling s.store.GetTopMemories (or a
paginated store API) and appending results to the memories slice until no more
results are returned; ensure the variable memories still holds the complete set
before further processing. Reference: s.store.GetTopMemories and the memories
variable in this handler.
- Fix stale server.go reference in architecture.md → mcpserver.go - buildProjectContext now returns (string, error), propagates store errors instead of silently returning empty string - Update global resource description: 'top 50' not 'all' (honest cap) - Strengthen TestNew_RegistersResources to exercise handler logic, not just check server construction
Summary
Adds two MCP Resources to the Ghost server, closing the gap between the TUI (push-based memory injection) and MCP clients like Claude Code (previously pull-only).
Problem
When Claude Code uses Ghost via MCP, memories are only loaded when Claude actively calls
ghost_project_context. After context compaction, Claude may not know to re-call it — losing session context silently. The TUI doesn't have this problem becauseBuildSystemBlocksinjects memories into every request automatically.Solution
MCP Resources can be pinned by clients so their content is automatically included in every request — the protocol-correct equivalent of Block 3 in the TUI prompt.
New Resources
ghost://project/{project_id}/context(ResourceTemplate)project_idresolves by name (e.g.dingo) or hash ID_globalmemories automatically (same asGetTopMemories)ghost://memories/global(Resource)ghost_save_globalChanges
internal/mcpserver/mcpserver.go—registerResources()+buildProjectContext()helperinternal/mcpserver/mcpserver_test.go— 5 new testsdocs/architecture.md— updated MCP data flow diagramTests
All green,
go vetclean.Summary by CodeRabbit
New Features
Improvements
Tests
Documentation