Skip to content

feat(mcp): resource support — list on connect + @server:uri expansion#115

Merged
oratis merged 1 commit into
mainfrom
feat/mcp-resources
May 31, 2026
Merged

feat(mcp): resource support — list on connect + @server:uri expansion#115
oratis merged 1 commit into
mainfrom
feat/mcp-resources

Conversation

@oratis

@oratis oratis commented May 31, 2026

Copy link
Copy Markdown
Owner

Summary

Adds MCP resources (docs/DEVELOPMENT_PLAN.md §3.3, previously deferred in BEHAVIOR_PARITY.md). An MCP server's resources can now be referenced from a prompt via @server:scheme://path, and their content is read + injected for the model.

PR 1 of a pair (PR 2 = MCP prompts as slash commands).

Changes

core — mcp/client.ts:

  • connectMcpServer lists resources on connect — capability-gated: a server without the resources capability (or one that errors on resources/list) just yields []. McpClientHandle gains resources: McpResourceMeta[].
  • readMcpResource(handle, uri) — reads a resource and flattens its contents to text; binary blobs render as a [binary <mime> <uri>] placeholder.
  • parseResourceRefs(text) — finds @server:scheme://path tokens. Requires :// so it won't match emails or @user:pass; dedupes by raw token.
  • expandMcpResourceRefs(text, handles) — reads each referenced resource and appends a <mcp-resource server=… uri=…> block, leaving the original token in place so the model sees what was referenced. Unknown server / read failure surface as errors[], never throw.

cli — repl.ts + headless.ts: expand @server:uri refs in the user message right after MCP connect, printing resolved/error lines.

Tests

+5 (client.test.ts):

  • End-to-end against a real spawned stdio server advertising a resources capability: connect → handle.resources populated → readMcpResource returns text → expandMcpResourceRefs appends the tagged block (original token kept) → unknown-server + missing-uri become errors without throwing.
  • parseResourceRefs pure cases: multi-ref extraction, email/@user:pass rejection, dedup, empty.

Core suite 569 green (+5); CLI 72 green; full repo suite green via pre-commit.

Notes

  • writeFakeServer test helper gained an optional resources arg (backward-compatible — existing callers unaffected).
  • Resource templates (resources/templates) and the desktop file-panel surfacing are not included; this covers the @server:uri prompt path.

🤖 Generated with Claude Code

Implements MCP resources (DEVELOPMENT_PLAN §3.3 / BEHAVIOR_PARITY): an MCP
server's resources can now be referenced from a prompt and their content is
injected for the model.

core (mcp/client.ts):
- connectMcpServer now lists resources on connect (capability-gated; a server
  without `resources` — or one that errors on resources/list — yields []).
  McpClientHandle gains `resources: McpResourceMeta[]`.
- readMcpResource(handle, uri) — reads a resource, flattens contents to text
  (binary blobs → `[binary …]` placeholder).
- parseResourceRefs(text) — finds `@server:scheme://path` tokens (requires
  `://`, so it won't match emails or `@user:pass`; dedupes).
- expandMcpResourceRefs(text, handles) — reads each referenced resource and
  appends a `<mcp-resource server=… uri=…>` block, leaving the original token
  in place; unknown server / read failure surface as errors, never throw.

cli:
- repl.ts + headless.ts expand `@server:uri` refs in the user message after
  MCP connect (resolved/error lines to the user).

Tests: +5 (connect→list→read→expand end-to-end against a real spawned stdio
server with a `resources` capability; parseResourceRefs pure cases incl.
email/`@user:pass` rejection + dedup). Core suite 569 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@oratis oratis merged commit 6cb6287 into main May 31, 2026
3 checks passed
@oratis oratis deleted the feat/mcp-resources branch May 31, 2026 07:25
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