From 9ed47b09fa38cf2c50fd4c285759aab40a6c2756 Mon Sep 17 00:00:00 2001 From: olaservo Date: Tue, 5 May 2026 07:26:28 -0700 Subject: [PATCH 01/12] docs: add skills-extension-candidates tracker Scaffold a candidates list for MCP servers, dev tools, SDKs, and skills repositories that could adopt SEP-2640. Initial entries: FastMCP 3.0 Skills, chrome-devtools-mcp, hf-mcp-server, Hugging Face skills library, github-mcp-server (PR #2428 demo), Azure Skills Plugin. Cross-link from related-work.md and add a row to the README docs table. --- README.md | 1 + docs/related-work.md | 2 ++ docs/skills-extension-candidates.md | 17 +++++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 docs/skills-extension-candidates.md diff --git a/README.md b/README.md index 48fe900..8f1953d 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ See [problem-statement.md](docs/problem-statement.md) for full details. | [Open Questions](docs/open-questions.md) | Unresolved questions with community input (see also [issues](https://github.com/modelcontextprotocol/experimental-ext-skills/issues) and [meeting notes](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/categories/meeting-notes-skills-over-mcp-wg)) | | [Experimental Findings](docs/experimental-findings.md) | Results from implementations and testing | | [Related Work](docs/related-work.md) | SEPs, implementations, and external resources | +| [Skills Extension Candidates](docs/skills-extension-candidates.md) | MCP servers, dev tools, SDKs, and skills repositories that are candidates for adopting the skills extension | | [Decision Log](docs/decisions.md) | Record of key decisions with context and rationale | ## Contributing diff --git a/docs/related-work.md b/docs/related-work.md index 76eba6f..b038c40 100644 --- a/docs/related-work.md +++ b/docs/related-work.md @@ -10,6 +10,8 @@ | ~~[SEP-2093](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2093)~~ | MCP Spec | ~~Resource Contents Metadata and Capabilities: scoped `resources/list`, per-resource capabilities, `resources/metadata` endpoint~~ — **rejected** ([labeled upstream](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2093)) | | ~~[SEP-2076](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2076)~~ | MCP Spec | ~~Agent Skills as a first-class MCP primitive~~ — **closed** (2026-02-24, without merge) | +> See also [**skills-extension-candidates.md**](skills-extension-candidates.md) for a tracker of MCP servers, dev tools, SDKs, and skills repositories that are candidates for adopting the skills extension. + ## Working Group Member Implementations Work by WG leads and active participants that directly implements the group's core patterns: SKILL.md with YAML frontmatter, `skill://` resource URIs, and progressive disclosure via MCP primitives. diff --git a/docs/skills-extension-candidates.md b/docs/skills-extension-candidates.md new file mode 100644 index 0000000..5e3b651 --- /dev/null +++ b/docs/skills-extension-candidates.md @@ -0,0 +1,17 @@ +# Skills Extension Candidates + +A tracker of MCP servers, dev tools, SDKs, and skills repositories that are candidates for adopting the skills extension proposed in [SEP-2640](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640). + +**Inclusion criterion.** An entry belongs here if it already ships skills in some non-MCP form (separate install path, plugin marketplace, framework-native provider), pairs an MCP server with a separate skills repo, or has an in-flight SEP-2640 implementation. + +## Snapshot + +| Server | Repo | Author / Org | Notes | +| :--- | :--- | :--- | :--- | +| FastMCP 3.0 Skills | [jlowin/fastmcp#2694](https://github.com/jlowin/fastmcp/issues/2694) — [docs](https://gofastmcp.com/servers/providers/skills) | FastMCP | Framework with its own native skills provider | +| chrome-devtools-mcp | [ChromeDevTools/chrome-devtools-mcp](https://github.com/ChromeDevTools/chrome-devtools-mcp) | Google (ChromeDevTools) | Bundles a [`skills/`](https://github.com/ChromeDevTools/chrome-devtools-mcp/tree/main/skills) folder, but requires separate install — not served via MCP | +| hf-mcp-server | [huggingface/hf-mcp-server](https://github.com/huggingface/hf-mcp-server) | Hugging Face | Official HF MCP server (Hub APIs + Gradio); no skills exposure today | +| Hugging Face skills library | [huggingface/skills](https://github.com/huggingface/skills) | Hugging Face | 13 SKILL.md skills paired with `hf-mcp-server` via Cursor `.mcp.json`; distributed outside MCP today | +| github-mcp-server | [github/github-mcp-server](https://github.com/github/github-mcp-server) | GitHub | SEP-2640 demo branch in [#2428](https://github.com/github/github-mcp-server/pull/2428) (WIP, not for merge) | +| Azure Skills Plugin | [microsoft/azure-skills](https://github.com/microsoft/azure-skills) | Microsoft | 25 Azure SKILL.md skills bundled with Azure MCP Server + Foundry MCP; distributed as a plugin, not via MCP | + From c8618ad42f1b69a31aaf07d34f4bde5b8440e8cb Mon Sep 17 00:00:00 2001 From: olaservo Date: Tue, 5 May 2026 07:48:11 -0700 Subject: [PATCH 02/12] docs: add Issue/PR tracker column to candidates table --- docs/skills-extension-candidates.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/skills-extension-candidates.md b/docs/skills-extension-candidates.md index 5e3b651..f3c73c3 100644 --- a/docs/skills-extension-candidates.md +++ b/docs/skills-extension-candidates.md @@ -6,12 +6,12 @@ A tracker of MCP servers, dev tools, SDKs, and skills repositories that are cand ## Snapshot -| Server | Repo | Author / Org | Notes | -| :--- | :--- | :--- | :--- | -| FastMCP 3.0 Skills | [jlowin/fastmcp#2694](https://github.com/jlowin/fastmcp/issues/2694) — [docs](https://gofastmcp.com/servers/providers/skills) | FastMCP | Framework with its own native skills provider | -| chrome-devtools-mcp | [ChromeDevTools/chrome-devtools-mcp](https://github.com/ChromeDevTools/chrome-devtools-mcp) | Google (ChromeDevTools) | Bundles a [`skills/`](https://github.com/ChromeDevTools/chrome-devtools-mcp/tree/main/skills) folder, but requires separate install — not served via MCP | -| hf-mcp-server | [huggingface/hf-mcp-server](https://github.com/huggingface/hf-mcp-server) | Hugging Face | Official HF MCP server (Hub APIs + Gradio); no skills exposure today | -| Hugging Face skills library | [huggingface/skills](https://github.com/huggingface/skills) | Hugging Face | 13 SKILL.md skills paired with `hf-mcp-server` via Cursor `.mcp.json`; distributed outside MCP today | -| github-mcp-server | [github/github-mcp-server](https://github.com/github/github-mcp-server) | GitHub | SEP-2640 demo branch in [#2428](https://github.com/github/github-mcp-server/pull/2428) (WIP, not for merge) | -| Azure Skills Plugin | [microsoft/azure-skills](https://github.com/microsoft/azure-skills) | Microsoft | 25 Azure SKILL.md skills bundled with Azure MCP Server + Foundry MCP; distributed as a plugin, not via MCP | +| Server | Repo | Author / Org | Issue/PR tracker | Notes | +| :--- | :--- | :--- | :--- | :--- | +| FastMCP 3.0 Skills | [jlowin/fastmcp](https://github.com/jlowin/fastmcp) — [docs](https://gofastmcp.com/servers/providers/skills) | FastMCP | [#2694](https://github.com/jlowin/fastmcp/issues/2694) | Framework with its own native skills provider | +| chrome-devtools-mcp | [ChromeDevTools/chrome-devtools-mcp](https://github.com/ChromeDevTools/chrome-devtools-mcp) | Google (ChromeDevTools) | _none yet_ | Bundles a [`skills/`](https://github.com/ChromeDevTools/chrome-devtools-mcp/tree/main/skills) folder, but requires separate install — not served via MCP | +| hf-mcp-server | [huggingface/hf-mcp-server](https://github.com/huggingface/hf-mcp-server) | Hugging Face | _none yet_ | Official HF MCP server (Hub APIs + Gradio); no skills exposure today | +| Hugging Face skills library | [huggingface/skills](https://github.com/huggingface/skills) | Hugging Face | _none yet_ | 13 SKILL.md skills paired with `hf-mcp-server` via Cursor `.mcp.json`; distributed outside MCP today | +| github-mcp-server | [github/github-mcp-server](https://github.com/github/github-mcp-server) | GitHub | [#2428](https://github.com/github/github-mcp-server/pull/2428) (WIP demo, not for merge) | SEP-2640 demo branch | +| Azure Skills Plugin | [microsoft/azure-skills](https://github.com/microsoft/azure-skills) | Microsoft | _none yet_ | 25 Azure SKILL.md skills bundled with Azure MCP Server + Foundry MCP; distributed as a plugin, not via MCP | From 132731ce3fdeddc8eb34ce768496f1ea6dbcf6fc Mon Sep 17 00:00:00 2001 From: olaservo Date: Tue, 5 May 2026 08:28:28 -0700 Subject: [PATCH 03/12] docs: add client-mcp-support survey alongside candidates tracker --- README.md | 1 + docs/client-mcp-support.md | 208 ++++++++++++++++++++++++++++ docs/skills-extension-candidates.md | 2 + 3 files changed, 211 insertions(+) create mode 100644 docs/client-mcp-support.md diff --git a/README.md b/README.md index 8f1953d..5875513 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ See [problem-statement.md](docs/problem-statement.md) for full details. | [Experimental Findings](docs/experimental-findings.md) | Results from implementations and testing | | [Related Work](docs/related-work.md) | SEPs, implementations, and external resources | | [Skills Extension Candidates](docs/skills-extension-candidates.md) | MCP servers, dev tools, SDKs, and skills repositories that are candidates for adopting the skills extension | +| [Client MCP Support](docs/client-mcp-support.md) | Survey of model-facing MCP resource loading and SEP-2640 support across open-source clients | | [Decision Log](docs/decisions.md) | Record of key decisions with context and rationale | ## Contributing diff --git a/docs/client-mcp-support.md b/docs/client-mcp-support.md new file mode 100644 index 0000000..8dde6bb --- /dev/null +++ b/docs/client-mcp-support.md @@ -0,0 +1,208 @@ +# Client Research: Model-facing MCP Resource & SEP-2640 Support + +> **Scope.** This page tracks two related areas of client support: +> +> 1. **Model-facing MCP resource loading** — does the client expose a tool that lets the model read MCP resources by URI? This is the SHOULD proposed in [modelcontextprotocol/modelcontextprotocol#2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527) and is verifiable today. The bulk of this page is this survey. +> 2. **SEP-2640 skills extension support** — once [SEP-2640](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640) finalizes, this page will also track which clients implement the extension. SEP-2640-related issues and PRs are tracked per-client in the "Open issues/PRs to watch" column rather than via a separate status field. +> +> **Why these are tracked together.** SEP-2640 layers skills on top of MCP resources. If a host's progressive-disclosure flow involves the model itself loading L2/L3 skill content from `skill://…` or related resource URIs, then the resource-read affordance for the model becomes critical for skills. A client's resource-loading shape today is a strong predictor of how it'll fit SEP-2640 tomorrow. +> +> See also [**skills-extension-candidates.md**](skills-extension-candidates.md) for the matching server-side tracker: MCP servers, dev tools, SDKs, and skills repositories that are candidates for adopting SEP-2640. +> + +## At-a-glance comparison + +Category values: **Framework** = SDK/library you build agents on top of · **CLI** = end-user coding agent or CLI · **IDE** = editor-embedded chat surface. + +| Client | Category | Tool exposed to model? | Tool name(s) | Tool signature | Calls `resources/read` on connected server? | Enablement gate | End-user docs? | Open issues/PRs to watch | +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +| **codex** (OpenAI) | CLI | Yes | `read_mcp_resource`, `list_mcp_resources`, `list_mcp_resource_templates` | `(server, uri)` — server explicitly named | Yes — handler calls `session.read_resource()` | Any MCP server is configured (`params.mcp_tools.is_some()`) | No — only the LLM-visible tool description; an internal steer tells the model to prefer `tool_search` | _none yet — add as found_ | +| **gemini-cli** (Google) | CLI | Yes | `read_mcp_resource`, `list_mcp_resources` | `(uri)` only — no server param ([Peter notes](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640#discussion_r3164100043) the client probes connected servers in turn until one resolves; **verify** against the loader code at next pass) | Yes — `read-mcp-resource.ts` calls `resources/read` | MCP manager present AND ≥1 connected server exposes a resource | Yes — `docs/tools/mcp-resources.md`, `docs/reference/tools.md:99-100`, `docs/cli/plan-mode.md:134-135` | _none yet — add as found_ | +| **goose** (Block) | CLI | Yes | `read_resource`, `list_resources` | Today: `extension_name` is **optional** on `read_resource`; if omitted the handler probes every connected extension and swallows errors. PR [#8989](https://github.com/aaif-goose/goose/pull/8989) (open) makes it required, moving the signature to `(extension_name, uri)` | Yes — `ExtensionManager::read_resource` → `client.read_resource(...)` | ≥1 enabled extension reports `ServerCapabilities::resources` | Yes — `documentation/docs/mcp/extension-manager-mcp.md:70-81` | Issue [#8988](https://github.com/aaif-goose/goose/issues/8988) (open), PR [#8989](https://github.com/aaif-goose/goose/pull/8989) (open) | +| **fast-agent** | Framework | Yes (multiplexed) | `get_resource`, `list_resources` | `(uri, server_name)` — also handles bundled `internal://` URIs through the same tool | Yes for MCP URIs — `_run_current_agent_get_resource_call` → `agent.get_resource(uri, namespace=server_name)`; `internal://` URIs short-circuit to bundled resources | Unconditional for every `SmartAgent` | Partial — `smart_prompt.md:26-28` instructs the model; design rationale in `plan/done/internal_resources.md`; no dedicated README section | _none yet — add as found_ | +| **vscode** (GitHub Copilot) | IDE | Yes (FS-provider indirection) | `copilot_readFile`, `copilot_listDirectory` (general-purpose, not MCP-specific) | `(path)` — accepts `mcp-resource://…` URIs as paths; the FS provider routes to MCP RPC | Yes — `mcp-resource://` URIs route via `IFileService` → `McpResourceFilesystem` provider → `r.readResource(...)` MCP RPC (`mcpResourceFilesystem.ts:293`) | Server must advertise `McpCapability.Resources`; model needs a URI to pass (typically obtained from user attachment or from an MCP tool's `resource_link` response) | No explicit doc, but mechanism is operational. [Connor Peet's comment on #2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527#issuecomment-4282395437) is the clearest write-up | _none yet — add as found_ | +| **opencode** | CLI | No | — (internal `readResource` only) | — | Internal only — `readResource()` exists at `packages/opencode/src/mcp/index.ts:722-726` but is invoked only when the user attaches a resource via file picker; `mcp.tools()` at `prompt.ts:444` forwards MCP *tools* but never a resource-read tool | n/a | Docs (`mcp-servers.mdx:8`) advertise tool forwarding only | _none yet — add as found_ | +| **deepagents** (LangChain) | Framework | No | — | — | n/a — delegates MCP wiring to [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters) via `load_mcp_tools()` (`mcp_tools.py:519-521`); that adapter only converts MCP tools, not resources | n/a | No mention in README | **Upstream-blocked**: needs a change in `langchain-mcp-adapters` (or a deepagents wrapper around `client.read_resource()`) | +| **strands-agents** (AWS) | Framework | No (internal SDK only) | — | — | Internal only — `MCPClient.read_resource_sync()` (`src/strands/tools/mcp/mcp_client.py:524`) and `list_resources_sync()` (line 500) call MCP `resources/read` / `resources/list`, but `MCPAgentTool` (the only adapter) wraps `mcp.types.Tool` only and `MCPClient.load_tools()` (the `ToolProvider` interface, line 227) returns tools only | n/a | _unknown — verify_ | _none yet — add as found_ | +| **Claude Code** (closed source, reference) | CLI | Yes | `ReadMcpResourceTool` | `(server, uri)` per [public docs](https://code.claude.com/docs/en/tools-reference) | Documented; source not verifiable | n/a | Yes — public tools reference page | n/a | +| **adk-python** (Google ADK) | Framework | Yes _(unverified — first pass below)_ | `load_mcp_resource` | Two-shot — discovers resources first, then takes a `resource_name` to read | Yes — `MCPToolset.read_resource()` calls `session.read_resource(uri)` (`tools/mcp_tool/mcp_toolset.py`) | Toolset must be configured with at least one MCP server | _unknown — verify_ | _none yet — add as found_ | +| **agent-framework** (Microsoft) | Framework | No (tools-only client bridge) | — | — | n/a — `MCPTool` / `MCPStdioTool` / `MCPStreamableHTTPTool` / `MCPWebsocketTool` in `python/packages/core/agent_framework/_mcp.py` materialize MCP *tools* into the agent's tool registry; no `read_resource` callsite found in client code (only in a test) | n/a | Samples cover MCP tool integration only | _none yet — add as found_ | +| **cline** | IDE | No | — | — | n/a — depends on `@modelcontextprotocol/sdk` for MCP, but zero matches for `resources/read` / `readResource` / `read_resource` in source. Tools-only bridge | n/a | MCP docs cover tools and config only | _none yet — add as found_ | +| **crewAI** | Framework | No | — | — | n/a — `crewai-tools` MCP adapter (`lib/crewai-tools/src/crewai_tools/adapters/mcp_adapter.py`) is built on `mcpadapt` and converts MCP tools only — same upstream-blocked pattern as smolagents | n/a | MCP adapter docs cover tools only | **Upstream-blocked** by `mcpadapt` (shared with smolagents) | +| **hermes-agent** (Nous Research) | CLI | Yes _(unverified — first pass below)_ | `mcp_{server}_read_resource` (one per connected server) | `(uri)` — server is encoded in the tool name | Yes — `_make_read_resource_handler()` in `tools/mcp_tool.py:~2159` calls `session.read_resource(uri)`; tool registered at `~2529` | Conditional — only registered when the server advertises resources (line ~2626) | _unknown — verify_ | _none yet — add as found_ | +| **mastra** | Framework | No (internal SDK only) | — | — | Internal only — `packages/mcp/src/client/actions/resource.ts:~130` exposes a `read(uri)` SDK method that calls `client.readResource(uri)`, but it is **not** registered as an LLM-facing tool; the model-facing tool bridge converts MCP tools only | n/a | SDK docs cover the action; no LLM-tool exposure | _none yet — add as found_ | +| **Roo-Code** | IDE | No | — | — | n/a — `src/services/mcp/McpHub.ts` imports `ReadResourceResultSchema` from the SDK but does not register a model-facing resource-read tool; the MCP hub maps tools only | n/a | _unknown — verify_ | _none yet — add as found_ | + +## Cross-cutting observations + +1. **Three implementation patterns for model-facing MCP resource access.** + 1. **Dedicated MCP resource tools** — Codex, Gemini CLI, Goose, Claude Code: explicit `read_mcp_resource` / `read_resource` (+ optional `list_*`) registered alongside other MCP tools. Most discoverable by the model; closest literal reading of #2527. + 2. **Multiplexed resource tool** — fast-agent: one `get_resource` tool handles both bundled (`internal://`) and MCP URIs behind a single name. Simpler surface for the model; relies on URI scheme to disambiguate. + 3. **FS-provider indirection via namespaced URIs** — VS Code: no MCP-specific tool. A dedicated URI scheme (`mcp-resource://`) is registered with the filesystem service so the generic `readFile` / `listDirectory` tools transparently reach MCP `resources/read`. Reuses the agent's existing file-reading affordance; costs nothing in tool-count budget. Downside: no `list` equivalent — the model can only read URIs it's been handed. + +2. **Tool signature is fragmented in pattern (1).** Among the dedicated-tool implementers, **Codex, fast-agent, and Claude Code** take an explicit `(server, uri)` pair. **Gemini-CLI and Goose**, currently make `uri` optional and as a fallback probe servers one-by-one until one resolves. + +3. **Trust models diverge.** Per-server enablement (Goose, Gemini CLI), unconditional-when-MCP-configured (Codex), or capability-gated FS provider (VS Code). For skills-over-MCP this matters because the "who can read what" boundary is currently set by each host individually — a portable skill that depends on `resources/read` will work or not based on whether the host considers MCP resource access a model-grade affordance. + +4. **Discoverability differs sharply between patterns.** Pattern (1) hosts pair `read_*` with a `list_*` so the model can enumerate resources on its own. Pattern (2) (fast-agent) has `list_resources`. Pattern (3) (VS Code) has *no list equivalent* — the model can only read a URI it's been handed (user attachment → chat context, or an MCP tool returning a `resource_link`). For skills this matters: a `skill://index.json`-style enumeration model implicitly assumes the model can either *list* or be *told* what's available. Pattern (3) needs the index handed in via attachment or a dedicated tool result. + +5. **VS Code's FS-provider pattern is worth its own consideration for skills.** Because `mcp-resource://` URIs are first-class in the file service, *any* tool that takes a path argument in VS Code can transparently read MCP resources — including, in principle, a skill loader. The skills-over-MCP design could lean on this by treating `skill://server/name/SKILL.md` as just another URI scheme registered with the host's file abstraction. This is closer to a registry-style integration (cf. how VS Code surfaces skills via `ChatSessionCustomizationProvider` rather than as system-prompt content). + +## Per-client deep dives + +### Agent SDKs / frameworks + +#### fast-agent _(verified)_ + +Verified at commit [`502d32e`](https://github.com/evalstate/fast-agent/commit/502d32e266f3221d744977f38b7a9b4bc5b93947). + +- **Model-facing tool:** `get_resource` registered at [`smart_agent.py:1478-1489`](https://github.com/evalstate/fast-agent/blob/502d32e266f3221d744977f38b7a9b4bc5b93947/src/fast_agent/agents/smart_agent.py) via `agent.add_tool(...)`. Dispatcher at `smart_agent.py:1529-1540` routes `internal://` to bundled resources; everything else hits the connected MCP server via `agent.get_resource(uri, namespace=server_name)` → MCP `resources/read`. +- **Signature:** `(uri, server_name)` — multiplexed across bundled and MCP URIs by scheme. MCP behavior depends on what the model passes for `server_name`. + +--- + +#### adk-python (Google ADK) _(first pass — verify before citing)_ + +- **MCP integration:** `src/google/adk/tools/mcp_tool/` package — `MCPToolset` is the entry point used by callers to connect an ADK agent to an MCP server. +- **Resource RPC wired:** `src/google/adk/tools/mcp_toolset.py:~380` exposes `async def read_resource()` which calls `session.read_resource(uri)` (~line 397). +- **Model-facing tool:** `src/google/adk/tools/load_mcp_resource_tool.py:~44` defines `load_mcp_resource`. Per the first-pass scan, the tool is two-shot — first invocation lists resources, then the model picks a `resource_name` for the second call (line ~131). **Verify the exact schema and confirm it's registered alongside the other ADK tools the agent sees.** +- **Why interesting:** ADK is one of two clients in the gap (with hermes-agent) that may already satisfy #2527 — and it's also the client with the most rigorous skill validation in the parallel skills survey, so this is where the spec extension and the resource-tool extension converge. + +--- + +#### agent-framework (Microsoft) _(first pass — verify before citing)_ + +- **MCP integration:** Multi-transport client tools (`MCPTool` + Stdio/HTTP/Websocket variants) in `python/packages/core/agent_framework/_mcp.py`, with .NET equivalents under `dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Models/`. Tools-only bridge; zero `read_resource` callsites in source (only in tests). +- **Why on the list:** dual-stack Python/.NET framework with rich skills metadata in the parallel skills survey. The asymmetry — skills support without resource-tool support — is the kind of gap a #2527-aligned PR would close. + +--- + +#### crewAI _(first pass — verify before citing)_ + +- **MCP integration:** `lib/crewai-tools/src/crewai_tools/adapters/mcp_adapter.py` imports `mcp` + `mcpadapt.core` and converts MCP tools to CrewAI `BaseTool` objects. +- **Resource RPC wired:** No — adapter handles only `Tool` types (line ~19). +- **Model-facing tool:** None. +- **Why on the list:** Same upstream block as **smolagents** — both depend on [`mcpadapt`](https://github.com/grll/mcpadapt), which is tools-only. A single upstream change in `mcpadapt` flips both clients. This is the highest-leverage adapter-library target identified so far. + +--- + +#### deepagents (LangChain) _(verified)_ + +Verified at commit [`a64ff43`](https://github.com/langchain-ai/deepagents/commit/a64ff430f14b76607dfb1d78234f928ed88a3af0). + +- **MCP wiring is outsourced** to `langchain_mcp_adapters.tools.load_mcp_tools()` (called from `mcp_tools.py:519-521`). The upstream adapter does not expose `resources/read` as a tool — zero hits for resource-read in deepagents source. +- **What it would take:** either upstream adds a resource-read tool, or deepagents wraps `client.read_resource()` outside the adapter. + +--- + +#### mastra _(first pass — verify before citing)_ + +- **MCP integration:** `packages/mcp/src/client/` imports `@modelcontextprotocol/sdk`. `packages/mcp/src/client/actions/resource.ts:~130` exposes `async read(uri)` which calls `this.client.readResource(uri)`. +- **Resource RPC wired:** Yes, but **internal SDK only**. `ResourceClientActions` is an SDK surface for callers, not registered as an LLM-facing tool. +- **Model-facing tool:** No. The model-facing tool bridge converts MCP tools only; resources require explicit code to invoke. +- **Why on the list:** Mastra's skill versioning architecture (content-addressable BlobStore, draft→publish lifecycle) is the most sophisticated. Unlocking resource-read at the model boundary would be a small change relative to the rest of the framework — the SDK plumbing already exists. + +--- + +#### strands-agents _(verified)_ + +Verified at commit [`8638fc2`](https://github.com/strands-agents/sdk-python/commit/8638fc2d629e32b7b5839f4c106d5aedcdf764c9) (2026-05-04). Strands matches the **mastra pattern**: resource RPC wired in the SDK, but no model-facing tool. + +- **Resource RPC wired but unbridged:** `MCPClient.read_resource_sync()` ([`mcp_client.py:524`](https://github.com/strands-agents/sdk-python/blob/8638fc2d629e32b7b5839f4c106d5aedcdf764c9/src/strands/tools/mcp/mcp_client.py)), `list_resources_sync()` (line 500), and `list_resource_templates_sync()` are SDK-public methods, but [`MCPAgentTool`](https://github.com/strands-agents/sdk-python/blob/8638fc2d629e32b7b5839f4c106d5aedcdf764c9/src/strands/tools/mcp/mcp_agent_tool.py) only wraps `mcp.types.Tool` and delegates to `call_tool_async(...)`. Outside tests, nothing in the repo invokes the resource methods. +- **Why on the list:** Strands has its own local-filesystem skills implementation at `src/strands/vended_plugins/skills/agent_skills.py`, so the framework already does progressive disclosure. Wiring resource-read to the model is the obvious next step for an MCP-backed skill story. + +--- + +### Coding agents / CLIs + +#### codex (OpenAI) _(verified)_ + +Verified at commit [`67849d9`](https://github.com/openai/codex/commit/67849d950d843c954102adb0db0e11f993aefdb7). + +- **Model-facing tools:** `read_mcp_resource`, `list_mcp_resources`, `list_mcp_resource_templates` defined at [`mcp_resource_tool.rs`](https://github.com/openai/codex/blob/67849d950d843c954102adb0db0e11f993aefdb7/codex-rs/tools/src/mcp_resource_tool.rs); registered unconditionally when an MCP server is configured. Handler at [`mcp_resource.rs`](https://github.com/openai/codex/blob/67849d950d843c954102adb0db0e11f993aefdb7/codex-rs/core/src/tools/handlers/mcp_resource.rs) → `session.read_resource()`. +- **Signature:** `(server, uri)` — model names the server explicitly. No user-facing doc; an internal steer tells the model to prefer `tool_search`. + +--- + +#### gemini-cli (Google) _(verified)_ + +Verified at commit [`4e17552`](https://github.com/google-gemini/gemini-cli/commit/4e175527a2b241a68afd5f1509a8bebc21a44dfe). + +- **Model-facing tool:** [`read-mcp-resource.ts`](https://github.com/google-gemini/gemini-cli/blob/4e175527a2b241a68afd5f1509a8bebc21a44dfe/packages/core/src/tools/read-mcp-resource.ts) → MCP `resources/read` RPC at line 135. Active-tool gate requires `mcpManager.getAllResources().length > 0`. +- **Signature:** `(uri)` only — gemini-cli probes connected servers until one resolves. Documented at [`docs/tools/mcp-resources.md`](https://github.com/google-gemini/gemini-cli/blob/4e175527a2b241a68afd5f1509a8bebc21a44dfe/docs/tools/mcp-resources.md) and covered by [integration test](https://github.com/google-gemini/gemini-cli/blob/4e175527a2b241a68afd5f1509a8bebc21a44dfe/integration-tests/mcp-resources.test.ts). + +--- + +#### goose (AAIF) _(verified)_ + +Verified at commit [`45d8bf8`](https://github.com/aaif-goose/goose/commit/45d8bf81d09d478ceedba8f6d1f0ad906123a981). + +- **Model-facing tools:** `read_resource`, `list_resources` registered at [`platform_extensions/ext_manager.rs:264-372`](https://github.com/aaif-goose/goose/blob/45d8bf81d09d478ceedba8f6d1f0ad906123a981/crates/goose/src/agents/platform_extensions/ext_manager.rs) when at least one extension reports `ServerCapabilities::resources`. Dispatch flows through [`extension_manager.rs:1262-1297`](https://github.com/aaif-goose/goose/blob/45d8bf81d09d478ceedba8f6d1f0ad906123a981/crates/goose/src/agents/extension_manager.rs) → `client.read_resource(...)` → MCP `resources/read`. Documented at [`extension-manager-mcp.md`](https://github.com/block/goose/blob/main/documentation/docs/mcp/extension-manager-mcp.md). +- **Signature:** Peter's #2640 claim is correct — `extension_name` is currently *optional* on `read_resource`, and the handler probes every connected extension and swallows errors when it's omitted. Issue [#8988](https://github.com/aaif-goose/goose/issues/8988) describes the bug; PR [#8989](https://github.com/aaif-goose/goose/pull/8989) (open) makes it required and rewrites the tool description to direct the model to call `list_resources` first when ownership is unknown. The PR also fixes a separate bug where `list_resources`'s schema declares `extension_name` but the handler reads `extension`, silently ignoring the model's filter. + +--- + +#### hermes-agent (Nous Research) _(first pass — verify before citing)_ + +- **MCP integration:** Full integration in `tools/mcp_tool.py`. +- **Resource RPC wired:** Yes — `_make_read_resource_handler()` at `tools/mcp_tool.py:~2159` calls `session.read_resource(uri)` at `~2178`. +- **Model-facing tool:** Yes — `mcp_{safe_name}_read_resource` registered per connected server at `tools/mcp_tool.py:~2529`, taking a `uri` parameter (handler key `read_resource` at `~2542`). Conditionally registered when the server advertises resources (`~2626`). +- **Signature:** `(uri)` — server is encoded in the tool name (one tool per server), so the model implicitly selects the server by selecting the tool. **Distinct from every other pattern surveyed**: not `(server, uri)`, not `(uri)`-with-probing, not URI-virtualized — it's *one tool per server*. Worth highlighting in the cross-cutting observations once verified. +- **Why interesting:** With adk-python, this is the second of the seven gap-clients that likely already satisfies #2527. The per-server-tool naming is also a candidate disambiguation pattern for skills-over-MCP. + +--- + +#### Claude Code (closed source — reference only) + +Claude Code is closed source so we cannot verify the loader, but the [public tools reference](https://code.claude.com/docs/en/tools-reference) documents `ReadMcpResourceTool` accepting `server` and `uri` parameters. Listed here as a reference data point for the `(server, uri)` signature shape also adopted by Codex and fast-agent. + +--- + +#### opencode _(verified)_ + +Verified at commit [`ce89bcb`](https://github.com/anomalyco/opencode/commit/ce89bcb8e238401ea8fee000dc54539057d47dc4). + +- **Tools forwarded to the model** at `packages/opencode/src/mcp/index.ts:444-519` via `client.callTool()`; tool naming convention `{server_name}:{tool_name}`. +- **Resource-read is UI-only:** `readResource()` at `mcp/index.ts:722-726` is invoked from the file picker, never registered as an LLM tool. Docs (`mcp-servers.mdx:8`) advertise tool forwarding only. + +--- + +### IDE extensions + +#### vscode (GitHub Copilot) _(verified)_ + +Verified at commits [`530cb5d`](https://github.com/microsoft/vscode/commit/530cb5de713aec2e96059e2f6cf41a95403cdb3d) (vscode core) and [`9e668cb`](https://github.com/microsoft/vscode-copilot-chat/commit/9e668cb12144c701cf0f2c6b3458c00fe3da20f1) (Copilot Chat extension). VS Code is the unique pattern here: no MCP-specific tool — generic `copilot_readFile` / `copilot_listDirectory` tools transparently reach MCP servers via filesystem-provider indirection on a custom URI scheme. + +- **URI scheme + FS provider:** [`McpResourceURI`](https://github.com/microsoft/vscode/blob/530cb5de713aec2e96059e2f6cf41a95403cdb3d/src/vs/workbench/contrib/mcp/common/mcpTypes.ts) defines `mcp-resource://` URIs that encode the MCP server's definition ID in the authority — self-routing. [`McpResourceFilesystem`](https://github.com/microsoft/vscode/blob/530cb5de713aec2e96059e2f6cf41a95403cdb3d/src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.ts) is registered for that scheme; `_readURIInner` decodes the URI, looks up the `McpServer`, and calls `r.readResource(...)` (line 293) — the MCP `resources/read` RPC. Capability-gated on `McpCapability.Resources`. +- **`resource_link` pre-wrap:** when an MCP tool returns a `resource_link`, `mcpLanguageModelToolContribution.ts:336-358` converts it into an `mcp-resource://` URI so the model can re-read it later via `copilot_readFile`. +- **Caveat — discoverability:** the model can only read a URI it has been handed (user attachment, or an MCP tool's `resource_link`). No `list_mcp_resources`-equivalent. [Connor Peet on PR #2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527#issuecomment-4282395437) is the clearest write-up of this pattern. + +--- + +#### cline _(first pass — verify before citing)_ + +- **MCP integration:** Depends on `@modelcontextprotocol/sdk` per `package.json`; MCP server config + UI surfaced in the IDE. +- **Resource RPC wired:** No callsite found — zero matches for `resources/read` / `readResource` / `read_resource` in source. +- **Model-facing tool:** None. The MCP integration is currently tools + UI configuration; resources aren't reached. +- **Why on the list:** Cline has the most extensive skills implementation in the parallel survey (incl. the admin-locked enterprise `globalSkills` primitive), so the absence of resource-read is a notable asymmetry. Worth a careful re-check given the SDK is already wired. + +--- + +#### Roo-Code _(first pass — verify before citing)_ + +- **MCP integration:** `src/services/mcp/McpHub.ts` imports from `@modelcontextprotocol/sdk/types.js`, including `ReadResourceResultSchema` (line ~15). +- **Resource RPC wired:** Schema imports suggest the capability is reachable, but no explicit `readResource` handler was found in `McpHub` on first pass; the hub maps tools only (the observed pattern is `tools = (response?.tools).map(...)`). +- **Model-facing tool:** No. +- **Why on the list:** Roo-Code has both a skills implementation and an MCP hub, and the SDK type imports indicate someone *intended* to surface resources at some point. Worth a thorough read of `McpHub.ts` to confirm whether resources are partially implemented or simply unused. + +## Takeaways for SEP-2640 (skills extension) + +- **Likely seven of sixteen open-source clients surveyed** (Codex, Gemini CLI, Goose, fast-agent, VS Code — verified — plus adk-python and hermes-agent on first-pass evidence pending verification) satisfy #2527's SHOULD. Gemini CLI and Goose also satisfy the implicit expectation that this be documented for end users. +- **Four implementation patterns** for model-facing MCP resource access — all support the layering Peter sketches in his #2640 comment, but with different costs: + - **Dedicated tools, `(server, uri)`** (Codex, Claude Code, fast-agent — fast-agent is also multiplexed across `internal://`): explicit `read_resource` registered alongside other MCP tools. Most discoverable; closest literal reading of #2527. + - **Dedicated tools, `(uri)`-only with server probing** (Gemini CLI; Goose currently — open PR [aaif-goose/goose#8989](https://github.com/aaif-goose/goose/pull/8989) would move it to `(extension_name, uri)`, addressing issue [#8988](https://github.com/aaif-goose/goose/issues/8988)): cleaner signature but loses cross-server disambiguation. **Should probably be fixed independently of skills.** + - **One tool per server, `(uri)`** (hermes-agent, first-pass): server is encoded in the tool name (`mcp_{server}_read_resource`), so the model selects the server by selecting the tool. Trades catalog tokens for unambiguity. + - **FS-provider indirection via namespaced URIs** (VS Code): no MCP-specific tool. `mcp-resource://` URIs are registered with the file service; generic `readFile` / `listDirectory` tools transparently reach `resources/read`. Costs nothing in tool-count budget; loses `list` affordance. +- **Signature mismatch is a portability hazard.** A skill that references `skill://code-review/checklist.json` resolves differently across hosts depending on whether the host disambiguates by server. **The spec should probably nudge implementations toward `(server, uri)` or per-server tool naming.** +- **Adapter libraries** for several "no" rows. **`mcpadapt`** blocks both **smolagents** *and* **crewAI** (via `crewai-tools`). **`langchain-mcp-adapters`** blocks **deepagents**. Three "no" rows collapse to two upstream changes. +- **Internal SDK without LLM-tool exposure** (mastra) is its own pattern: the resource RPC is wired in the SDK but not bridged to the model. Closing this gap is typically smaller-scope than wiring the RPC from scratch. diff --git a/docs/skills-extension-candidates.md b/docs/skills-extension-candidates.md index f3c73c3..25e2483 100644 --- a/docs/skills-extension-candidates.md +++ b/docs/skills-extension-candidates.md @@ -4,6 +4,8 @@ A tracker of MCP servers, dev tools, SDKs, and skills repositories that are cand **Inclusion criterion.** An entry belongs here if it already ships skills in some non-MCP form (separate install path, plugin marketplace, framework-native provider), pairs an MCP server with a separate skills repo, or has an in-flight SEP-2640 implementation. +> See also [**client-mcp-support.md**](client-mcp-support.md) for the matching client-side survey: which open-source MCP hosts already let the model load resources by URI (the prerequisite for any client to consume what these candidates would expose). + ## Snapshot | Server | Repo | Author / Org | Issue/PR tracker | Notes | From c5d4aef948b1374b318f9b01bcdaa5da57681fe9 Mon Sep 17 00:00:00 2001 From: olaservo Date: Sat, 9 May 2026 18:08:57 -0700 Subject: [PATCH 04/12] docs: link Azure MCP Server source in candidates table --- docs/skills-extension-candidates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/skills-extension-candidates.md b/docs/skills-extension-candidates.md index 25e2483..c5b966d 100644 --- a/docs/skills-extension-candidates.md +++ b/docs/skills-extension-candidates.md @@ -15,5 +15,5 @@ A tracker of MCP servers, dev tools, SDKs, and skills repositories that are cand | hf-mcp-server | [huggingface/hf-mcp-server](https://github.com/huggingface/hf-mcp-server) | Hugging Face | _none yet_ | Official HF MCP server (Hub APIs + Gradio); no skills exposure today | | Hugging Face skills library | [huggingface/skills](https://github.com/huggingface/skills) | Hugging Face | _none yet_ | 13 SKILL.md skills paired with `hf-mcp-server` via Cursor `.mcp.json`; distributed outside MCP today | | github-mcp-server | [github/github-mcp-server](https://github.com/github/github-mcp-server) | GitHub | [#2428](https://github.com/github/github-mcp-server/pull/2428) (WIP demo, not for merge) | SEP-2640 demo branch | -| Azure Skills Plugin | [microsoft/azure-skills](https://github.com/microsoft/azure-skills) | Microsoft | _none yet_ | 25 Azure SKILL.md skills bundled with Azure MCP Server + Foundry MCP; distributed as a plugin, not via MCP | +| Azure Skills Plugin | [microsoft/azure-skills](https://github.com/microsoft/azure-skills) | Microsoft | _none yet_ | 25 Azure SKILL.md skills bundled with [Azure MCP Server](https://github.com/microsoft/mcp/tree/main/servers/Azure.Mcp.Server) + Foundry MCP; distributed as a plugin, not via MCP | From 9d7a08463570d1857cdeb7aa7132daaa3b3a57b1 Mon Sep 17 00:00:00 2001 From: olaservo Date: Sat, 23 May 2026 18:56:47 -0700 Subject: [PATCH 05/12] docs: remove gemini-cli from client MCP support survey --- docs/client-mcp-support.md | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/docs/client-mcp-support.md b/docs/client-mcp-support.md index 8dde6bb..dff52a5 100644 --- a/docs/client-mcp-support.md +++ b/docs/client-mcp-support.md @@ -17,7 +17,6 @@ Category values: **Framework** = SDK/library you build agents on top of · **CLI | Client | Category | Tool exposed to model? | Tool name(s) | Tool signature | Calls `resources/read` on connected server? | Enablement gate | End-user docs? | Open issues/PRs to watch | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | **codex** (OpenAI) | CLI | Yes | `read_mcp_resource`, `list_mcp_resources`, `list_mcp_resource_templates` | `(server, uri)` — server explicitly named | Yes — handler calls `session.read_resource()` | Any MCP server is configured (`params.mcp_tools.is_some()`) | No — only the LLM-visible tool description; an internal steer tells the model to prefer `tool_search` | _none yet — add as found_ | -| **gemini-cli** (Google) | CLI | Yes | `read_mcp_resource`, `list_mcp_resources` | `(uri)` only — no server param ([Peter notes](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640#discussion_r3164100043) the client probes connected servers in turn until one resolves; **verify** against the loader code at next pass) | Yes — `read-mcp-resource.ts` calls `resources/read` | MCP manager present AND ≥1 connected server exposes a resource | Yes — `docs/tools/mcp-resources.md`, `docs/reference/tools.md:99-100`, `docs/cli/plan-mode.md:134-135` | _none yet — add as found_ | | **goose** (Block) | CLI | Yes | `read_resource`, `list_resources` | Today: `extension_name` is **optional** on `read_resource`; if omitted the handler probes every connected extension and swallows errors. PR [#8989](https://github.com/aaif-goose/goose/pull/8989) (open) makes it required, moving the signature to `(extension_name, uri)` | Yes — `ExtensionManager::read_resource` → `client.read_resource(...)` | ≥1 enabled extension reports `ServerCapabilities::resources` | Yes — `documentation/docs/mcp/extension-manager-mcp.md:70-81` | Issue [#8988](https://github.com/aaif-goose/goose/issues/8988) (open), PR [#8989](https://github.com/aaif-goose/goose/pull/8989) (open) | | **fast-agent** | Framework | Yes (multiplexed) | `get_resource`, `list_resources` | `(uri, server_name)` — also handles bundled `internal://` URIs through the same tool | Yes for MCP URIs — `_run_current_agent_get_resource_call` → `agent.get_resource(uri, namespace=server_name)`; `internal://` URIs short-circuit to bundled resources | Unconditional for every `SmartAgent` | Partial — `smart_prompt.md:26-28` instructs the model; design rationale in `plan/done/internal_resources.md`; no dedicated README section | _none yet — add as found_ | | **vscode** (GitHub Copilot) | IDE | Yes (FS-provider indirection) | `copilot_readFile`, `copilot_listDirectory` (general-purpose, not MCP-specific) | `(path)` — accepts `mcp-resource://…` URIs as paths; the FS provider routes to MCP RPC | Yes — `mcp-resource://` URIs route via `IFileService` → `McpResourceFilesystem` provider → `r.readResource(...)` MCP RPC (`mcpResourceFilesystem.ts:293`) | Server must advertise `McpCapability.Resources`; model needs a URI to pass (typically obtained from user attachment or from an MCP tool's `resource_link` response) | No explicit doc, but mechanism is operational. [Connor Peet's comment on #2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527#issuecomment-4282395437) is the clearest write-up | _none yet — add as found_ | @@ -36,13 +35,13 @@ Category values: **Framework** = SDK/library you build agents on top of · **CLI ## Cross-cutting observations 1. **Three implementation patterns for model-facing MCP resource access.** - 1. **Dedicated MCP resource tools** — Codex, Gemini CLI, Goose, Claude Code: explicit `read_mcp_resource` / `read_resource` (+ optional `list_*`) registered alongside other MCP tools. Most discoverable by the model; closest literal reading of #2527. + 1. **Dedicated MCP resource tools** — Codex, Goose, Claude Code: explicit `read_mcp_resource` / `read_resource` (+ optional `list_*`) registered alongside other MCP tools. Most discoverable by the model; closest literal reading of #2527. 2. **Multiplexed resource tool** — fast-agent: one `get_resource` tool handles both bundled (`internal://`) and MCP URIs behind a single name. Simpler surface for the model; relies on URI scheme to disambiguate. 3. **FS-provider indirection via namespaced URIs** — VS Code: no MCP-specific tool. A dedicated URI scheme (`mcp-resource://`) is registered with the filesystem service so the generic `readFile` / `listDirectory` tools transparently reach MCP `resources/read`. Reuses the agent's existing file-reading affordance; costs nothing in tool-count budget. Downside: no `list` equivalent — the model can only read URIs it's been handed. -2. **Tool signature is fragmented in pattern (1).** Among the dedicated-tool implementers, **Codex, fast-agent, and Claude Code** take an explicit `(server, uri)` pair. **Gemini-CLI and Goose**, currently make `uri` optional and as a fallback probe servers one-by-one until one resolves. +2. **Tool signature is fragmented in pattern (1).** Among the dedicated-tool implementers, **Codex, fast-agent, and Claude Code** take an explicit `(server, uri)` pair. **Goose** currently makes `uri` optional and as a fallback probes servers one-by-one until one resolves. -3. **Trust models diverge.** Per-server enablement (Goose, Gemini CLI), unconditional-when-MCP-configured (Codex), or capability-gated FS provider (VS Code). For skills-over-MCP this matters because the "who can read what" boundary is currently set by each host individually — a portable skill that depends on `resources/read` will work or not based on whether the host considers MCP resource access a model-grade affordance. +3. **Trust models diverge.** Per-server enablement (Goose), unconditional-when-MCP-configured (Codex), or capability-gated FS provider (VS Code). For skills-over-MCP this matters because the "who can read what" boundary is currently set by each host individually — a portable skill that depends on `resources/read` will work or not based on whether the host considers MCP resource access a model-grade affordance. 4. **Discoverability differs sharply between patterns.** Pattern (1) hosts pair `read_*` with a `list_*` so the model can enumerate resources on its own. Pattern (2) (fast-agent) has `list_resources`. Pattern (3) (VS Code) has *no list equivalent* — the model can only read a URI it's been handed (user attachment → chat context, or an MCP tool returning a `resource_link`). For skills this matters: a `skill://index.json`-style enumeration model implicitly assumes the model can either *list* or be *told* what's available. Pattern (3) needs the index handed in via attachment or a dedicated tool result. @@ -124,15 +123,6 @@ Verified at commit [`67849d9`](https://github.com/openai/codex/commit/67849d950d --- -#### gemini-cli (Google) _(verified)_ - -Verified at commit [`4e17552`](https://github.com/google-gemini/gemini-cli/commit/4e175527a2b241a68afd5f1509a8bebc21a44dfe). - -- **Model-facing tool:** [`read-mcp-resource.ts`](https://github.com/google-gemini/gemini-cli/blob/4e175527a2b241a68afd5f1509a8bebc21a44dfe/packages/core/src/tools/read-mcp-resource.ts) → MCP `resources/read` RPC at line 135. Active-tool gate requires `mcpManager.getAllResources().length > 0`. -- **Signature:** `(uri)` only — gemini-cli probes connected servers until one resolves. Documented at [`docs/tools/mcp-resources.md`](https://github.com/google-gemini/gemini-cli/blob/4e175527a2b241a68afd5f1509a8bebc21a44dfe/docs/tools/mcp-resources.md) and covered by [integration test](https://github.com/google-gemini/gemini-cli/blob/4e175527a2b241a68afd5f1509a8bebc21a44dfe/integration-tests/mcp-resources.test.ts). - ---- - #### goose (AAIF) _(verified)_ Verified at commit [`45d8bf8`](https://github.com/aaif-goose/goose/commit/45d8bf81d09d478ceedba8f6d1f0ad906123a981). @@ -197,10 +187,10 @@ Verified at commits [`530cb5d`](https://github.com/microsoft/vscode/commit/530cb ## Takeaways for SEP-2640 (skills extension) -- **Likely seven of sixteen open-source clients surveyed** (Codex, Gemini CLI, Goose, fast-agent, VS Code — verified — plus adk-python and hermes-agent on first-pass evidence pending verification) satisfy #2527's SHOULD. Gemini CLI and Goose also satisfy the implicit expectation that this be documented for end users. +- **Likely six of fifteen open-source clients surveyed** (Codex, Goose, fast-agent, VS Code — verified — plus adk-python and hermes-agent on first-pass evidence pending verification) satisfy #2527's SHOULD. Goose also satisfies the implicit expectation that this be documented for end users. - **Four implementation patterns** for model-facing MCP resource access — all support the layering Peter sketches in his #2640 comment, but with different costs: - **Dedicated tools, `(server, uri)`** (Codex, Claude Code, fast-agent — fast-agent is also multiplexed across `internal://`): explicit `read_resource` registered alongside other MCP tools. Most discoverable; closest literal reading of #2527. - - **Dedicated tools, `(uri)`-only with server probing** (Gemini CLI; Goose currently — open PR [aaif-goose/goose#8989](https://github.com/aaif-goose/goose/pull/8989) would move it to `(extension_name, uri)`, addressing issue [#8988](https://github.com/aaif-goose/goose/issues/8988)): cleaner signature but loses cross-server disambiguation. **Should probably be fixed independently of skills.** + - **Dedicated tools, `(uri)`-only with server probing** (Goose currently — open PR [aaif-goose/goose#8989](https://github.com/aaif-goose/goose/pull/8989) would move it to `(extension_name, uri)`, addressing issue [#8988](https://github.com/aaif-goose/goose/issues/8988)): cleaner signature but loses cross-server disambiguation. **Should probably be fixed independently of skills.** - **One tool per server, `(uri)`** (hermes-agent, first-pass): server is encoded in the tool name (`mcp_{server}_read_resource`), so the model selects the server by selecting the tool. Trades catalog tokens for unambiguity. - **FS-provider indirection via namespaced URIs** (VS Code): no MCP-specific tool. `mcp-resource://` URIs are registered with the file service; generic `readFile` / `listDirectory` tools transparently reach `resources/read`. Costs nothing in tool-count budget; loses `list` affordance. - **Signature mismatch is a portability hazard.** A skill that references `skill://code-review/checklist.json` resolves differently across hosts depending on whether the host disambiguates by server. **The spec should probably nudge implementations toward `(server, uri)` or per-server tool naming.** From 5236327232815c87ccf1d135d55c32d5e4aa8ce4 Mon Sep 17 00:00:00 2001 From: olaservo Date: Sat, 23 May 2026 19:52:58 -0700 Subject: [PATCH 06/12] docs: verify hermes-agent, switch source refs to main-branch links, refresh takeaways - Promote hermes-agent from first-pass to verified; note its per-server tool pattern (`mcp_{server}_read_resource` + `mcp_{server}_list_resources`) and confirm end-user docs exist - Drop stale line numbers throughout; convert path refs to GitHub source-file links on `main` (commit-pinned URLs decayed once files moved) - Goose: PR #8989 has landed, so describe current `(extension_name, uri)` required signature and drop the now-closed issue/PR tracking - Takeaways: collapse to three implementation patterns (Goose now fits the `(server, uri)` bucket), fix open-source count to fourteen, drop the smolagents name-drop (not in survey), add strands-agents alongside mastra for the internal-SDK-only pattern, and reframe the signature recommendation around server-resolution reliability rather than URI portability --- docs/client-mcp-support.md | 95 ++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/docs/client-mcp-support.md b/docs/client-mcp-support.md index dff52a5..12be59f 100644 --- a/docs/client-mcp-support.md +++ b/docs/client-mcp-support.md @@ -17,20 +17,20 @@ Category values: **Framework** = SDK/library you build agents on top of · **CLI | Client | Category | Tool exposed to model? | Tool name(s) | Tool signature | Calls `resources/read` on connected server? | Enablement gate | End-user docs? | Open issues/PRs to watch | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | **codex** (OpenAI) | CLI | Yes | `read_mcp_resource`, `list_mcp_resources`, `list_mcp_resource_templates` | `(server, uri)` — server explicitly named | Yes — handler calls `session.read_resource()` | Any MCP server is configured (`params.mcp_tools.is_some()`) | No — only the LLM-visible tool description; an internal steer tells the model to prefer `tool_search` | _none yet — add as found_ | -| **goose** (Block) | CLI | Yes | `read_resource`, `list_resources` | Today: `extension_name` is **optional** on `read_resource`; if omitted the handler probes every connected extension and swallows errors. PR [#8989](https://github.com/aaif-goose/goose/pull/8989) (open) makes it required, moving the signature to `(extension_name, uri)` | Yes — `ExtensionManager::read_resource` → `client.read_resource(...)` | ≥1 enabled extension reports `ServerCapabilities::resources` | Yes — `documentation/docs/mcp/extension-manager-mcp.md:70-81` | Issue [#8988](https://github.com/aaif-goose/goose/issues/8988) (open), PR [#8989](https://github.com/aaif-goose/goose/pull/8989) (open) | -| **fast-agent** | Framework | Yes (multiplexed) | `get_resource`, `list_resources` | `(uri, server_name)` — also handles bundled `internal://` URIs through the same tool | Yes for MCP URIs — `_run_current_agent_get_resource_call` → `agent.get_resource(uri, namespace=server_name)`; `internal://` URIs short-circuit to bundled resources | Unconditional for every `SmartAgent` | Partial — `smart_prompt.md:26-28` instructs the model; design rationale in `plan/done/internal_resources.md`; no dedicated README section | _none yet — add as found_ | -| **vscode** (GitHub Copilot) | IDE | Yes (FS-provider indirection) | `copilot_readFile`, `copilot_listDirectory` (general-purpose, not MCP-specific) | `(path)` — accepts `mcp-resource://…` URIs as paths; the FS provider routes to MCP RPC | Yes — `mcp-resource://` URIs route via `IFileService` → `McpResourceFilesystem` provider → `r.readResource(...)` MCP RPC (`mcpResourceFilesystem.ts:293`) | Server must advertise `McpCapability.Resources`; model needs a URI to pass (typically obtained from user attachment or from an MCP tool's `resource_link` response) | No explicit doc, but mechanism is operational. [Connor Peet's comment on #2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527#issuecomment-4282395437) is the clearest write-up | _none yet — add as found_ | -| **opencode** | CLI | No | — (internal `readResource` only) | — | Internal only — `readResource()` exists at `packages/opencode/src/mcp/index.ts:722-726` but is invoked only when the user attaches a resource via file picker; `mcp.tools()` at `prompt.ts:444` forwards MCP *tools* but never a resource-read tool | n/a | Docs (`mcp-servers.mdx:8`) advertise tool forwarding only | _none yet — add as found_ | -| **deepagents** (LangChain) | Framework | No | — | — | n/a — delegates MCP wiring to [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters) via `load_mcp_tools()` (`mcp_tools.py:519-521`); that adapter only converts MCP tools, not resources | n/a | No mention in README | **Upstream-blocked**: needs a change in `langchain-mcp-adapters` (or a deepagents wrapper around `client.read_resource()`) | -| **strands-agents** (AWS) | Framework | No (internal SDK only) | — | — | Internal only — `MCPClient.read_resource_sync()` (`src/strands/tools/mcp/mcp_client.py:524`) and `list_resources_sync()` (line 500) call MCP `resources/read` / `resources/list`, but `MCPAgentTool` (the only adapter) wraps `mcp.types.Tool` only and `MCPClient.load_tools()` (the `ToolProvider` interface, line 227) returns tools only | n/a | _unknown — verify_ | _none yet — add as found_ | +| **goose** (Block) | CLI | Yes | `read_resource`, `list_resources` | `(extension_name, uri)` on `read_resource` — `extension_name` required; `list_resources` takes an optional `extension_name` filter | Yes — `ExtensionManager::read_resource` → `client.read_resource(...)` | ≥1 enabled extension reports `ServerCapabilities::resources` | Yes — [`extension-manager-mcp.md`](https://github.com/block/goose/blob/main/documentation/docs/mcp/extension-manager-mcp.md) | _none yet — add as found_ | +| **fast-agent** | Framework | Yes (multiplexed) | `get_resource`, `list_resources` | `(uri, server_name)` — also handles bundled `internal://` URIs through the same tool | Yes for MCP URIs — `_run_current_agent_get_resource_call` → `agent.get_resource(uri, namespace=server_name)`; `internal://` URIs short-circuit to bundled resources | Unconditional for every `SmartAgent` | Partial — `smart_prompt.md` instructs the model; design rationale in `plan/done/internal_resources.md`; no dedicated README section | _none yet — add as found_ | +| **vscode** (GitHub Copilot) | IDE | Yes (FS-provider indirection) | `copilot_readFile`, `copilot_listDirectory` (general-purpose, not MCP-specific) | `(path)` — accepts `mcp-resource://…` URIs as paths; the FS provider routes to MCP RPC | Yes — `mcp-resource://` URIs route via `IFileService` → `McpResourceFilesystem` provider → `r.readResource(...)` MCP RPC ([`mcpResourceFilesystem.ts`](https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.ts)) | Server must advertise `McpCapability.Resources`; model needs a URI to pass (typically obtained from user attachment or from an MCP tool's `resource_link` response) | No explicit doc, but mechanism is operational. [Connor Peet's comment on #2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527#issuecomment-4282395437) is the clearest write-up | _none yet — add as found_ | +| **opencode** | CLI | No | — (internal `readResource` only) | — | Internal only — `readResource()` exists in [`packages/opencode/src/mcp/index.ts`](https://github.com/anomalyco/opencode/blob/main/packages/opencode/src/mcp/index.ts) but is invoked only when the user attaches a resource via file picker; `mcp.tools()` in `prompt.ts` forwards MCP *tools* but never a resource-read tool | n/a | Docs (`mcp-servers.mdx`) advertise tool forwarding only | _none yet — add as found_ | +| **deepagents** (LangChain) | Framework | No | — | — | n/a — delegates MCP wiring to [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters) via `load_mcp_tools()` (in [`mcp_tools.py`](https://github.com/langchain-ai/deepagents/blob/main/src/deepagents/mcp_tools.py)); that adapter only converts MCP tools, not resources | n/a | No mention in README | **Upstream-blocked**: needs a change in `langchain-mcp-adapters` (or a deepagents wrapper around `client.read_resource()`) | +| **strands-agents** (AWS) | Framework | No (internal SDK only) | — | — | Internal only — `MCPClient.read_resource_sync()` and `list_resources_sync()` in [`mcp_client.py`](https://github.com/strands-agents/sdk-python/blob/main/src/strands/tools/mcp/mcp_client.py) call MCP `resources/read` / `resources/list`, but `MCPAgentTool` (the only adapter) wraps `mcp.types.Tool` only and `MCPClient.load_tools()` (the `ToolProvider` interface) returns tools only | n/a | _unknown — verify_ | _none yet — add as found_ | | **Claude Code** (closed source, reference) | CLI | Yes | `ReadMcpResourceTool` | `(server, uri)` per [public docs](https://code.claude.com/docs/en/tools-reference) | Documented; source not verifiable | n/a | Yes — public tools reference page | n/a | -| **adk-python** (Google ADK) | Framework | Yes _(unverified — first pass below)_ | `load_mcp_resource` | Two-shot — discovers resources first, then takes a `resource_name` to read | Yes — `MCPToolset.read_resource()` calls `session.read_resource(uri)` (`tools/mcp_tool/mcp_toolset.py`) | Toolset must be configured with at least one MCP server | _unknown — verify_ | _none yet — add as found_ | -| **agent-framework** (Microsoft) | Framework | No (tools-only client bridge) | — | — | n/a — `MCPTool` / `MCPStdioTool` / `MCPStreamableHTTPTool` / `MCPWebsocketTool` in `python/packages/core/agent_framework/_mcp.py` materialize MCP *tools* into the agent's tool registry; no `read_resource` callsite found in client code (only in a test) | n/a | Samples cover MCP tool integration only | _none yet — add as found_ | +| **adk-python** (Google ADK) | Framework | Yes _(unverified — first pass below)_ | `load_mcp_resource` | Two-shot — discovers resources first, then takes a `resource_name` to read | Yes — `MCPToolset.read_resource()` calls `session.read_resource(uri)` ([`mcp_toolset.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/mcp_tool/mcp_toolset.py)) | Toolset must be configured with at least one MCP server | _unknown — verify_ | _none yet — add as found_ | +| **agent-framework** (Microsoft) | Framework | No (tools-only client bridge) | — | — | n/a — `MCPTool` / `MCPStdioTool` / `MCPStreamableHTTPTool` / `MCPWebsocketTool` in [`_mcp.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/_mcp.py) materialize MCP *tools* into the agent's tool registry; no `read_resource` callsite found in client code (only in a test) | n/a | Samples cover MCP tool integration only | _none yet — add as found_ | | **cline** | IDE | No | — | — | n/a — depends on `@modelcontextprotocol/sdk` for MCP, but zero matches for `resources/read` / `readResource` / `read_resource` in source. Tools-only bridge | n/a | MCP docs cover tools and config only | _none yet — add as found_ | -| **crewAI** | Framework | No | — | — | n/a — `crewai-tools` MCP adapter (`lib/crewai-tools/src/crewai_tools/adapters/mcp_adapter.py`) is built on `mcpadapt` and converts MCP tools only — same upstream-blocked pattern as smolagents | n/a | MCP adapter docs cover tools only | **Upstream-blocked** by `mcpadapt` (shared with smolagents) | -| **hermes-agent** (Nous Research) | CLI | Yes _(unverified — first pass below)_ | `mcp_{server}_read_resource` (one per connected server) | `(uri)` — server is encoded in the tool name | Yes — `_make_read_resource_handler()` in `tools/mcp_tool.py:~2159` calls `session.read_resource(uri)`; tool registered at `~2529` | Conditional — only registered when the server advertises resources (line ~2626) | _unknown — verify_ | _none yet — add as found_ | -| **mastra** | Framework | No (internal SDK only) | — | — | Internal only — `packages/mcp/src/client/actions/resource.ts:~130` exposes a `read(uri)` SDK method that calls `client.readResource(uri)`, but it is **not** registered as an LLM-facing tool; the model-facing tool bridge converts MCP tools only | n/a | SDK docs cover the action; no LLM-tool exposure | _none yet — add as found_ | -| **Roo-Code** | IDE | No | — | — | n/a — `src/services/mcp/McpHub.ts` imports `ReadResourceResultSchema` from the SDK but does not register a model-facing resource-read tool; the MCP hub maps tools only | n/a | _unknown — verify_ | _none yet — add as found_ | +| **crewAI** | Framework | No | — | — | n/a — `crewai-tools` MCP adapter ([`mcp_adapter.py`](https://github.com/crewAIInc/crewAI-tools/blob/main/crewai_tools/adapters/mcp_adapter.py)) is built on `mcpadapt` and converts MCP tools only — same upstream-blocked pattern as smolagents | n/a | MCP adapter docs cover tools only | **Upstream-blocked** by `mcpadapt` (shared with smolagents) | +| **hermes-agent** (Nous Research) | CLI | Yes | `mcp_{server}_read_resource`, `mcp_{server}_list_resources` (one pair per connected server) | `(uri)` — server is encoded in the tool name | Yes — `_make_read_resource_handler()` in [`tools/mcp_tool.py`](https://github.com/NousResearch/hermes-agent/blob/main/tools/mcp_tool.py) calls `session.read_resource(uri)` and registers the tool per server | Two gates: `tools.resources` config flag (default on) AND server's advertised `capabilities.resources` | Yes — [`features/mcp.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/mcp.md) and [`guides/use-mcp-with-hermes.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/guides/use-mcp-with-hermes.md) | _none yet — add as found_ | +| **mastra** | Framework | No (internal SDK only) | — | — | Internal only — [`resource.ts`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/actions/resource.ts) exposes a `read(uri)` SDK method that calls `client.readResource(uri)`, but it is **not** registered as an LLM-facing tool; the model-facing tool bridge converts MCP tools only | n/a | SDK docs cover the action; no LLM-tool exposure | _none yet — add as found_ | +| **Roo-Code** | IDE | No | — | — | n/a — [`McpHub.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) imports `ReadResourceResultSchema` from the SDK but does not register a model-facing resource-read tool; the MCP hub maps tools only | n/a | _unknown — verify_ | _none yet — add as found_ | ## Cross-cutting observations @@ -39,7 +39,7 @@ Category values: **Framework** = SDK/library you build agents on top of · **CLI 2. **Multiplexed resource tool** — fast-agent: one `get_resource` tool handles both bundled (`internal://`) and MCP URIs behind a single name. Simpler surface for the model; relies on URI scheme to disambiguate. 3. **FS-provider indirection via namespaced URIs** — VS Code: no MCP-specific tool. A dedicated URI scheme (`mcp-resource://`) is registered with the filesystem service so the generic `readFile` / `listDirectory` tools transparently reach MCP `resources/read`. Reuses the agent's existing file-reading affordance; costs nothing in tool-count budget. Downside: no `list` equivalent — the model can only read URIs it's been handed. -2. **Tool signature is fragmented in pattern (1).** Among the dedicated-tool implementers, **Codex, fast-agent, and Claude Code** take an explicit `(server, uri)` pair. **Goose** currently makes `uri` optional and as a fallback probes servers one-by-one until one resolves. +2. **Dedicated-tool implementers converge on `(server, uri)`.** Codex, Goose, fast-agent, and Claude Code all take an explicit server identifier alongside the URI. hermes-agent is the remaining variant in pattern (1)'s family: it encodes server-in-tool-name (one tool per server) and takes only `(uri)`. 3. **Trust models diverge.** Per-server enablement (Goose), unconditional-when-MCP-configured (Codex), or capability-gated FS provider (VS Code). For skills-over-MCP this matters because the "who can read what" boundary is currently set by each host individually — a portable skill that depends on `resources/read` will work or not based on whether the host considers MCP resource access a model-grade affordance. @@ -55,31 +55,31 @@ Category values: **Framework** = SDK/library you build agents on top of · **CLI Verified at commit [`502d32e`](https://github.com/evalstate/fast-agent/commit/502d32e266f3221d744977f38b7a9b4bc5b93947). -- **Model-facing tool:** `get_resource` registered at [`smart_agent.py:1478-1489`](https://github.com/evalstate/fast-agent/blob/502d32e266f3221d744977f38b7a9b4bc5b93947/src/fast_agent/agents/smart_agent.py) via `agent.add_tool(...)`. Dispatcher at `smart_agent.py:1529-1540` routes `internal://` to bundled resources; everything else hits the connected MCP server via `agent.get_resource(uri, namespace=server_name)` → MCP `resources/read`. +- **Model-facing tool:** `get_resource` registered in [`smart_agent.py`](https://github.com/evalstate/fast-agent/blob/main/src/fast_agent/agents/smart_agent.py) via `agent.add_tool(...)`. The dispatcher in the same file routes `internal://` to bundled resources; everything else hits the connected MCP server via `agent.get_resource(uri, namespace=server_name)` → MCP `resources/read`. - **Signature:** `(uri, server_name)` — multiplexed across bundled and MCP URIs by scheme. MCP behavior depends on what the model passes for `server_name`. --- #### adk-python (Google ADK) _(first pass — verify before citing)_ -- **MCP integration:** `src/google/adk/tools/mcp_tool/` package — `MCPToolset` is the entry point used by callers to connect an ADK agent to an MCP server. -- **Resource RPC wired:** `src/google/adk/tools/mcp_toolset.py:~380` exposes `async def read_resource()` which calls `session.read_resource(uri)` (~line 397). -- **Model-facing tool:** `src/google/adk/tools/load_mcp_resource_tool.py:~44` defines `load_mcp_resource`. Per the first-pass scan, the tool is two-shot — first invocation lists resources, then the model picks a `resource_name` for the second call (line ~131). **Verify the exact schema and confirm it's registered alongside the other ADK tools the agent sees.** +- **MCP integration:** [`src/google/adk/tools/mcp_tool/`](https://github.com/google/adk-python/tree/main/src/google/adk/tools/mcp_tool) package — `MCPToolset` is the entry point used by callers to connect an ADK agent to an MCP server. +- **Resource RPC wired:** [`mcp_toolset.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/mcp_tool/mcp_toolset.py) exposes `async def read_resource()` which calls `session.read_resource(uri)`. +- **Model-facing tool:** [`load_mcp_resource_tool.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/mcp_tool/load_mcp_resource_tool.py) defines `load_mcp_resource`. Per the first-pass scan, the tool is two-shot — first invocation lists resources, then the model picks a `resource_name` for the second call. **Verify the exact schema and confirm it's registered alongside the other ADK tools the agent sees.** - **Why interesting:** ADK is one of two clients in the gap (with hermes-agent) that may already satisfy #2527 — and it's also the client with the most rigorous skill validation in the parallel skills survey, so this is where the spec extension and the resource-tool extension converge. --- #### agent-framework (Microsoft) _(first pass — verify before citing)_ -- **MCP integration:** Multi-transport client tools (`MCPTool` + Stdio/HTTP/Websocket variants) in `python/packages/core/agent_framework/_mcp.py`, with .NET equivalents under `dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Models/`. Tools-only bridge; zero `read_resource` callsites in source (only in tests). +- **MCP integration:** Multi-transport client tools (`MCPTool` + Stdio/HTTP/Websocket variants) in [`_mcp.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/_mcp.py), with .NET equivalents under [`dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Models/`](https://github.com/microsoft/agent-framework/tree/main/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Models). Tools-only bridge; zero `read_resource` callsites in source (only in tests). - **Why on the list:** dual-stack Python/.NET framework with rich skills metadata in the parallel skills survey. The asymmetry — skills support without resource-tool support — is the kind of gap a #2527-aligned PR would close. --- #### crewAI _(first pass — verify before citing)_ -- **MCP integration:** `lib/crewai-tools/src/crewai_tools/adapters/mcp_adapter.py` imports `mcp` + `mcpadapt.core` and converts MCP tools to CrewAI `BaseTool` objects. -- **Resource RPC wired:** No — adapter handles only `Tool` types (line ~19). +- **MCP integration:** [`mcp_adapter.py`](https://github.com/crewAIInc/crewAI-tools/blob/main/crewai_tools/adapters/mcp_adapter.py) imports `mcp` + `mcpadapt.core` and converts MCP tools to CrewAI `BaseTool` objects. +- **Resource RPC wired:** No — adapter handles only `Tool` types. - **Model-facing tool:** None. - **Why on the list:** Same upstream block as **smolagents** — both depend on [`mcpadapt`](https://github.com/grll/mcpadapt), which is tools-only. A single upstream change in `mcpadapt` flips both clients. This is the highest-leverage adapter-library target identified so far. @@ -89,14 +89,14 @@ Verified at commit [`502d32e`](https://github.com/evalstate/fast-agent/commit/50 Verified at commit [`a64ff43`](https://github.com/langchain-ai/deepagents/commit/a64ff430f14b76607dfb1d78234f928ed88a3af0). -- **MCP wiring is outsourced** to `langchain_mcp_adapters.tools.load_mcp_tools()` (called from `mcp_tools.py:519-521`). The upstream adapter does not expose `resources/read` as a tool — zero hits for resource-read in deepagents source. +- **MCP wiring is outsourced** to `langchain_mcp_adapters.tools.load_mcp_tools()` (called from [`mcp_tools.py`](https://github.com/langchain-ai/deepagents/blob/main/src/deepagents/mcp_tools.py)). The upstream adapter does not expose `resources/read` as a tool — zero hits for resource-read in deepagents source. - **What it would take:** either upstream adds a resource-read tool, or deepagents wraps `client.read_resource()` outside the adapter. --- #### mastra _(first pass — verify before citing)_ -- **MCP integration:** `packages/mcp/src/client/` imports `@modelcontextprotocol/sdk`. `packages/mcp/src/client/actions/resource.ts:~130` exposes `async read(uri)` which calls `this.client.readResource(uri)`. +- **MCP integration:** [`packages/mcp/src/client/`](https://github.com/mastra-ai/mastra/tree/main/packages/mcp/src/client) imports `@modelcontextprotocol/sdk`. [`resource.ts`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/actions/resource.ts) exposes `async read(uri)` which calls `this.client.readResource(uri)`. - **Resource RPC wired:** Yes, but **internal SDK only**. `ResourceClientActions` is an SDK surface for callers, not registered as an LLM-facing tool. - **Model-facing tool:** No. The model-facing tool bridge converts MCP tools only; resources require explicit code to invoke. - **Why on the list:** Mastra's skill versioning architecture (content-addressable BlobStore, draft→publish lifecycle) is the most sophisticated. Unlocking resource-read at the model boundary would be a small change relative to the rest of the framework — the SDK plumbing already exists. @@ -107,8 +107,8 @@ Verified at commit [`a64ff43`](https://github.com/langchain-ai/deepagents/commit Verified at commit [`8638fc2`](https://github.com/strands-agents/sdk-python/commit/8638fc2d629e32b7b5839f4c106d5aedcdf764c9) (2026-05-04). Strands matches the **mastra pattern**: resource RPC wired in the SDK, but no model-facing tool. -- **Resource RPC wired but unbridged:** `MCPClient.read_resource_sync()` ([`mcp_client.py:524`](https://github.com/strands-agents/sdk-python/blob/8638fc2d629e32b7b5839f4c106d5aedcdf764c9/src/strands/tools/mcp/mcp_client.py)), `list_resources_sync()` (line 500), and `list_resource_templates_sync()` are SDK-public methods, but [`MCPAgentTool`](https://github.com/strands-agents/sdk-python/blob/8638fc2d629e32b7b5839f4c106d5aedcdf764c9/src/strands/tools/mcp/mcp_agent_tool.py) only wraps `mcp.types.Tool` and delegates to `call_tool_async(...)`. Outside tests, nothing in the repo invokes the resource methods. -- **Why on the list:** Strands has its own local-filesystem skills implementation at `src/strands/vended_plugins/skills/agent_skills.py`, so the framework already does progressive disclosure. Wiring resource-read to the model is the obvious next step for an MCP-backed skill story. +- **Resource RPC wired but unbridged:** `MCPClient.read_resource_sync()`, `list_resources_sync()`, and `list_resource_templates_sync()` in [`mcp_client.py`](https://github.com/strands-agents/sdk-python/blob/main/src/strands/tools/mcp/mcp_client.py) are SDK-public methods, but [`MCPAgentTool`](https://github.com/strands-agents/sdk-python/blob/main/src/strands/tools/mcp/mcp_agent_tool.py) only wraps `mcp.types.Tool` and delegates to `call_tool_async(...)`. Outside tests, nothing in the repo invokes the resource methods. +- **Why on the list:** Strands has its own local-filesystem skills implementation at [`agent_skills.py`](https://github.com/strands-agents/sdk-python/blob/main/src/strands/vended_plugins/skills/agent_skills.py), so the framework already does progressive disclosure. Wiring resource-read to the model is the obvious next step for an MCP-backed skill story. --- @@ -118,7 +118,7 @@ Verified at commit [`8638fc2`](https://github.com/strands-agents/sdk-python/comm Verified at commit [`67849d9`](https://github.com/openai/codex/commit/67849d950d843c954102adb0db0e11f993aefdb7). -- **Model-facing tools:** `read_mcp_resource`, `list_mcp_resources`, `list_mcp_resource_templates` defined at [`mcp_resource_tool.rs`](https://github.com/openai/codex/blob/67849d950d843c954102adb0db0e11f993aefdb7/codex-rs/tools/src/mcp_resource_tool.rs); registered unconditionally when an MCP server is configured. Handler at [`mcp_resource.rs`](https://github.com/openai/codex/blob/67849d950d843c954102adb0db0e11f993aefdb7/codex-rs/core/src/tools/handlers/mcp_resource.rs) → `session.read_resource()`. +- **Model-facing tools:** `read_mcp_resource`, `list_mcp_resources`, `list_mcp_resource_templates` defined at [`mcp_resource_tool.rs`](https://github.com/openai/codex/blob/main/codex-rs/tools/src/mcp_resource_tool.rs); registered unconditionally when an MCP server is configured. Handler at [`mcp_resource.rs`](https://github.com/openai/codex/blob/main/codex-rs/core/src/tools/handlers/mcp_resource.rs) → `session.read_resource()`. - **Signature:** `(server, uri)` — model names the server explicitly. No user-facing doc; an internal steer tells the model to prefer `tool_search`. --- @@ -127,18 +127,21 @@ Verified at commit [`67849d9`](https://github.com/openai/codex/commit/67849d950d Verified at commit [`45d8bf8`](https://github.com/aaif-goose/goose/commit/45d8bf81d09d478ceedba8f6d1f0ad906123a981). -- **Model-facing tools:** `read_resource`, `list_resources` registered at [`platform_extensions/ext_manager.rs:264-372`](https://github.com/aaif-goose/goose/blob/45d8bf81d09d478ceedba8f6d1f0ad906123a981/crates/goose/src/agents/platform_extensions/ext_manager.rs) when at least one extension reports `ServerCapabilities::resources`. Dispatch flows through [`extension_manager.rs:1262-1297`](https://github.com/aaif-goose/goose/blob/45d8bf81d09d478ceedba8f6d1f0ad906123a981/crates/goose/src/agents/extension_manager.rs) → `client.read_resource(...)` → MCP `resources/read`. Documented at [`extension-manager-mcp.md`](https://github.com/block/goose/blob/main/documentation/docs/mcp/extension-manager-mcp.md). -- **Signature:** Peter's #2640 claim is correct — `extension_name` is currently *optional* on `read_resource`, and the handler probes every connected extension and swallows errors when it's omitted. Issue [#8988](https://github.com/aaif-goose/goose/issues/8988) describes the bug; PR [#8989](https://github.com/aaif-goose/goose/pull/8989) (open) makes it required and rewrites the tool description to direct the model to call `list_resources` first when ownership is unknown. The PR also fixes a separate bug where `list_resources`'s schema declares `extension_name` but the handler reads `extension`, silently ignoring the model's filter. +- **Model-facing tools:** `read_resource`, `list_resources` registered in [`ext_manager.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/agents/platform_extensions/ext_manager.rs) when at least one extension reports `ServerCapabilities::resources`. Dispatch flows through [`extension_manager.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/agents/extension_manager.rs) → `client.read_resource(...)` → MCP `resources/read`. Documented at [`extension-manager-mcp.md`](https://github.com/block/goose/blob/main/documentation/docs/mcp/extension-manager-mcp.md). +- **Signature:** `(extension_name, uri)` on `read_resource` — `extension_name` is required. `list_resources` takes an optional `extension_name` filter; the tool description directs the model to call `list_resources` first when ownership is unknown. --- -#### hermes-agent (Nous Research) _(first pass — verify before citing)_ +#### hermes-agent (Nous Research) _(verified)_ -- **MCP integration:** Full integration in `tools/mcp_tool.py`. -- **Resource RPC wired:** Yes — `_make_read_resource_handler()` at `tools/mcp_tool.py:~2159` calls `session.read_resource(uri)` at `~2178`. -- **Model-facing tool:** Yes — `mcp_{safe_name}_read_resource` registered per connected server at `tools/mcp_tool.py:~2529`, taking a `uri` parameter (handler key `read_resource` at `~2542`). Conditionally registered when the server advertises resources (`~2626`). -- **Signature:** `(uri)` — server is encoded in the tool name (one tool per server), so the model implicitly selects the server by selecting the tool. **Distinct from every other pattern surveyed**: not `(server, uri)`, not `(uri)`-with-probing, not URI-virtualized — it's *one tool per server*. Worth highlighting in the cross-cutting observations once verified. -- **Why interesting:** With adk-python, this is the second of the seven gap-clients that likely already satisfies #2527. The per-server-tool naming is also a candidate disambiguation pattern for skills-over-MCP. +Verified at commit [`72ff3e9`](https://github.com/NousResearch/hermes-agent/commit/72ff3e909c73b625ee244ab5ea3d0608ee85dcf3) (2026-05-23). + +- **MCP integration:** Full integration in [`tools/mcp_tool.py`](https://github.com/NousResearch/hermes-agent/blob/main/tools/mcp_tool.py). +- **Resource RPC wired:** Yes — `_make_read_resource_handler()` calls `await server.session.read_resource(uri)`. +- **Model-facing tools:** Yes — both `mcp_{safe_name}_read_resource` (taking `uri`) and `mcp_{safe_name}_list_resources` (no parameters) registered per connected server via `_build_utility_schemas()`. Conditionally registered when the server advertises `capabilities.resources` AND the per-server `tools.resources` config flag is on (default). +- **Signature:** `(uri)` — server is encoded in the tool name (one tool per server), so the model implicitly selects the server by selecting the tool. **Distinct from every other pattern surveyed**: not `(server, uri)`, not `(uri)`-with-probing, not URI-virtualized — it's *one tool per server*. The matching `list_resources` per server gives the model a discovery affordance without cross-server probing. +- **End-user docs:** [`features/mcp.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/mcp.md) and [`guides/use-mcp-with-hermes.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/guides/use-mcp-with-hermes.md) both document the utility wrappers. (Minor doc/code mismatch: the user-facing docs name the tools as bare `read_resource` / `list_resources`, but the actual model-facing names include the `mcp_{server}_` prefix.) +- **Why interesting:** With adk-python, this is the second of the seven gap-clients that already satisfies #2527. The per-server-tool naming is also a candidate disambiguation pattern for skills-over-MCP. --- @@ -152,8 +155,8 @@ Claude Code is closed source so we cannot verify the loader, but the [public too Verified at commit [`ce89bcb`](https://github.com/anomalyco/opencode/commit/ce89bcb8e238401ea8fee000dc54539057d47dc4). -- **Tools forwarded to the model** at `packages/opencode/src/mcp/index.ts:444-519` via `client.callTool()`; tool naming convention `{server_name}:{tool_name}`. -- **Resource-read is UI-only:** `readResource()` at `mcp/index.ts:722-726` is invoked from the file picker, never registered as an LLM tool. Docs (`mcp-servers.mdx:8`) advertise tool forwarding only. +- **Tools forwarded to the model** in [`packages/opencode/src/mcp/index.ts`](https://github.com/anomalyco/opencode/blob/main/packages/opencode/src/mcp/index.ts) via `client.callTool()`; tool naming convention `{server_name}:{tool_name}`. +- **Resource-read is UI-only:** `readResource()` in the same file is invoked from the file picker, never registered as an LLM tool. Docs ([`mcp-servers.mdx`](https://github.com/anomalyco/opencode/blob/main/packages/web/src/content/docs/docs/mcp-servers.mdx)) advertise tool forwarding only. --- @@ -163,8 +166,8 @@ Verified at commit [`ce89bcb`](https://github.com/anomalyco/opencode/commit/ce89 Verified at commits [`530cb5d`](https://github.com/microsoft/vscode/commit/530cb5de713aec2e96059e2f6cf41a95403cdb3d) (vscode core) and [`9e668cb`](https://github.com/microsoft/vscode-copilot-chat/commit/9e668cb12144c701cf0f2c6b3458c00fe3da20f1) (Copilot Chat extension). VS Code is the unique pattern here: no MCP-specific tool — generic `copilot_readFile` / `copilot_listDirectory` tools transparently reach MCP servers via filesystem-provider indirection on a custom URI scheme. -- **URI scheme + FS provider:** [`McpResourceURI`](https://github.com/microsoft/vscode/blob/530cb5de713aec2e96059e2f6cf41a95403cdb3d/src/vs/workbench/contrib/mcp/common/mcpTypes.ts) defines `mcp-resource://` URIs that encode the MCP server's definition ID in the authority — self-routing. [`McpResourceFilesystem`](https://github.com/microsoft/vscode/blob/530cb5de713aec2e96059e2f6cf41a95403cdb3d/src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.ts) is registered for that scheme; `_readURIInner` decodes the URI, looks up the `McpServer`, and calls `r.readResource(...)` (line 293) — the MCP `resources/read` RPC. Capability-gated on `McpCapability.Resources`. -- **`resource_link` pre-wrap:** when an MCP tool returns a `resource_link`, `mcpLanguageModelToolContribution.ts:336-358` converts it into an `mcp-resource://` URI so the model can re-read it later via `copilot_readFile`. +- **URI scheme + FS provider:** [`McpResourceURI`](https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/mcp/common/mcpTypes.ts) defines `mcp-resource://` URIs that encode the MCP server's definition ID in the authority — self-routing. [`McpResourceFilesystem`](https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.ts) is registered for that scheme; `_readURIInner` decodes the URI, looks up the `McpServer`, and calls `r.readResource(...)` — the MCP `resources/read` RPC. Capability-gated on `McpCapability.Resources`. +- **`resource_link` pre-wrap:** when an MCP tool returns a `resource_link`, [`mcpLanguageModelToolContribution.ts`](https://github.com/microsoft/vscode-copilot-chat/blob/main/src/extension/conversation/vscode-node/mcpLanguageModelToolContribution.ts) converts it into an `mcp-resource://` URI so the model can re-read it later via `copilot_readFile`. - **Caveat — discoverability:** the model can only read a URI it has been handed (user attachment, or an MCP tool's `resource_link`). No `list_mcp_resources`-equivalent. [Connor Peet on PR #2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527#issuecomment-4282395437) is the clearest write-up of this pattern. --- @@ -180,19 +183,19 @@ Verified at commits [`530cb5d`](https://github.com/microsoft/vscode/commit/530cb #### Roo-Code _(first pass — verify before citing)_ -- **MCP integration:** `src/services/mcp/McpHub.ts` imports from `@modelcontextprotocol/sdk/types.js`, including `ReadResourceResultSchema` (line ~15). +- **MCP integration:** [`McpHub.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) imports from `@modelcontextprotocol/sdk/types.js`, including `ReadResourceResultSchema`. - **Resource RPC wired:** Schema imports suggest the capability is reachable, but no explicit `readResource` handler was found in `McpHub` on first pass; the hub maps tools only (the observed pattern is `tools = (response?.tools).map(...)`). - **Model-facing tool:** No. - **Why on the list:** Roo-Code has both a skills implementation and an MCP hub, and the SDK type imports indicate someone *intended* to surface resources at some point. Worth a thorough read of `McpHub.ts` to confirm whether resources are partially implemented or simply unused. ## Takeaways for SEP-2640 (skills extension) -- **Likely six of fifteen open-source clients surveyed** (Codex, Goose, fast-agent, VS Code — verified — plus adk-python and hermes-agent on first-pass evidence pending verification) satisfy #2527's SHOULD. Goose also satisfies the implicit expectation that this be documented for end users. -- **Four implementation patterns** for model-facing MCP resource access — all support the layering Peter sketches in his #2640 comment, but with different costs: - - **Dedicated tools, `(server, uri)`** (Codex, Claude Code, fast-agent — fast-agent is also multiplexed across `internal://`): explicit `read_resource` registered alongside other MCP tools. Most discoverable; closest literal reading of #2527. - - **Dedicated tools, `(uri)`-only with server probing** (Goose currently — open PR [aaif-goose/goose#8989](https://github.com/aaif-goose/goose/pull/8989) would move it to `(extension_name, uri)`, addressing issue [#8988](https://github.com/aaif-goose/goose/issues/8988)): cleaner signature but loses cross-server disambiguation. **Should probably be fixed independently of skills.** - - **One tool per server, `(uri)`** (hermes-agent, first-pass): server is encoded in the tool name (`mcp_{server}_read_resource`), so the model selects the server by selecting the tool. Trades catalog tokens for unambiguity. +- **Likely six of fourteen open-source clients surveyed** (Codex, Goose, fast-agent, VS Code, hermes-agent — verified — plus adk-python on first-pass evidence pending verification) satisfy #2527's SHOULD; closed-source Claude Code's public docs confirm it does too. Goose and hermes-agent also satisfy the implicit expectation that this be documented for end users. +- **Three implementation patterns** for model-facing MCP resource access — all support the layering Peter sketches in his #2640 comment, but with different costs: + - **Dedicated tools, `(server, uri)`** (Codex, Goose, Claude Code, fast-agent — fast-agent is also multiplexed across `internal://`): explicit `read_resource` registered alongside other MCP tools. Most discoverable; closest literal reading of #2527. + - **One tool per server, `(uri)`** (hermes-agent): server is encoded in the tool name (`mcp_{server}_read_resource`), so the model selects the server by selecting the tool. Trades catalog tokens for unambiguity. Pairs with `mcp_{server}_list_resources` so the model has a per-server discovery affordance. - **FS-provider indirection via namespaced URIs** (VS Code): no MCP-specific tool. `mcp-resource://` URIs are registered with the file service; generic `readFile` / `listDirectory` tools transparently reach `resources/read`. Costs nothing in tool-count budget; loses `list` affordance. -- **Signature mismatch is a portability hazard.** A skill that references `skill://code-review/checklist.json` resolves differently across hosts depending on whether the host disambiguates by server. **The spec should probably nudge implementations toward `(server, uri)` or per-server tool naming.** -- **Adapter libraries** for several "no" rows. **`mcpadapt`** blocks both **smolagents** *and* **crewAI** (via `crewai-tools`). **`langchain-mcp-adapters`** blocks **deepagents**. Three "no" rows collapse to two upstream changes. -- **Internal SDK without LLM-tool exposure** (mastra) is its own pattern: the resource RPC is wired in the SDK but not bridged to the model. Closing this gap is typically smaller-scope than wiring the RPC from scratch. + + Reliability implication: each pattern enforces server identity differently — explicit parameter (`(server, uri)`), tool choice (per-server tool), or URI authority (`mcp-resource:///...`). **The spec should nudge implementations to keep server identity mandatory** so a skill always resolves to its owning server. Otherwise the host has to probe every connected server when the model omits it — either silently picking the wrong one, or iterating through all of them at the cost of latency and tokens. +- **Adapter libraries block two "no" rows.** **crewAI** depends on [`mcpadapt`](https://github.com/grll/mcpadapt); **deepagents** depends on [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters). Both adapters are tools-only — the unlock for either client lives in the adapter, not the client repo. +- **Internal SDK without LLM-tool exposure** (mastra, strands-agents) is its own pattern: the resource RPC is wired in the SDK but not bridged to the model. Closing this gap is typically smaller-scope than wiring the RPC from scratch. From 10d817fa8a1054aefef0e87c8daed14e028ffc9f Mon Sep 17 00:00:00 2001 From: olaservo Date: Sun, 24 May 2026 13:07:09 -0700 Subject: [PATCH 07/12] docs: verify remaining first-pass clients, flip cline/Roo-Code to Yes Verified adk-python, agent-framework, crewAI, mastra, cline, Roo-Code against local source clones. Two corrections to prior state: - cline and Roo-Code both expose access_mcp_resource(server, uri) as a model-facing tool via McpHub.readResource. Flipped from No to Yes. - adk-python's load_mcp_resource takes resource_names: array[string] in a single call (not two-shot); opt-in via use_mcp_resources flag. Headline count updated from six to eight of fourteen open-source clients satisfying #2527. Cross-cutting observations and takeaways adjusted for the new (server, uri) family members and the four-pattern signature breakdown. Trust-model list extended. --- docs/client-mcp-support.md | 124 ++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 58 deletions(-) diff --git a/docs/client-mcp-support.md b/docs/client-mcp-support.md index 12be59f..e643702 100644 --- a/docs/client-mcp-support.md +++ b/docs/client-mcp-support.md @@ -2,7 +2,7 @@ > **Scope.** This page tracks two related areas of client support: > -> 1. **Model-facing MCP resource loading** — does the client expose a tool that lets the model read MCP resources by URI? This is the SHOULD proposed in [modelcontextprotocol/modelcontextprotocol#2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527) and is verifiable today. The bulk of this page is this survey. +> 1. **Model-facing MCP resource loading** — does the client expose a tool that lets the model trigger an MCP `resources/read`? This is the SHOULD proposed in [modelcontextprotocol/modelcontextprotocol#2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527) (which phrases it as "by URI"); for survey purposes we also count by-name variants where the framework resolves a model-supplied name to a URI before calling `resources/read` (adk-python is the one such case found). The bulk of this page is this survey. > 2. **SEP-2640 skills extension support** — once [SEP-2640](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640) finalizes, this page will also track which clients implement the extension. SEP-2640-related issues and PRs are tracked per-client in the "Open issues/PRs to watch" column rather than via a separate status field. > > **Why these are tracked together.** SEP-2640 layers skills on top of MCP resources. If a host's progressive-disclosure flow involves the model itself loading L2/L3 skill content from `skill://…` or related resource URIs, then the resource-read affordance for the model becomes critical for skills. A client's resource-loading shape today is a strong predictor of how it'll fit SEP-2640 tomorrow. @@ -22,28 +22,28 @@ Category values: **Framework** = SDK/library you build agents on top of · **CLI | **vscode** (GitHub Copilot) | IDE | Yes (FS-provider indirection) | `copilot_readFile`, `copilot_listDirectory` (general-purpose, not MCP-specific) | `(path)` — accepts `mcp-resource://…` URIs as paths; the FS provider routes to MCP RPC | Yes — `mcp-resource://` URIs route via `IFileService` → `McpResourceFilesystem` provider → `r.readResource(...)` MCP RPC ([`mcpResourceFilesystem.ts`](https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.ts)) | Server must advertise `McpCapability.Resources`; model needs a URI to pass (typically obtained from user attachment or from an MCP tool's `resource_link` response) | No explicit doc, but mechanism is operational. [Connor Peet's comment on #2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527#issuecomment-4282395437) is the clearest write-up | _none yet — add as found_ | | **opencode** | CLI | No | — (internal `readResource` only) | — | Internal only — `readResource()` exists in [`packages/opencode/src/mcp/index.ts`](https://github.com/anomalyco/opencode/blob/main/packages/opencode/src/mcp/index.ts) but is invoked only when the user attaches a resource via file picker; `mcp.tools()` in `prompt.ts` forwards MCP *tools* but never a resource-read tool | n/a | Docs (`mcp-servers.mdx`) advertise tool forwarding only | _none yet — add as found_ | | **deepagents** (LangChain) | Framework | No | — | — | n/a — delegates MCP wiring to [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters) via `load_mcp_tools()` (in [`mcp_tools.py`](https://github.com/langchain-ai/deepagents/blob/main/src/deepagents/mcp_tools.py)); that adapter only converts MCP tools, not resources | n/a | No mention in README | **Upstream-blocked**: needs a change in `langchain-mcp-adapters` (or a deepagents wrapper around `client.read_resource()`) | -| **strands-agents** (AWS) | Framework | No (internal SDK only) | — | — | Internal only — `MCPClient.read_resource_sync()` and `list_resources_sync()` in [`mcp_client.py`](https://github.com/strands-agents/sdk-python/blob/main/src/strands/tools/mcp/mcp_client.py) call MCP `resources/read` / `resources/list`, but `MCPAgentTool` (the only adapter) wraps `mcp.types.Tool` only and `MCPClient.load_tools()` (the `ToolProvider` interface) returns tools only | n/a | _unknown — verify_ | _none yet — add as found_ | +| **strands-agents** (AWS) | Framework | No (internal SDK only) | — | — | Internal only — `MCPClient.read_resource_sync()` and `list_resources_sync()` in [`mcp_client.py`](https://github.com/strands-agents/sdk-python/blob/main/src/strands/tools/mcp/mcp_client.py) call MCP `resources/read` / `resources/list`, but `MCPAgentTool` (the only adapter) wraps `mcp.types.Tool` only and `MCPClient.load_tools()` (the `ToolProvider` interface) returns tools only | n/a | No — `docs/MCP_CLIENT_ARCHITECTURE.md` and `AGENTS.md` do not mention MCP resources | _none yet — add as found_ | | **Claude Code** (closed source, reference) | CLI | Yes | `ReadMcpResourceTool` | `(server, uri)` per [public docs](https://code.claude.com/docs/en/tools-reference) | Documented; source not verifiable | n/a | Yes — public tools reference page | n/a | -| **adk-python** (Google ADK) | Framework | Yes _(unverified — first pass below)_ | `load_mcp_resource` | Two-shot — discovers resources first, then takes a `resource_name` to read | Yes — `MCPToolset.read_resource()` calls `session.read_resource(uri)` ([`mcp_toolset.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/mcp_tool/mcp_toolset.py)) | Toolset must be configured with at least one MCP server | _unknown — verify_ | _none yet — add as found_ | +| **adk-python** (Google ADK) | Framework | Yes (by name, not URI) | `load_mcp_resource` | `(resource_names: array[string])` — model passes catalog names; framework resolves each to a URI and calls `session.read_resource(uri=…)`. The catalog is injected into the model's context by `_append_resources_to_llm_request()` rather than via a separate list call | Yes — `McpToolset.read_resource()` calls `session.read_resource(uri=…)` ([`mcp_toolset.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/mcp_tool/mcp_toolset.py)) | Opt-in via `use_mcp_resources=True` on `McpToolset` (default `False`) | No — no user-facing docs found | _none yet — add as found_ | | **agent-framework** (Microsoft) | Framework | No (tools-only client bridge) | — | — | n/a — `MCPTool` / `MCPStdioTool` / `MCPStreamableHTTPTool` / `MCPWebsocketTool` in [`_mcp.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/_mcp.py) materialize MCP *tools* into the agent's tool registry; no `read_resource` callsite found in client code (only in a test) | n/a | Samples cover MCP tool integration only | _none yet — add as found_ | -| **cline** | IDE | No | — | — | n/a — depends on `@modelcontextprotocol/sdk` for MCP, but zero matches for `resources/read` / `readResource` / `read_resource` in source. Tools-only bridge | n/a | MCP docs cover tools and config only | _none yet — add as found_ | +| **cline** | IDE | Yes | `access_mcp_resource` | `(server_name, uri)` | Yes — [`McpHub.readResource(serverName, uri)`](https://github.com/cline/cline/blob/main/src/services/mcp/McpHub.ts) calls `resources/read`; invoked from [`AccessMcpResourceHandler`](https://github.com/cline/cline/blob/main/src/core/task/tools/handlers/AccessMcpResourceHandler.ts) | Server's `resources` capability surfaces in system prompt context via the [`mcp.ts` formatter](https://github.com/cline/cline/blob/main/src/core/prompts/system-prompt/components/mcp.ts) | No dedicated user-facing docs found | _none yet — add as found_ | | **crewAI** | Framework | No | — | — | n/a — `crewai-tools` MCP adapter ([`mcp_adapter.py`](https://github.com/crewAIInc/crewAI-tools/blob/main/crewai_tools/adapters/mcp_adapter.py)) is built on `mcpadapt` and converts MCP tools only — same upstream-blocked pattern as smolagents | n/a | MCP adapter docs cover tools only | **Upstream-blocked** by `mcpadapt` (shared with smolagents) | | **hermes-agent** (Nous Research) | CLI | Yes | `mcp_{server}_read_resource`, `mcp_{server}_list_resources` (one pair per connected server) | `(uri)` — server is encoded in the tool name | Yes — `_make_read_resource_handler()` in [`tools/mcp_tool.py`](https://github.com/NousResearch/hermes-agent/blob/main/tools/mcp_tool.py) calls `session.read_resource(uri)` and registers the tool per server | Two gates: `tools.resources` config flag (default on) AND server's advertised `capabilities.resources` | Yes — [`features/mcp.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/mcp.md) and [`guides/use-mcp-with-hermes.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/guides/use-mcp-with-hermes.md) | _none yet — add as found_ | | **mastra** | Framework | No (internal SDK only) | — | — | Internal only — [`resource.ts`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/actions/resource.ts) exposes a `read(uri)` SDK method that calls `client.readResource(uri)`, but it is **not** registered as an LLM-facing tool; the model-facing tool bridge converts MCP tools only | n/a | SDK docs cover the action; no LLM-tool exposure | _none yet — add as found_ | -| **Roo-Code** | IDE | No | — | — | n/a — [`McpHub.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) imports `ReadResourceResultSchema` from the SDK but does not register a model-facing resource-read tool; the MCP hub maps tools only | n/a | _unknown — verify_ | _none yet — add as found_ | +| **Roo-Code** | IDE | Yes | `access_mcp_resource` | `(server_name, uri)` | Yes — [`McpHub.readResource(serverName, uri, source?)`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) called from [`accessMcpResourceTool.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/core/tools/accessMcpResourceTool.ts) | `access_mcp_resource` is a member of the `mcp` tool group; server must advertise `resources` capability | Yes — [`access-mcp-resource.md`](https://github.com/RooCodeInc/Roo-Code/blob/main/apps/docs/docs/advanced-usage/available-tools/access-mcp-resource.md) | _none yet — add as found_ | ## Cross-cutting observations 1. **Three implementation patterns for model-facing MCP resource access.** - 1. **Dedicated MCP resource tools** — Codex, Goose, Claude Code: explicit `read_mcp_resource` / `read_resource` (+ optional `list_*`) registered alongside other MCP tools. Most discoverable by the model; closest literal reading of #2527. + 1. **Dedicated MCP resource tools** — Codex, Goose, Claude Code, Cline, Roo-Code: explicit `read_mcp_resource` / `read_resource` / `access_mcp_resource` (+ optional `list_*`) registered alongside other MCP tools. Most discoverable by the model; closest literal reading of #2527. adk-python is a near-relative — its `load_mcp_resource` takes a batch of `resource_names` in one call rather than a single URI, but the affordance shape is the same. 2. **Multiplexed resource tool** — fast-agent: one `get_resource` tool handles both bundled (`internal://`) and MCP URIs behind a single name. Simpler surface for the model; relies on URI scheme to disambiguate. 3. **FS-provider indirection via namespaced URIs** — VS Code: no MCP-specific tool. A dedicated URI scheme (`mcp-resource://`) is registered with the filesystem service so the generic `readFile` / `listDirectory` tools transparently reach MCP `resources/read`. Reuses the agent's existing file-reading affordance; costs nothing in tool-count budget. Downside: no `list` equivalent — the model can only read URIs it's been handed. -2. **Dedicated-tool implementers converge on `(server, uri)`.** Codex, Goose, fast-agent, and Claude Code all take an explicit server identifier alongside the URI. hermes-agent is the remaining variant in pattern (1)'s family: it encodes server-in-tool-name (one tool per server) and takes only `(uri)`. +2. **Dedicated-tool implementers converge on `(server, uri)`.** Codex, Goose, fast-agent, Claude Code, Cline, and Roo-Code all take an explicit server identifier alongside the URI. hermes-agent is the remaining variant in pattern (1)'s family: it encodes server-in-tool-name (one tool per server) and takes only `(uri)`. adk-python is the outlier — it takes `(resource_names: array[string])` and resolves URIs via a model-visible catalog injected into context. -3. **Trust models diverge.** Per-server enablement (Goose), unconditional-when-MCP-configured (Codex), or capability-gated FS provider (VS Code). For skills-over-MCP this matters because the "who can read what" boundary is currently set by each host individually — a portable skill that depends on `resources/read` will work or not based on whether the host considers MCP resource access a model-grade affordance. +3. **Trust models diverge.** Per-server enablement (Goose), unconditional-when-MCP-configured (Codex), capability-gated FS provider (VS Code), capability-gated dedicated tool (Cline, Roo-Code), or framework opt-in flag (adk-python, `use_mcp_resources=True`, default off). For skills-over-MCP this matters because the "who can read what" boundary is currently set by each host individually — a portable skill that depends on `resources/read` will work or not based on whether the host considers MCP resource access a model-grade affordance. -4. **Discoverability differs sharply between patterns.** Pattern (1) hosts pair `read_*` with a `list_*` so the model can enumerate resources on its own. Pattern (2) (fast-agent) has `list_resources`. Pattern (3) (VS Code) has *no list equivalent* — the model can only read a URI it's been handed (user attachment → chat context, or an MCP tool returning a `resource_link`). For skills this matters: a `skill://index.json`-style enumeration model implicitly assumes the model can either *list* or be *told* what's available. Pattern (3) needs the index handed in via attachment or a dedicated tool result. +4. **Discoverability differs sharply between patterns — and within them.** Within pattern (1), discovery shapes diverge: Codex, Goose, hermes-agent (per server), and Claude Code pair `read_*` with a `list_*` tool so the model can enumerate resources on its own; Cline instead injects each server's `resources` and `resourceTemplates` into the system prompt via its `mcp.ts` formatter; adk-python injects an in-context catalog of resource names via `_append_resources_to_llm_request()`. Pattern (2) (fast-agent) has `list_resources`. Pattern (3) (VS Code) has *no list equivalent* — the model can only read a URI it's been handed (user attachment → chat context, or an MCP tool returning a `resource_link`). For skills this matters: a `skill://index.json`-style enumeration model implicitly assumes the model can either *list* or be *told* what's available. Pattern (3) needs the index handed in via attachment or a dedicated tool result. 5. **VS Code's FS-provider pattern is worth its own consideration for skills.** Because `mcp-resource://` URIs are first-class in the file service, *any* tool that takes a path argument in VS Code can transparently read MCP resources — including, in principle, a skill loader. The skills-over-MCP design could lean on this by treating `skill://server/name/SKILL.md` as just another URI scheme registered with the host's file abstraction. This is closer to a registry-style integration (cf. how VS Code surfaces skills via `ChatSessionCustomizationProvider` rather than as system-prompt content). @@ -51,8 +51,7 @@ Category values: **Framework** = SDK/library you build agents on top of · **CLI ### Agent SDKs / frameworks -#### fast-agent _(verified)_ - +#### fast-agent Verified at commit [`502d32e`](https://github.com/evalstate/fast-agent/commit/502d32e266f3221d744977f38b7a9b4bc5b93947). - **Model-facing tool:** `get_resource` registered in [`smart_agent.py`](https://github.com/evalstate/fast-agent/blob/main/src/fast_agent/agents/smart_agent.py) via `agent.add_tool(...)`. The dispatcher in the same file routes `internal://` to bundled resources; everything else hits the connected MCP server via `agent.get_resource(uri, namespace=server_name)` → MCP `resources/read`. @@ -60,33 +59,38 @@ Verified at commit [`502d32e`](https://github.com/evalstate/fast-agent/commit/50 --- -#### adk-python (Google ADK) _(first pass — verify before citing)_ +#### adk-python (Google ADK) +Verified at commit [`7ad7994`](https://github.com/google/adk-python/commit/7ad7994744de18f2394e4bcb961cd5c7a24afb4b) (2026-05-22). -- **MCP integration:** [`src/google/adk/tools/mcp_tool/`](https://github.com/google/adk-python/tree/main/src/google/adk/tools/mcp_tool) package — `MCPToolset` is the entry point used by callers to connect an ADK agent to an MCP server. -- **Resource RPC wired:** [`mcp_toolset.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/mcp_tool/mcp_toolset.py) exposes `async def read_resource()` which calls `session.read_resource(uri)`. -- **Model-facing tool:** [`load_mcp_resource_tool.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/mcp_tool/load_mcp_resource_tool.py) defines `load_mcp_resource`. Per the first-pass scan, the tool is two-shot — first invocation lists resources, then the model picks a `resource_name` for the second call. **Verify the exact schema and confirm it's registered alongside the other ADK tools the agent sees.** -- **Why interesting:** ADK is one of two clients in the gap (with hermes-agent) that may already satisfy #2527 — and it's also the client with the most rigorous skill validation in the parallel skills survey, so this is where the spec extension and the resource-tool extension converge. +- **MCP integration:** [`src/google/adk/tools/mcp_tool/`](https://github.com/google/adk-python/tree/main/src/google/adk/tools/mcp_tool) package — `McpToolset` (lowercase c; `MCPToolset` is a deprecated alias) is the entry point used by callers to connect an ADK agent to an MCP server. +- **Resource RPC wired:** [`mcp_toolset.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/mcp_tool/mcp_toolset.py) exposes `async def read_resource(self, name, readonly_context=None)` (line 380) which calls `session.read_resource(uri=resource_info["uri"])` (line 397). +- **Model-facing tool:** [`load_mcp_resource_tool.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/load_mcp_resource_tool.py) defines `load_mcp_resource`. **Not two-shot** — the tool's input schema is `resource_names: array[string]` (one call returns the contents of N resources). The catalog of available resources is exposed to the model via `_append_resources_to_llm_request()` injecting it into the LLM context, rather than via a separate `list` tool. +- **Enablement:** opt-in via the `use_mcp_resources=True` constructor flag on `McpToolset` (default `False`). When set, `get_tools()` (line 372) appends `LoadMcpResourceTool` to the toolset alongside the dynamically discovered MCP tools. +- **End-user docs:** none found in `README.md` or the docs folder — the affordance is undocumented for end users despite being implemented. +- **Why interesting:** ADK is the client with the most rigorous skill validation in the parallel skills survey, so this is where the spec extension and the resource-tool extension converge. The batch `resource_names` shape is a distinct fourth signature among dedicated-tool implementers. --- -#### agent-framework (Microsoft) _(first pass — verify before citing)_ +#### agent-framework (Microsoft) +Verified at commit [`793403f`](https://github.com/microsoft/agent-framework/commit/793403f3db3c44463eb4e9bb8ad95af0a027f906) (2026-05-22). -- **MCP integration:** Multi-transport client tools (`MCPTool` + Stdio/HTTP/Websocket variants) in [`_mcp.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/_mcp.py), with .NET equivalents under [`dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Models/`](https://github.com/microsoft/agent-framework/tree/main/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Models). Tools-only bridge; zero `read_resource` callsites in source (only in tests). -- **Why on the list:** dual-stack Python/.NET framework with rich skills metadata in the parallel skills survey. The asymmetry — skills support without resource-tool support — is the kind of gap a #2527-aligned PR would close. +- **MCP integration:** Multi-transport client tools — `MCPTool` (line 180) plus `MCPStdioTool` (1463), `MCPStreamableHTTPTool` (1598), `MCPWebsocketTool` (1775) in [`_mcp.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/_mcp.py). The client-facing methods are `load_tools()`, `call_tool()`, `load_prompts()`, `get_prompt()` — no resource methods. .NET equivalents (e.g. `DefaultMcpToolHandler`) under [`dotnet/src/`](https://github.com/microsoft/agent-framework/tree/main/dotnet/src) expose `InvokeToolAsync()` only. +- **Resource RPC wired:** No MCP resource RPC. The only production `read_resource` callsite in the repo is in [`_skills.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/_skills.py) (lines 2090–2112) and refers to **skill** resources, not MCP `resources/read`. All MCP `resources/read` references are confined to `tests/core/test_skills.py`. +- **Why on the list:** dual-stack Python/.NET framework with rich skills metadata in the parallel skills survey. The asymmetry — skills support without MCP resource-tool support — is the kind of gap a #2527-aligned PR would close. --- -#### crewAI _(first pass — verify before citing)_ +#### crewAI +Verified at commit [`c3e2001`](https://github.com/crewAIInc/crewAI/commit/c3e2001d524164739bbc17cdb25bd77bf6af6eaa) (2026-05-23) of the main `crewAI` repo, which vendors `crewai-tools` under `lib/crewai-tools/`. -- **MCP integration:** [`mcp_adapter.py`](https://github.com/crewAIInc/crewAI-tools/blob/main/crewai_tools/adapters/mcp_adapter.py) imports `mcp` + `mcpadapt.core` and converts MCP tools to CrewAI `BaseTool` objects. -- **Resource RPC wired:** No — adapter handles only `Tool` types. +- **MCP integration:** [`mcp_adapter.py`](https://github.com/crewAIInc/crewAI-tools/blob/main/crewai_tools/adapters/mcp_adapter.py) imports `mcp` (`StdioServerParameters`, `CallToolResult`, `TextContent`, `Tool`) and `mcpadapt.core` (`MCPAdapt`, `ToolAdapter`); `CrewAIToolAdapter.adapt(func, mcp_tool: Tool)` converts MCP tools to CrewAI `BaseTool` objects. +- **Resource RPC wired:** No — `adapt()` is typed to accept only `mcp_tool: Tool`; zero matches for `resource`/`Resource` anywhere in the adapter file or directory. `_run()` extracts `CallToolResult` content only. - **Model-facing tool:** None. -- **Why on the list:** Same upstream block as **smolagents** — both depend on [`mcpadapt`](https://github.com/grll/mcpadapt), which is tools-only. A single upstream change in `mcpadapt` flips both clients. This is the highest-leverage adapter-library target identified so far. +- **Why on the list:** Same upstream block as **smolagents** — both depend on [`mcpadapt`](https://github.com/grll/mcpadapt) (`mcpadapt>=0.1.9` declared as optional dep in `lib/crewai-tools/pyproject.toml`), which is tools-only. A single upstream change in `mcpadapt` flips both clients. This is the highest-leverage adapter-library target identified so far. --- -#### deepagents (LangChain) _(verified)_ - +#### deepagents (LangChain) Verified at commit [`a64ff43`](https://github.com/langchain-ai/deepagents/commit/a64ff430f14b76607dfb1d78234f928ed88a3af0). - **MCP wiring is outsourced** to `langchain_mcp_adapters.tools.load_mcp_tools()` (called from [`mcp_tools.py`](https://github.com/langchain-ai/deepagents/blob/main/src/deepagents/mcp_tools.py)). The upstream adapter does not expose `resources/read` as a tool — zero hits for resource-read in deepagents source. @@ -94,17 +98,17 @@ Verified at commit [`a64ff43`](https://github.com/langchain-ai/deepagents/commit --- -#### mastra _(first pass — verify before citing)_ +#### mastra +Verified at commit [`59b20e7`](https://github.com/mastra-ai/mastra/commit/59b20e759fa039370f7e1859b9e06726fe143cc3) (2026-05-23). -- **MCP integration:** [`packages/mcp/src/client/`](https://github.com/mastra-ai/mastra/tree/main/packages/mcp/src/client) imports `@modelcontextprotocol/sdk`. [`resource.ts`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/actions/resource.ts) exposes `async read(uri)` which calls `this.client.readResource(uri)`. -- **Resource RPC wired:** Yes, but **internal SDK only**. `ResourceClientActions` is an SDK surface for callers, not registered as an LLM-facing tool. -- **Model-facing tool:** No. The model-facing tool bridge converts MCP tools only; resources require explicit code to invoke. +- **MCP integration:** [`packages/mcp/src/client/client.ts:10`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/client.ts) imports `Client` from `@modelcontextprotocol/sdk/client/index.js`. [`actions/resource.ts:130-132`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/actions/resource.ts) exposes `public async read(uri: string)` which directly returns `this.client.readResource(uri)`. +- **Resource RPC wired:** Yes, but **internal SDK only**. `ResourceClientActions` is mounted as `this.resources` on the client (`client.ts:271`) — an SDK surface for callers, not registered as an LLM-facing tool. +- **Model-facing tool:** No. The model-facing bridge is `tools()` at [`client.ts:741-743`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/client.ts) which calls `this.client.listTools()` and iterates only the returned tools array — resources are never traversed. - **Why on the list:** Mastra's skill versioning architecture (content-addressable BlobStore, draft→publish lifecycle) is the most sophisticated. Unlocking resource-read at the model boundary would be a small change relative to the rest of the framework — the SDK plumbing already exists. --- -#### strands-agents _(verified)_ - +#### strands-agents Verified at commit [`8638fc2`](https://github.com/strands-agents/sdk-python/commit/8638fc2d629e32b7b5839f4c106d5aedcdf764c9) (2026-05-04). Strands matches the **mastra pattern**: resource RPC wired in the SDK, but no model-facing tool. - **Resource RPC wired but unbridged:** `MCPClient.read_resource_sync()`, `list_resources_sync()`, and `list_resource_templates_sync()` in [`mcp_client.py`](https://github.com/strands-agents/sdk-python/blob/main/src/strands/tools/mcp/mcp_client.py) are SDK-public methods, but [`MCPAgentTool`](https://github.com/strands-agents/sdk-python/blob/main/src/strands/tools/mcp/mcp_agent_tool.py) only wraps `mcp.types.Tool` and delegates to `call_tool_async(...)`. Outside tests, nothing in the repo invokes the resource methods. @@ -114,8 +118,7 @@ Verified at commit [`8638fc2`](https://github.com/strands-agents/sdk-python/comm ### Coding agents / CLIs -#### codex (OpenAI) _(verified)_ - +#### codex (OpenAI) Verified at commit [`67849d9`](https://github.com/openai/codex/commit/67849d950d843c954102adb0db0e11f993aefdb7). - **Model-facing tools:** `read_mcp_resource`, `list_mcp_resources`, `list_mcp_resource_templates` defined at [`mcp_resource_tool.rs`](https://github.com/openai/codex/blob/main/codex-rs/tools/src/mcp_resource_tool.rs); registered unconditionally when an MCP server is configured. Handler at [`mcp_resource.rs`](https://github.com/openai/codex/blob/main/codex-rs/core/src/tools/handlers/mcp_resource.rs) → `session.read_resource()`. @@ -123,8 +126,7 @@ Verified at commit [`67849d9`](https://github.com/openai/codex/commit/67849d950d --- -#### goose (AAIF) _(verified)_ - +#### goose (AAIF) Verified at commit [`45d8bf8`](https://github.com/aaif-goose/goose/commit/45d8bf81d09d478ceedba8f6d1f0ad906123a981). - **Model-facing tools:** `read_resource`, `list_resources` registered in [`ext_manager.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/agents/platform_extensions/ext_manager.rs) when at least one extension reports `ServerCapabilities::resources`. Dispatch flows through [`extension_manager.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/agents/extension_manager.rs) → `client.read_resource(...)` → MCP `resources/read`. Documented at [`extension-manager-mcp.md`](https://github.com/block/goose/blob/main/documentation/docs/mcp/extension-manager-mcp.md). @@ -132,27 +134,25 @@ Verified at commit [`45d8bf8`](https://github.com/aaif-goose/goose/commit/45d8bf --- -#### hermes-agent (Nous Research) _(verified)_ - +#### hermes-agent (Nous Research) Verified at commit [`72ff3e9`](https://github.com/NousResearch/hermes-agent/commit/72ff3e909c73b625ee244ab5ea3d0608ee85dcf3) (2026-05-23). - **MCP integration:** Full integration in [`tools/mcp_tool.py`](https://github.com/NousResearch/hermes-agent/blob/main/tools/mcp_tool.py). - **Resource RPC wired:** Yes — `_make_read_resource_handler()` calls `await server.session.read_resource(uri)`. - **Model-facing tools:** Yes — both `mcp_{safe_name}_read_resource` (taking `uri`) and `mcp_{safe_name}_list_resources` (no parameters) registered per connected server via `_build_utility_schemas()`. Conditionally registered when the server advertises `capabilities.resources` AND the per-server `tools.resources` config flag is on (default). -- **Signature:** `(uri)` — server is encoded in the tool name (one tool per server), so the model implicitly selects the server by selecting the tool. **Distinct from every other pattern surveyed**: not `(server, uri)`, not `(uri)`-with-probing, not URI-virtualized — it's *one tool per server*. The matching `list_resources` per server gives the model a discovery affordance without cross-server probing. +- **Signature:** `(uri)` — server is encoded in the tool name (one tool per server), so the model implicitly selects the server by selecting the tool. **Distinct from every other pattern surveyed**: not `(server, uri)`, not `(resource_names: array[string])` batch, not `(uri)`-with-probing, not URI-virtualized — it's *one tool per server*. The matching `list_resources` per server gives the model a discovery affordance without cross-server probing. - **End-user docs:** [`features/mcp.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/mcp.md) and [`guides/use-mcp-with-hermes.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/guides/use-mcp-with-hermes.md) both document the utility wrappers. (Minor doc/code mismatch: the user-facing docs name the tools as bare `read_resource` / `list_resources`, but the actual model-facing names include the `mcp_{server}_` prefix.) -- **Why interesting:** With adk-python, this is the second of the seven gap-clients that already satisfies #2527. The per-server-tool naming is also a candidate disambiguation pattern for skills-over-MCP. +- **Why interesting:** The per-server-tool naming is a candidate disambiguation pattern for skills-over-MCP — the model can't pick the wrong server because each tool only binds to one. --- #### Claude Code (closed source — reference only) -Claude Code is closed source so we cannot verify the loader, but the [public tools reference](https://code.claude.com/docs/en/tools-reference) documents `ReadMcpResourceTool` accepting `server` and `uri` parameters. Listed here as a reference data point for the `(server, uri)` signature shape also adopted by Codex and fast-agent. +Claude Code is closed source so we cannot verify the loader, but the [public tools reference](https://code.claude.com/docs/en/tools-reference) documents `ReadMcpResourceTool` accepting `server` and `uri` parameters. Listed here as a reference data point for the `(server, uri)` signature shape also adopted by Codex, Goose, fast-agent, Cline, and Roo-Code. --- -#### opencode _(verified)_ - +#### opencode Verified at commit [`ce89bcb`](https://github.com/anomalyco/opencode/commit/ce89bcb8e238401ea8fee000dc54539057d47dc4). - **Tools forwarded to the model** in [`packages/opencode/src/mcp/index.ts`](https://github.com/anomalyco/opencode/blob/main/packages/opencode/src/mcp/index.ts) via `client.callTool()`; tool naming convention `{server_name}:{tool_name}`. @@ -162,8 +162,7 @@ Verified at commit [`ce89bcb`](https://github.com/anomalyco/opencode/commit/ce89 ### IDE extensions -#### vscode (GitHub Copilot) _(verified)_ - +#### vscode (GitHub Copilot) Verified at commits [`530cb5d`](https://github.com/microsoft/vscode/commit/530cb5de713aec2e96059e2f6cf41a95403cdb3d) (vscode core) and [`9e668cb`](https://github.com/microsoft/vscode-copilot-chat/commit/9e668cb12144c701cf0f2c6b3458c00fe3da20f1) (Copilot Chat extension). VS Code is the unique pattern here: no MCP-specific tool — generic `copilot_readFile` / `copilot_listDirectory` tools transparently reach MCP servers via filesystem-provider indirection on a custom URI scheme. - **URI scheme + FS provider:** [`McpResourceURI`](https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/mcp/common/mcpTypes.ts) defines `mcp-resource://` URIs that encode the MCP server's definition ID in the authority — self-routing. [`McpResourceFilesystem`](https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.ts) is registered for that scheme; `_readURIInner` decodes the URI, looks up the `McpServer`, and calls `r.readResource(...)` — the MCP `resources/read` RPC. Capability-gated on `McpCapability.Resources`. @@ -172,30 +171,39 @@ Verified at commits [`530cb5d`](https://github.com/microsoft/vscode/commit/530cb --- -#### cline _(first pass — verify before citing)_ +#### cline -- **MCP integration:** Depends on `@modelcontextprotocol/sdk` per `package.json`; MCP server config + UI surfaced in the IDE. -- **Resource RPC wired:** No callsite found — zero matches for `resources/read` / `readResource` / `read_resource` in source. -- **Model-facing tool:** None. The MCP integration is currently tools + UI configuration; resources aren't reached. -- **Why on the list:** Cline has the most extensive skills implementation in the parallel survey (incl. the admin-locked enterprise `globalSkills` primitive), so the absence of resource-read is a notable asymmetry. Worth a careful re-check given the SDK is already wired. +Verified at commit [`8a6441f`](https://github.com/cline/cline/commit/8a6441fddd3b4d372d086886ebe4ee11e78dc993) (2026-05-22). + +- **MCP integration:** Depends on `@modelcontextprotocol/sdk` `^1.25.1` per `package.json:504`. +- **Resource RPC wired:** Yes. [`McpHub.readResource(serverName, uri)`](https://github.com/cline/cline/blob/main/src/services/mcp/McpHub.ts) (lines 1174–1192) issues a raw `resources/read` request against the named connection's client and decodes with `ReadResourceResultSchema`. +- **Model-facing tool:** Yes. [`AccessMcpResourceHandler`](https://github.com/cline/cline/blob/main/src/core/task/tools/handlers/AccessMcpResourceHandler.ts) (line 145) calls `mcpHub.readResource(...)` from the model-tool execution pipeline. The model sees `access_mcp_resource` as a registered tool taking `(server_name, uri)`. +- **Discoverability:** The [system-prompt formatter](https://github.com/cline/cline/blob/main/src/core/prompts/system-prompt/components/mcp.ts) (`mcp.ts:56–102`) enumerates each connected server's `resources` (line 72–74) and `resourceTemplates` (line 68–70) in `formatMcpServersList()`. Populated by `fetchResourcesList()` and `fetchResourceTemplatesList()` in `McpHub.ts:658, 713–730`. +- **End-user docs:** none found in `README.md`; no `docs/` directory in the repo root. +- **Why interesting:** Cline has the most extensive skills implementation in the parallel survey (incl. the admin-locked enterprise `globalSkills` primitive), so the *presence* of full resource-read support, in-prompt enumeration, and dedicated handler is the natural complement. --- -#### Roo-Code _(first pass — verify before citing)_ +#### Roo-Code + +Verified at commit [`b867ec9`](https://github.com/RooCodeInc/Roo-Code/commit/b867ec9145750d0ae1ff7f02d35406e9bf2a0b16) (2026-05-15). -- **MCP integration:** [`McpHub.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) imports from `@modelcontextprotocol/sdk/types.js`, including `ReadResourceResultSchema`. -- **Resource RPC wired:** Schema imports suggest the capability is reachable, but no explicit `readResource` handler was found in `McpHub` on first pass; the hub maps tools only (the observed pattern is `tools = (response?.tools).map(...)`). -- **Model-facing tool:** No. -- **Why on the list:** Roo-Code has both a skills implementation and an MCP hub, and the SDK type imports indicate someone *intended* to surface resources at some point. Worth a thorough read of `McpHub.ts` to confirm whether resources are partially implemented or simply unused. +- **MCP integration:** [`McpHub.ts:15`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) imports `ReadResourceResultSchema` from `@modelcontextprotocol/sdk/types.js`. +- **Resource RPC wired:** Yes. [`McpHub.readResource(serverName, uri, source?)`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) (lines 1711–1728) finds the named connection and issues `client.request({ method: "resources/read", params: { uri } }, ReadResourceResultSchema)`. The optional `source: "global" | "project"` disambiguates same-named servers from different scopes. +- **Model-facing tool:** Yes. [`accessMcpResourceTool.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/core/tools/accessMcpResourceTool.ts) (line 53) calls `McpHub.readResource(...)`. `access_mcp_resource` is registered in the `mcp` tool group in `src/shared/tools.ts` alongside `use_mcp_tool`. +- **Tools-vs-resources mapping:** Tools are dynamically mapped per-server via `tools = (response?.tools || []).map(...)` at `McpHub.ts:1027` (`fetchToolsList`). Resources are *not* mapped to per-resource tools — they remain data, accessed through the single dedicated `access_mcp_resource` tool. +- **End-user docs:** Yes — [`access-mcp-resource.md`](https://github.com/RooCodeInc/Roo-Code/blob/main/apps/docs/docs/advanced-usage/available-tools/access-mcp-resource.md) is a dedicated user-facing guide. +- **Why interesting:** Roo-Code has both a skills implementation and an MCP hub, and also ships explicit user-facing documentation for the resource affordance — joining hermes-agent and Goose as the third client to document this for end users. ## Takeaways for SEP-2640 (skills extension) -- **Likely six of fourteen open-source clients surveyed** (Codex, Goose, fast-agent, VS Code, hermes-agent — verified — plus adk-python on first-pass evidence pending verification) satisfy #2527's SHOULD; closed-source Claude Code's public docs confirm it does too. Goose and hermes-agent also satisfy the implicit expectation that this be documented for end users. -- **Three implementation patterns** for model-facing MCP resource access — all support the layering Peter sketches in his #2640 comment, but with different costs: - - **Dedicated tools, `(server, uri)`** (Codex, Goose, Claude Code, fast-agent — fast-agent is also multiplexed across `internal://`): explicit `read_resource` registered alongside other MCP tools. Most discoverable; closest literal reading of #2527. +- **Eight of fourteen open-source clients surveyed** (Codex, Goose, fast-agent, VS Code, hermes-agent, adk-python, Cline, Roo-Code) satisfy #2527's SHOULD; closed-source Claude Code's public docs confirm it does too. Goose, hermes-agent, and Roo-Code also satisfy the implicit expectation that this be documented for end users; the other implementers ship the affordance with no user-facing documentation. +- **Four implementation patterns** for model-facing MCP resource access — all support the layering Peter sketches in his #2640 comment, but with different costs: + - **Dedicated tools, `(server, uri)`** (Codex, Goose, Claude Code, fast-agent, Cline, Roo-Code — fast-agent is also multiplexed across `internal://`): explicit `read_resource` / `access_mcp_resource` registered alongside other MCP tools. Most discoverable; closest literal reading of #2527. By volume, this is the dominant pattern. + - **Dedicated tool, `(resource_names: array[string])`** (adk-python): batch read; the available resources are surfaced to the model via context injection rather than a separate list tool. Same affordance shape as the `(server, uri)` family but with the server identifier embedded in the catalogued resource name rather than passed as a parameter. - **One tool per server, `(uri)`** (hermes-agent): server is encoded in the tool name (`mcp_{server}_read_resource`), so the model selects the server by selecting the tool. Trades catalog tokens for unambiguity. Pairs with `mcp_{server}_list_resources` so the model has a per-server discovery affordance. - **FS-provider indirection via namespaced URIs** (VS Code): no MCP-specific tool. `mcp-resource://` URIs are registered with the file service; generic `readFile` / `listDirectory` tools transparently reach `resources/read`. Costs nothing in tool-count budget; loses `list` affordance. - Reliability implication: each pattern enforces server identity differently — explicit parameter (`(server, uri)`), tool choice (per-server tool), or URI authority (`mcp-resource:///...`). **The spec should nudge implementations to keep server identity mandatory** so a skill always resolves to its owning server. Otherwise the host has to probe every connected server when the model omits it — either silently picking the wrong one, or iterating through all of them at the cost of latency and tokens. + Reliability implication: each pattern enforces server identity differently — explicit parameter (`(server, uri)`), tool choice (per-server tool), catalog-name lookup (adk-python), or URI authority (`mcp-resource:///...`). **The spec should nudge implementations to keep server identity mandatory** so a skill always resolves to its owning server. Otherwise the host has to probe every connected server when the model omits it — either silently picking the wrong one, or iterating through all of them at the cost of latency and tokens. - **Adapter libraries block two "no" rows.** **crewAI** depends on [`mcpadapt`](https://github.com/grll/mcpadapt); **deepagents** depends on [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters). Both adapters are tools-only — the unlock for either client lives in the adapter, not the client repo. - **Internal SDK without LLM-tool exposure** (mastra, strands-agents) is its own pattern: the resource RPC is wired in the SDK but not bridged to the model. Closing this gap is typically smaller-scope than wiring the RPC from scratch. From 990fb87c8bbbae02ed8819c61423984eed62750e Mon Sep 17 00:00:00 2001 From: olaservo Date: Tue, 26 May 2026 18:48:08 -0700 Subject: [PATCH 08/12] docs: add Figma and Adobe MCP as SEP-2640 testing candidates --- docs/skills-extension-candidates.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/skills-extension-candidates.md b/docs/skills-extension-candidates.md index c5b966d..f137124 100644 --- a/docs/skills-extension-candidates.md +++ b/docs/skills-extension-candidates.md @@ -16,4 +16,6 @@ A tracker of MCP servers, dev tools, SDKs, and skills repositories that are cand | Hugging Face skills library | [huggingface/skills](https://github.com/huggingface/skills) | Hugging Face | _none yet_ | 13 SKILL.md skills paired with `hf-mcp-server` via Cursor `.mcp.json`; distributed outside MCP today | | github-mcp-server | [github/github-mcp-server](https://github.com/github/github-mcp-server) | GitHub | [#2428](https://github.com/github/github-mcp-server/pull/2428) (WIP demo, not for merge) | SEP-2640 demo branch | | Azure Skills Plugin | [microsoft/azure-skills](https://github.com/microsoft/azure-skills) | Microsoft | _none yet_ | 25 Azure SKILL.md skills bundled with [Azure MCP Server](https://github.com/microsoft/mcp/tree/main/servers/Azure.Mcp.Server) + Foundry MCP; distributed as a plugin, not via MCP | +| Figma MCP | _TBD_ | Figma | _none yet_ | Contact: Discord `adityamuttur` — candidate for SEP-2640 testing | +| Adobe MCP | _TBD_ | Adobe | _none yet_ | Contact: Discord `justinmathew8592` — candidate for SEP-2640 testing | From 18daaa2f0307fa714e77bfcd7a1ab985b337059c Mon Sep 17 00:00:00 2001 From: olaservo Date: Sat, 30 May 2026 20:39:33 -0700 Subject: [PATCH 09/12] docs: update FastMCP 3.0 Skills entry with detailed notes on SEP-2640 compliance --- docs/skills-extension-candidates.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/skills-extension-candidates.md b/docs/skills-extension-candidates.md index f137124..75858c9 100644 --- a/docs/skills-extension-candidates.md +++ b/docs/skills-extension-candidates.md @@ -10,12 +10,10 @@ A tracker of MCP servers, dev tools, SDKs, and skills repositories that are cand | Server | Repo | Author / Org | Issue/PR tracker | Notes | | :--- | :--- | :--- | :--- | :--- | -| FastMCP 3.0 Skills | [jlowin/fastmcp](https://github.com/jlowin/fastmcp) — [docs](https://gofastmcp.com/servers/providers/skills) | FastMCP | [#2694](https://github.com/jlowin/fastmcp/issues/2694) | Framework with its own native skills provider | +| FastMCP 3.0 Skills | [jlowin/fastmcp](https://github.com/jlowin/fastmcp) — [docs](https://gofastmcp.com/servers/providers/skills) | FastMCP | [#2694](https://github.com/jlowin/fastmcp/issues/2694) | Framework with its own native skills provider using MCP Resources; doesn't yet reflect SEP-2640 | | chrome-devtools-mcp | [ChromeDevTools/chrome-devtools-mcp](https://github.com/ChromeDevTools/chrome-devtools-mcp) | Google (ChromeDevTools) | _none yet_ | Bundles a [`skills/`](https://github.com/ChromeDevTools/chrome-devtools-mcp/tree/main/skills) folder, but requires separate install — not served via MCP | -| hf-mcp-server | [huggingface/hf-mcp-server](https://github.com/huggingface/hf-mcp-server) | Hugging Face | _none yet_ | Official HF MCP server (Hub APIs + Gradio); no skills exposure today | -| Hugging Face skills library | [huggingface/skills](https://github.com/huggingface/skills) | Hugging Face | _none yet_ | 13 SKILL.md skills paired with `hf-mcp-server` via Cursor `.mcp.json`; distributed outside MCP today | +| hf-mcp-server | [huggingface/hf-mcp-server](https://github.com/huggingface/hf-mcp-server) | Hugging Face | _none yet_ | Official HF MCP server (Hub APIs + Gradio); could serve the associated skills from [huggingface/skills](https://github.com/huggingface/skills) instead of installing separately | | github-mcp-server | [github/github-mcp-server](https://github.com/github/github-mcp-server) | GitHub | [#2428](https://github.com/github/github-mcp-server/pull/2428) (WIP demo, not for merge) | SEP-2640 demo branch | | Azure Skills Plugin | [microsoft/azure-skills](https://github.com/microsoft/azure-skills) | Microsoft | _none yet_ | 25 Azure SKILL.md skills bundled with [Azure MCP Server](https://github.com/microsoft/mcp/tree/main/servers/Azure.Mcp.Server) + Foundry MCP; distributed as a plugin, not via MCP | | Figma MCP | _TBD_ | Figma | _none yet_ | Contact: Discord `adityamuttur` — candidate for SEP-2640 testing | | Adobe MCP | _TBD_ | Adobe | _none yet_ | Contact: Discord `justinmathew8592` — candidate for SEP-2640 testing | - From 35802c6c2e2f510443c92d0de3b553a0adae2abb Mon Sep 17 00:00:00 2001 From: olaservo Date: Thu, 18 Jun 2026 07:08:54 -0700 Subject: [PATCH 10/12] docs: drop unconfirmed Cursor SEP-2640 entry, track latest SEP-2640 wire-contract PRs Remove the Cursor row + deep dive (reported WIP never confirmed). Add the in-flight PRs realigning to the 2026-06-05/06-09 SEP-2640 schema (frontmatter + archives[] index, resources/directory/read): hf-mcp-server#174, fast-agent#825, huggingface/skills#172. --- docs/client-mcp-support.md | 106 ++++++++++++++++------------ docs/skills-extension-candidates.md | 2 +- 2 files changed, 60 insertions(+), 48 deletions(-) diff --git a/docs/client-mcp-support.md b/docs/client-mcp-support.md index e643702..876b4d6 100644 --- a/docs/client-mcp-support.md +++ b/docs/client-mcp-support.md @@ -3,7 +3,7 @@ > **Scope.** This page tracks two related areas of client support: > > 1. **Model-facing MCP resource loading** — does the client expose a tool that lets the model trigger an MCP `resources/read`? This is the SHOULD proposed in [modelcontextprotocol/modelcontextprotocol#2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527) (which phrases it as "by URI"); for survey purposes we also count by-name variants where the framework resolves a model-supplied name to a URI before calling `resources/read` (adk-python is the one such case found). The bulk of this page is this survey. -> 2. **SEP-2640 skills extension support** — once [SEP-2640](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640) finalizes, this page will also track which clients implement the extension. SEP-2640-related issues and PRs are tracked per-client in the "Open issues/PRs to watch" column rather than via a separate status field. +> 2. **SEP-2640 skills extension support** — as clients ship [SEP-2640](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640) implementations, this page tracks them. **fast-agent is the first surveyed client to ship one** (registry/install scope — see its deep dive), verified live against the Hugging Face MCP server, which is the first server-side implementation we've interoperated with. SEP-2640-related issues, PRs, and shipped implementations are tracked per-client in the "Open issues/PRs to watch" column rather than via a separate status field. > > **Why these are tracked together.** SEP-2640 layers skills on top of MCP resources. If a host's progressive-disclosure flow involves the model itself loading L2/L3 skill content from `skill://…` or related resource URIs, then the resource-read affordance for the model becomes critical for skills. A client's resource-loading shape today is a strong predictor of how it'll fit SEP-2640 tomorrow. > @@ -18,15 +18,15 @@ Category values: **Framework** = SDK/library you build agents on top of · **CLI | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | **codex** (OpenAI) | CLI | Yes | `read_mcp_resource`, `list_mcp_resources`, `list_mcp_resource_templates` | `(server, uri)` — server explicitly named | Yes — handler calls `session.read_resource()` | Any MCP server is configured (`params.mcp_tools.is_some()`) | No — only the LLM-visible tool description; an internal steer tells the model to prefer `tool_search` | _none yet — add as found_ | | **goose** (Block) | CLI | Yes | `read_resource`, `list_resources` | `(extension_name, uri)` on `read_resource` — `extension_name` required; `list_resources` takes an optional `extension_name` filter | Yes — `ExtensionManager::read_resource` → `client.read_resource(...)` | ≥1 enabled extension reports `ServerCapabilities::resources` | Yes — [`extension-manager-mcp.md`](https://github.com/block/goose/blob/main/documentation/docs/mcp/extension-manager-mcp.md) | _none yet — add as found_ | -| **fast-agent** | Framework | Yes (multiplexed) | `get_resource`, `list_resources` | `(uri, server_name)` — also handles bundled `internal://` URIs through the same tool | Yes for MCP URIs — `_run_current_agent_get_resource_call` → `agent.get_resource(uri, namespace=server_name)`; `internal://` URIs short-circuit to bundled resources | Unconditional for every `SmartAgent` | Partial — `smart_prompt.md` instructs the model; design rationale in `plan/done/internal_resources.md`; no dedicated README section | _none yet — add as found_ | -| **vscode** (GitHub Copilot) | IDE | Yes (FS-provider indirection) | `copilot_readFile`, `copilot_listDirectory` (general-purpose, not MCP-specific) | `(path)` — accepts `mcp-resource://…` URIs as paths; the FS provider routes to MCP RPC | Yes — `mcp-resource://` URIs route via `IFileService` → `McpResourceFilesystem` provider → `r.readResource(...)` MCP RPC ([`mcpResourceFilesystem.ts`](https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.ts)) | Server must advertise `McpCapability.Resources`; model needs a URI to pass (typically obtained from user attachment or from an MCP tool's `resource_link` response) | No explicit doc, but mechanism is operational. [Connor Peet's comment on #2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527#issuecomment-4282395437) is the clearest write-up | _none yet — add as found_ | +| **fast-agent** | Framework | Yes (multiplexed) | `get_resource` (no model-facing `list_resources`) | `(uri, server_name)` — also handles bundled `internal://` URIs through the same tool | Yes for MCP URIs — `_run_current_agent_get_resource_call` → `agent.get_resource(uri, namespace=server_name)`; `internal://` URIs short-circuit to bundled resources | Unconditional for every `SmartAgent` | Partial — `smart_prompt.md` instructs the model; design rationale in `plan/done/internal_resources.md`; no dedicated README section | **SEP-2640 shipped** (registry/install scope) — consumes the `io.modelcontextprotocol/skills` extension to install SHA256-verified skills from `skill://index.json` ([`mcp_registry.py`](https://github.com/evalstate/fast-agent/blob/main/src/fast_agent/skills/mcp_registry.py), [`skills-over-mcp.md`](https://github.com/evalstate/fast-agent/blob/main/docs/docs/mcp/skills-over-mcp.md)); does not yet read skill resources at model runtime. Verified live against [hf-mcp-server](https://github.com/huggingface/hf-mcp-server). **Watch:** draft [#816](https://github.com/evalstate/fast-agent/pull/816) adds MCP-served skill *runtime* loading (URI-backed manifests, `SkillReader` resource reads, untrusted-content wrapping) | +| **vscode** (GitHub Copilot) | IDE | Yes (FS-provider indirection) | `copilot_readFile`, `copilot_listDirectory` (general-purpose, not MCP-specific) | `(path)` — accepts `mcp-resource://…` URIs as paths; the FS provider routes to MCP RPC | Yes — `mcp-resource://` URIs route via `IFileService` → `McpResourceFilesystem` provider → `r.readResource(...)` MCP RPC ([`mcpResourceFilesystem.ts`](https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.ts)) | Server must advertise `McpCapability.Resources`; model needs a URI to pass (typically obtained from a user attachment — the earlier Copilot Chat `resource_link`→`mcp-resource://` pre-wrap has since been removed; see deep dive) | No explicit doc, but mechanism is operational. [Connor Peet's comment on #2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527#issuecomment-4282395437) is the clearest write-up | _none yet — add as found_ | | **opencode** | CLI | No | — (internal `readResource` only) | — | Internal only — `readResource()` exists in [`packages/opencode/src/mcp/index.ts`](https://github.com/anomalyco/opencode/blob/main/packages/opencode/src/mcp/index.ts) but is invoked only when the user attaches a resource via file picker; `mcp.tools()` in `prompt.ts` forwards MCP *tools* but never a resource-read tool | n/a | Docs (`mcp-servers.mdx`) advertise tool forwarding only | _none yet — add as found_ | -| **deepagents** (LangChain) | Framework | No | — | — | n/a — delegates MCP wiring to [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters) via `load_mcp_tools()` (in [`mcp_tools.py`](https://github.com/langchain-ai/deepagents/blob/main/src/deepagents/mcp_tools.py)); that adapter only converts MCP tools, not resources | n/a | No mention in README | **Upstream-blocked**: needs a change in `langchain-mcp-adapters` (or a deepagents wrapper around `client.read_resource()`) | -| **strands-agents** (AWS) | Framework | No (internal SDK only) | — | — | Internal only — `MCPClient.read_resource_sync()` and `list_resources_sync()` in [`mcp_client.py`](https://github.com/strands-agents/sdk-python/blob/main/src/strands/tools/mcp/mcp_client.py) call MCP `resources/read` / `resources/list`, but `MCPAgentTool` (the only adapter) wraps `mcp.types.Tool` only and `MCPClient.load_tools()` (the `ToolProvider` interface) returns tools only | n/a | No — `docs/MCP_CLIENT_ARCHITECTURE.md` and `AGENTS.md` do not mention MCP resources | _none yet — add as found_ | +| **deepagents** (LangChain) | Framework | No | — | — | n/a — delegates MCP wiring to [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters) (via `convert_mcp_tool_to_langchain_tool()` / `_build_cached_mcp_tool()` in [`mcp_tools.py`](https://github.com/langchain-ai/deepagents/blob/main/libs/code/deepagents_code/mcp_tools.py)); that adapter only converts MCP tools, not resources | n/a | No mention in README | **Upstream-blocked**: needs a change in `langchain-mcp-adapters` (or a deepagents wrapper around `client.read_resource()`) | +| **strands-agents** (AWS) | Framework | No (internal SDK only) | — | — | Internal only — `MCPClient.read_resource_sync()` and `list_resources_sync()` in [`mcp_client.py`](https://github.com/strands-agents/sdk-python/blob/main/strands-py/src/strands/tools/mcp/mcp_client.py) call MCP `resources/read` / `resources/list`, but `MCPAgentTool` (the only adapter) wraps `mcp.types.Tool` only and `MCPClient.load_tools()` (the `ToolProvider` interface) returns tools only | n/a | No — `docs/MCP_CLIENT_ARCHITECTURE.md` and `AGENTS.md` do not mention MCP resources | _none yet — add as found_ | | **Claude Code** (closed source, reference) | CLI | Yes | `ReadMcpResourceTool` | `(server, uri)` per [public docs](https://code.claude.com/docs/en/tools-reference) | Documented; source not verifiable | n/a | Yes — public tools reference page | n/a | | **adk-python** (Google ADK) | Framework | Yes (by name, not URI) | `load_mcp_resource` | `(resource_names: array[string])` — model passes catalog names; framework resolves each to a URI and calls `session.read_resource(uri=…)`. The catalog is injected into the model's context by `_append_resources_to_llm_request()` rather than via a separate list call | Yes — `McpToolset.read_resource()` calls `session.read_resource(uri=…)` ([`mcp_toolset.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/mcp_tool/mcp_toolset.py)) | Opt-in via `use_mcp_resources=True` on `McpToolset` (default `False`) | No — no user-facing docs found | _none yet — add as found_ | | **agent-framework** (Microsoft) | Framework | No (tools-only client bridge) | — | — | n/a — `MCPTool` / `MCPStdioTool` / `MCPStreamableHTTPTool` / `MCPWebsocketTool` in [`_mcp.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/_mcp.py) materialize MCP *tools* into the agent's tool registry; no `read_resource` callsite found in client code (only in a test) | n/a | Samples cover MCP tool integration only | _none yet — add as found_ | -| **cline** | IDE | Yes | `access_mcp_resource` | `(server_name, uri)` | Yes — [`McpHub.readResource(serverName, uri)`](https://github.com/cline/cline/blob/main/src/services/mcp/McpHub.ts) calls `resources/read`; invoked from [`AccessMcpResourceHandler`](https://github.com/cline/cline/blob/main/src/core/task/tools/handlers/AccessMcpResourceHandler.ts) | Server's `resources` capability surfaces in system prompt context via the [`mcp.ts` formatter](https://github.com/cline/cline/blob/main/src/core/prompts/system-prompt/components/mcp.ts) | No dedicated user-facing docs found | _none yet — add as found_ | +| **cline** | IDE | Yes | `access_mcp_resource` | `(server_name, uri)` | Yes — [`McpHub.readResource(serverName, uri)`](https://github.com/cline/cline/blob/main/apps/vscode/src/services/mcp/McpHub.ts) calls `resources/read`; invoked from [`AccessMcpResourceHandler`](https://github.com/cline/cline/blob/main/apps/vscode/src/core/task/tools/handlers/AccessMcpResourceHandler.ts) | Server's `resources` capability surfaces in system prompt context via the [`mcp.ts` formatter](https://github.com/cline/cline/blob/main/apps/vscode/src/core/prompts/system-prompt/components/mcp.ts) | No dedicated user-facing docs found | _none yet — add as found_ | | **crewAI** | Framework | No | — | — | n/a — `crewai-tools` MCP adapter ([`mcp_adapter.py`](https://github.com/crewAIInc/crewAI-tools/blob/main/crewai_tools/adapters/mcp_adapter.py)) is built on `mcpadapt` and converts MCP tools only — same upstream-blocked pattern as smolagents | n/a | MCP adapter docs cover tools only | **Upstream-blocked** by `mcpadapt` (shared with smolagents) | | **hermes-agent** (Nous Research) | CLI | Yes | `mcp_{server}_read_resource`, `mcp_{server}_list_resources` (one pair per connected server) | `(uri)` — server is encoded in the tool name | Yes — `_make_read_resource_handler()` in [`tools/mcp_tool.py`](https://github.com/NousResearch/hermes-agent/blob/main/tools/mcp_tool.py) calls `session.read_resource(uri)` and registers the tool per server | Two gates: `tools.resources` config flag (default on) AND server's advertised `capabilities.resources` | Yes — [`features/mcp.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/mcp.md) and [`guides/use-mcp-with-hermes.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/guides/use-mcp-with-hermes.md) | _none yet — add as found_ | | **mastra** | Framework | No (internal SDK only) | — | — | Internal only — [`resource.ts`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/actions/resource.ts) exposes a `read(uri)` SDK method that calls `client.readResource(uri)`, but it is **not** registered as an LLM-facing tool; the model-facing tool bridge converts MCP tools only | n/a | SDK docs cover the action; no LLM-tool exposure | _none yet — add as found_ | @@ -43,7 +43,7 @@ Category values: **Framework** = SDK/library you build agents on top of · **CLI 3. **Trust models diverge.** Per-server enablement (Goose), unconditional-when-MCP-configured (Codex), capability-gated FS provider (VS Code), capability-gated dedicated tool (Cline, Roo-Code), or framework opt-in flag (adk-python, `use_mcp_resources=True`, default off). For skills-over-MCP this matters because the "who can read what" boundary is currently set by each host individually — a portable skill that depends on `resources/read` will work or not based on whether the host considers MCP resource access a model-grade affordance. -4. **Discoverability differs sharply between patterns — and within them.** Within pattern (1), discovery shapes diverge: Codex, Goose, hermes-agent (per server), and Claude Code pair `read_*` with a `list_*` tool so the model can enumerate resources on its own; Cline instead injects each server's `resources` and `resourceTemplates` into the system prompt via its `mcp.ts` formatter; adk-python injects an in-context catalog of resource names via `_append_resources_to_llm_request()`. Pattern (2) (fast-agent) has `list_resources`. Pattern (3) (VS Code) has *no list equivalent* — the model can only read a URI it's been handed (user attachment → chat context, or an MCP tool returning a `resource_link`). For skills this matters: a `skill://index.json`-style enumeration model implicitly assumes the model can either *list* or be *told* what's available. Pattern (3) needs the index handed in via attachment or a dedicated tool result. +4. **Discoverability differs sharply between patterns — and within them.** Within pattern (1), discovery shapes diverge: Codex, Goose, hermes-agent (per server), and Claude Code pair `read_*` with a `list_*` tool so the model can enumerate resources on its own; Cline instead injects each server's `resources` and `resourceTemplates` into the system prompt via its `mcp.ts` formatter; adk-python injects an in-context catalog of resource names via `_append_resources_to_llm_request()`. Pattern (2) (fast-agent) has *no* model-facing `list_resources` on current main — only the `get_resource` tool is registered (an internal `smart_list_resources` method exists but isn't exposed to the model). Pattern (3) (VS Code) has *no list equivalent* — the model can only read a URI it's been handed (user attachment → chat context, or an MCP tool returning a `resource_link`). For skills this matters: a `skill://index.json`-style enumeration model implicitly assumes the model can either *list* or be *told* what's available. Pattern (3) needs the index handed in via attachment or a dedicated tool result. 5. **VS Code's FS-provider pattern is worth its own consideration for skills.** Because `mcp-resource://` URIs are first-class in the file service, *any* tool that takes a path argument in VS Code can transparently read MCP resources — including, in principle, a skill loader. The skills-over-MCP design could lean on this by treating `skill://server/name/SKILL.md` as just another URI scheme registered with the host's file abstraction. This is closer to a registry-style integration (cf. how VS Code surfaces skills via `ChatSessionCustomizationProvider` rather than as system-prompt content). @@ -52,38 +52,49 @@ Category values: **Framework** = SDK/library you build agents on top of · **CLI ### Agent SDKs / frameworks #### fast-agent -Verified at commit [`502d32e`](https://github.com/evalstate/fast-agent/commit/502d32e266f3221d744977f38b7a9b4bc5b93947). +Verified at commit [`10a996b`](https://github.com/evalstate/fast-agent/commit/10a996b6d2be0a0daa307c3fd0d6b40096587325) (2026-06-02). -- **Model-facing tool:** `get_resource` registered in [`smart_agent.py`](https://github.com/evalstate/fast-agent/blob/main/src/fast_agent/agents/smart_agent.py) via `agent.add_tool(...)`. The dispatcher in the same file routes `internal://` to bundled resources; everything else hits the connected MCP server via `agent.get_resource(uri, namespace=server_name)` → MCP `resources/read`. +- **Model-facing tool:** `get_resource` registered in [`smart_agent.py`](https://github.com/evalstate/fast-agent/blob/main/src/fast_agent/agents/smart_agent.py) via `agent.add_tool(...)` (the three model-facing tools registered there are `smart`, `slash_command`, and `get_resource` — `smart_tool_names`). The dispatcher in the same file routes `internal://` to bundled resources; everything else hits the connected MCP server via `agent.get_resource(uri, namespace=server_name)` → MCP `resources/read`. - **Signature:** `(uri, server_name)` — multiplexed across bundled and MCP URIs by scheme. MCP behavior depends on what the model passes for `server_name`. +- **No model-facing `list_resources`:** an internal `smart_list_resources` method exists but is **not** registered via `agent.add_tool(...)`, so the model cannot enumerate resources — only read a URI it's been handed. (Earlier revisions of this page listed `list_resources` as a fast-agent tool; that is not the case on current main.) + +**SEP-2640 skills extension (shipped — registry/install scope).** Verified at commit [`10a996b`](https://github.com/evalstate/fast-agent/commit/10a996b6d2be0a0daa307c3fd0d6b40096587325). fast-agent is the first surveyed client to ship a SEP-2640 implementation. + +- **What it implements:** the *registry and installation* portion of the draft SEP, not model-facing resource loading. When a connected server advertises the `io.modelcontextprotocol/skills` extension capability (`server_supports_mcp_skills()` checks `capabilities.extensions` for the key in [`mcp_registry.py`](https://github.com/evalstate/fast-agent/blob/main/src/fast_agent/skills/mcp_registry.py)), fast-agent treats it as an MCP-backed skills registry. +- **Flow:** `/skills registry` reads `skill://index.json` (via the same `get_resource` → `resources/read` path), lists installable `skill-md` or `archive` entries that carry a valid `sha256:` digest, then downloads the artifact, verifies its SHA-256, and writes it into the normal managed skills directory. Installed skills record MCP server provenance + the verified artifact digest in sidecar metadata; `/skills update` can compare digests and apply a verified update. +- **Hardening:** rejects `file://` URLs, enforces index/SKILL.md/archive size caps, and extracts archives with path-traversal and symlink guards (`_validate_archive_name`, `filter="data"`). +- **Explicit non-goals (current scope):** does **not** expose MCP-served skill resources directly to the model, and active skills do **not** read supporting files from the MCP server at runtime — that deeper resource-loading workflow is in flight in draft [PR #816](https://github.com/evalstate/fast-agent/pull/816) ("Add MCP-served skill runtime support": URI-backed skill manifests, MCP resource loading via `SkillReader`, untrusted-content wrapping, template resolution, enable/disable), stacked on the now-merged registry/install PR. So today this is a distinct affordance from the model-facing `get_resource` tool surveyed above: the SEP-2640 path is host-driven install, not a model tool call. +- **In flight:** draft [PR #825](https://github.com/evalstate/fast-agent/pull/825) realigns to the current SEP-2640 wire contract (new `frontmatter` + per-skill `archives[]` index schema; adds `resources/directory/read`), verified against [hf-mcp-server#174](https://github.com/huggingface/hf-mcp-server/pull/174). +- **Verified against a live server:** the [Hugging Face MCP server](https://github.com/huggingface/hf-mcp-server) is the server-side counterpart (advertises the same extension + serves `skill://` resources; see its row in [skills-extension-candidates.md](skills-extension-candidates.md)). fast-agent's docs walk through `/mcp connect --name hf https://huggingface.co/mcp` → `/skills registry hf` → `/skills add`. --- #### adk-python (Google ADK) -Verified at commit [`7ad7994`](https://github.com/google/adk-python/commit/7ad7994744de18f2394e4bcb961cd5c7a24afb4b) (2026-05-22). +Verified at commit [`61a3933`](https://github.com/google/adk-python/commit/61a39330d) (2026-06-03). - **MCP integration:** [`src/google/adk/tools/mcp_tool/`](https://github.com/google/adk-python/tree/main/src/google/adk/tools/mcp_tool) package — `McpToolset` (lowercase c; `MCPToolset` is a deprecated alias) is the entry point used by callers to connect an ADK agent to an MCP server. -- **Resource RPC wired:** [`mcp_toolset.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/mcp_tool/mcp_toolset.py) exposes `async def read_resource(self, name, readonly_context=None)` (line 380) which calls `session.read_resource(uri=resource_info["uri"])` (line 397). +- **Resource RPC wired:** [`mcp_toolset.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/mcp_tool/mcp_toolset.py) exposes `async def read_resource(self, name, readonly_context=None)` which calls `session.read_resource(uri=resource_info["uri"])`. - **Model-facing tool:** [`load_mcp_resource_tool.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/load_mcp_resource_tool.py) defines `load_mcp_resource`. **Not two-shot** — the tool's input schema is `resource_names: array[string]` (one call returns the contents of N resources). The catalog of available resources is exposed to the model via `_append_resources_to_llm_request()` injecting it into the LLM context, rather than via a separate `list` tool. -- **Enablement:** opt-in via the `use_mcp_resources=True` constructor flag on `McpToolset` (default `False`). When set, `get_tools()` (line 372) appends `LoadMcpResourceTool` to the toolset alongside the dynamically discovered MCP tools. +- **Enablement:** opt-in via the `use_mcp_resources=True` constructor flag on `McpToolset` (default `False`). When set, `get_tools()` appends `LoadMcpResourceTool` to the toolset alongside the dynamically discovered MCP tools. - **End-user docs:** none found in `README.md` or the docs folder — the affordance is undocumented for end users despite being implemented. - **Why interesting:** ADK is the client with the most rigorous skill validation in the parallel skills survey, so this is where the spec extension and the resource-tool extension converge. The batch `resource_names` shape is a distinct fourth signature among dedicated-tool implementers. --- #### agent-framework (Microsoft) -Verified at commit [`793403f`](https://github.com/microsoft/agent-framework/commit/793403f3db3c44463eb4e9bb8ad95af0a027f906) (2026-05-22). +Verified at commit [`c3901a4`](https://github.com/microsoft/agent-framework/commit/c3901a4dd) (2026-06-03). -- **MCP integration:** Multi-transport client tools — `MCPTool` (line 180) plus `MCPStdioTool` (1463), `MCPStreamableHTTPTool` (1598), `MCPWebsocketTool` (1775) in [`_mcp.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/_mcp.py). The client-facing methods are `load_tools()`, `call_tool()`, `load_prompts()`, `get_prompt()` — no resource methods. .NET equivalents (e.g. `DefaultMcpToolHandler`) under [`dotnet/src/`](https://github.com/microsoft/agent-framework/tree/main/dotnet/src) expose `InvokeToolAsync()` only. -- **Resource RPC wired:** No MCP resource RPC. The only production `read_resource` callsite in the repo is in [`_skills.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/_skills.py) (lines 2090–2112) and refers to **skill** resources, not MCP `resources/read`. All MCP `resources/read` references are confined to `tests/core/test_skills.py`. -- **Why on the list:** dual-stack Python/.NET framework with rich skills metadata in the parallel skills survey. The asymmetry — skills support without MCP resource-tool support — is the kind of gap a #2527-aligned PR would close. +- **MCP integration:** Multi-transport client tools — `MCPTool` plus `MCPStdioTool`, `MCPStreamableHTTPTool`, `MCPWebsocketTool` in [`_mcp.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/_mcp.py). The client-facing methods are `load_tools()`, `call_tool()`, `load_prompts()`, `get_prompt()` — no resource methods. .NET equivalents (e.g. `DefaultMcpToolHandler`) under [`dotnet/src/`](https://github.com/microsoft/agent-framework/tree/main/dotnet/src) expose `InvokeToolAsync()` only. +- **Resource RPC wired:** No MCP resource RPC at the model boundary. The only production `read_resource` callsites are in [`_skills.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/_skills.py) and refer to **skill** resources, not the model-facing MCP `resources/read`. All MCP `resources/read` references are confined to tests. +- **Update:** upstream has since added **MCP-based skills *discovery*** (recent commits use MCP resources internally for skill metadata / `skill://index.json` lookups via `_skills.py`) — but this is still not exposed to the model as a resource-read tool. +- **Why on the list:** dual-stack Python/.NET framework with rich skills metadata in the parallel skills survey. The asymmetry — skills support without a model-facing MCP resource tool — is the kind of gap a #2527-aligned PR would close. --- #### crewAI -Verified at commit [`c3e2001`](https://github.com/crewAIInc/crewAI/commit/c3e2001d524164739bbc17cdb25bd77bf6af6eaa) (2026-05-23) of the main `crewAI` repo, which vendors `crewai-tools` under `lib/crewai-tools/`. +Verified at commit [`051fa0c`](https://github.com/crewAIInc/crewAI/commit/051fa0c1c) (2026-06) of the main `crewAI` repo, which vendors `crewai-tools` under `lib/crewai-tools/` (the adapter is now under `lib/crewai-tools/src/crewai_tools/`). -- **MCP integration:** [`mcp_adapter.py`](https://github.com/crewAIInc/crewAI-tools/blob/main/crewai_tools/adapters/mcp_adapter.py) imports `mcp` (`StdioServerParameters`, `CallToolResult`, `TextContent`, `Tool`) and `mcpadapt.core` (`MCPAdapt`, `ToolAdapter`); `CrewAIToolAdapter.adapt(func, mcp_tool: Tool)` converts MCP tools to CrewAI `BaseTool` objects. +- **MCP integration:** [`mcp_adapter.py`](https://github.com/crewAIInc/crewAI/blob/main/lib/crewai-tools/src/crewai_tools/adapters/mcp_adapter.py) imports `mcp` (`StdioServerParameters`, `CallToolResult`, `TextContent`, `Tool`) and `mcpadapt.core` (`MCPAdapt`, `ToolAdapter`); `CrewAIToolAdapter.adapt(func, mcp_tool: Tool)` converts MCP tools to CrewAI `BaseTool` objects. - **Resource RPC wired:** No — `adapt()` is typed to accept only `mcp_tool: Tool`; zero matches for `resource`/`Resource` anywhere in the adapter file or directory. `_run()` extracts `CallToolResult` content only. - **Model-facing tool:** None. - **Why on the list:** Same upstream block as **smolagents** — both depend on [`mcpadapt`](https://github.com/grll/mcpadapt) (`mcpadapt>=0.1.9` declared as optional dep in `lib/crewai-tools/pyproject.toml`), which is tools-only. A single upstream change in `mcpadapt` flips both clients. This is the highest-leverage adapter-library target identified so far. @@ -91,38 +102,38 @@ Verified at commit [`c3e2001`](https://github.com/crewAIInc/crewAI/commit/c3e200 --- #### deepagents (LangChain) -Verified at commit [`a64ff43`](https://github.com/langchain-ai/deepagents/commit/a64ff430f14b76607dfb1d78234f928ed88a3af0). +Verified at commit [`436409f`](https://github.com/langchain-ai/deepagents/commit/436409fc) (2026-06-03). Note the repo has since been restructured into a monorepo — the MCP code now lives under `libs/code/deepagents_code/`. -- **MCP wiring is outsourced** to `langchain_mcp_adapters.tools.load_mcp_tools()` (called from [`mcp_tools.py`](https://github.com/langchain-ai/deepagents/blob/main/src/deepagents/mcp_tools.py)). The upstream adapter does not expose `resources/read` as a tool — zero hits for resource-read in deepagents source. +- **MCP wiring is outsourced** to `langchain-mcp-adapters` — [`mcp_tools.py`](https://github.com/langchain-ai/deepagents/blob/main/libs/code/deepagents_code/mcp_tools.py) calls `convert_mcp_tool_to_langchain_tool()` / `_build_cached_mcp_tool()` (the older `load_mcp_tools()` entry point is no longer used). The adapter does not expose `resources/read` as a tool — zero hits for resource-read in deepagents source; sessions only call `list_tools()` / `call_tool()`. - **What it would take:** either upstream adds a resource-read tool, or deepagents wraps `client.read_resource()` outside the adapter. --- #### mastra -Verified at commit [`59b20e7`](https://github.com/mastra-ai/mastra/commit/59b20e759fa039370f7e1859b9e06726fe143cc3) (2026-05-23). +Verified at commit [`f82cc72`](https://github.com/mastra-ai/mastra/commit/f82cc72edc) (2026-06). -- **MCP integration:** [`packages/mcp/src/client/client.ts:10`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/client.ts) imports `Client` from `@modelcontextprotocol/sdk/client/index.js`. [`actions/resource.ts:130-132`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/actions/resource.ts) exposes `public async read(uri: string)` which directly returns `this.client.readResource(uri)`. -- **Resource RPC wired:** Yes, but **internal SDK only**. `ResourceClientActions` is mounted as `this.resources` on the client (`client.ts:271`) — an SDK surface for callers, not registered as an LLM-facing tool. -- **Model-facing tool:** No. The model-facing bridge is `tools()` at [`client.ts:741-743`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/client.ts) which calls `this.client.listTools()` and iterates only the returned tools array — resources are never traversed. +- **MCP integration:** [`packages/mcp/src/client/client.ts`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/client.ts) imports `Client` from `@modelcontextprotocol/sdk/client/index.js`. [`actions/resource.ts`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/actions/resource.ts) exposes `public async read(uri: string)` which directly returns `this.client.readResource(uri)`. +- **Resource RPC wired:** Yes, but **internal SDK only**. `ResourceClientActions` is mounted as `this.resources` on the client — an SDK surface for callers, not registered as an LLM-facing tool. +- **Model-facing tool:** No. The model-facing bridge is `tools()` at [`client.ts`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/client.ts) which calls `this.client.listTools()` and iterates only the returned tools array — resources are never traversed. - **Why on the list:** Mastra's skill versioning architecture (content-addressable BlobStore, draft→publish lifecycle) is the most sophisticated. Unlocking resource-read at the model boundary would be a small change relative to the rest of the framework — the SDK plumbing already exists. --- #### strands-agents -Verified at commit [`8638fc2`](https://github.com/strands-agents/sdk-python/commit/8638fc2d629e32b7b5839f4c106d5aedcdf764c9) (2026-05-04). Strands matches the **mastra pattern**: resource RPC wired in the SDK, but no model-facing tool. +Verified at commit [`0e0035f`](https://github.com/strands-agents/sdk-python/commit/0e0035fb) (2026-06). Strands matches the **mastra pattern**: resource RPC wired in the SDK, but no model-facing tool. Note the repo restructured to a `strands-py/` top-level package since the prior `8638fc2` check (verified 1108 commits later — the pattern is unchanged). -- **Resource RPC wired but unbridged:** `MCPClient.read_resource_sync()`, `list_resources_sync()`, and `list_resource_templates_sync()` in [`mcp_client.py`](https://github.com/strands-agents/sdk-python/blob/main/src/strands/tools/mcp/mcp_client.py) are SDK-public methods, but [`MCPAgentTool`](https://github.com/strands-agents/sdk-python/blob/main/src/strands/tools/mcp/mcp_agent_tool.py) only wraps `mcp.types.Tool` and delegates to `call_tool_async(...)`. Outside tests, nothing in the repo invokes the resource methods. -- **Why on the list:** Strands has its own local-filesystem skills implementation at [`agent_skills.py`](https://github.com/strands-agents/sdk-python/blob/main/src/strands/vended_plugins/skills/agent_skills.py), so the framework already does progressive disclosure. Wiring resource-read to the model is the obvious next step for an MCP-backed skill story. +- **Resource RPC wired but unbridged:** `MCPClient.read_resource_sync()`, `list_resources_sync()`, and `list_resource_templates_sync()` in [`mcp_client.py`](https://github.com/strands-agents/sdk-python/blob/main/strands-py/src/strands/tools/mcp/mcp_client.py) are SDK-public methods, but [`MCPAgentTool`](https://github.com/strands-agents/sdk-python/blob/main/strands-py/src/strands/tools/mcp/mcp_agent_tool.py) only wraps `mcp.types.Tool` and delegates to `call_tool_async(...)`. Outside tests, nothing in the repo invokes the resource methods. +- **Why on the list:** Strands has its own local-filesystem skills implementation at [`agent_skills.py`](https://github.com/strands-agents/sdk-python/blob/main/strands-py/src/strands/vended_plugins/skills/agent_skills.py), so the framework already does progressive disclosure. Wiring resource-read to the model is the obvious next step for an MCP-backed skill story. --- ### Coding agents / CLIs #### codex (OpenAI) -Verified at commit [`67849d9`](https://github.com/openai/codex/commit/67849d950d843c954102adb0db0e11f993aefdb7). +Verified at commit [`ad2012d`](https://github.com/openai/codex/commit/ad2012d645b7146d31bb03f98e2bd9371635d11a). (The handlers were reorganized from the single `codex-rs/tools/src/mcp_resource_tool.rs` file into a per-tool module directory since the prior `67849d9` check.) -- **Model-facing tools:** `read_mcp_resource`, `list_mcp_resources`, `list_mcp_resource_templates` defined at [`mcp_resource_tool.rs`](https://github.com/openai/codex/blob/main/codex-rs/tools/src/mcp_resource_tool.rs); registered unconditionally when an MCP server is configured. Handler at [`mcp_resource.rs`](https://github.com/openai/codex/blob/main/codex-rs/core/src/tools/handlers/mcp_resource.rs) → `session.read_resource()`. -- **Signature:** `(server, uri)` — model names the server explicitly. No user-facing doc; an internal steer tells the model to prefer `tool_search`. +- **Model-facing tools:** `read_mcp_resource`, `list_mcp_resources`, `list_mcp_resource_templates`, each a handler module under [`codex-rs/core/src/tools/handlers/mcp_resource/`](https://github.com/openai/codex/tree/main/codex-rs/core/src/tools/handlers/mcp_resource); registered unconditionally via `add_mcp_resource_tools` in [`spec_plan.rs`](https://github.com/openai/codex/blob/main/codex-rs/core/src/tools/spec_plan.rs), gated on `context.mcp_tools.is_some()`. The read handler [`read_mcp_resource.rs`](https://github.com/openai/codex/blob/main/codex-rs/core/src/tools/handlers/mcp_resource/read_mcp_resource.rs) calls `session.read_resource(&server, …)`. +- **Signature:** `(server, uri)` — model names the server explicitly. No user-facing doc; an internal steer (in `apps_instructions.rs`) tells the model to prefer `tool_search`. --- @@ -135,10 +146,10 @@ Verified at commit [`45d8bf8`](https://github.com/aaif-goose/goose/commit/45d8bf --- #### hermes-agent (Nous Research) -Verified at commit [`72ff3e9`](https://github.com/NousResearch/hermes-agent/commit/72ff3e909c73b625ee244ab5ea3d0608ee85dcf3) (2026-05-23). +Verified at commit [`03ba06e`](https://github.com/NousResearch/hermes-agent/commit/03ba06ebf) (2026-06). No drift across the 376 commits since the prior `72ff3e9` check. - **MCP integration:** Full integration in [`tools/mcp_tool.py`](https://github.com/NousResearch/hermes-agent/blob/main/tools/mcp_tool.py). -- **Resource RPC wired:** Yes — `_make_read_resource_handler()` calls `await server.session.read_resource(uri)`. +- **Resource RPC wired:** Yes — `_make_read_resource_handler()` calls `await server.session.read_resource(uri)`; the per-server schemas are built in `_build_utility_schemas()`. - **Model-facing tools:** Yes — both `mcp_{safe_name}_read_resource` (taking `uri`) and `mcp_{safe_name}_list_resources` (no parameters) registered per connected server via `_build_utility_schemas()`. Conditionally registered when the server advertises `capabilities.resources` AND the per-server `tools.resources` config flag is on (default). - **Signature:** `(uri)` — server is encoded in the tool name (one tool per server), so the model implicitly selects the server by selecting the tool. **Distinct from every other pattern surveyed**: not `(server, uri)`, not `(resource_names: array[string])` batch, not `(uri)`-with-probing, not URI-virtualized — it's *one tool per server*. The matching `list_resources` per server gives the model a discovery affordance without cross-server probing. - **End-user docs:** [`features/mcp.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/mcp.md) and [`guides/use-mcp-with-hermes.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/guides/use-mcp-with-hermes.md) both document the utility wrappers. (Minor doc/code mismatch: the user-facing docs name the tools as bare `read_resource` / `list_resources`, but the actual model-facing names include the `mcp_{server}_` prefix.) @@ -153,32 +164,32 @@ Claude Code is closed source so we cannot verify the loader, but the [public too --- #### opencode -Verified at commit [`ce89bcb`](https://github.com/anomalyco/opencode/commit/ce89bcb8e238401ea8fee000dc54539057d47dc4). +Verified at commit [`2a33add`](https://github.com/anomalyco/opencode/commit/2a33addd2) on the canonical `dev` default branch. -- **Tools forwarded to the model** in [`packages/opencode/src/mcp/index.ts`](https://github.com/anomalyco/opencode/blob/main/packages/opencode/src/mcp/index.ts) via `client.callTool()`; tool naming convention `{server_name}:{tool_name}`. -- **Resource-read is UI-only:** `readResource()` in the same file is invoked from the file picker, never registered as an LLM tool. Docs ([`mcp-servers.mdx`](https://github.com/anomalyco/opencode/blob/main/packages/web/src/content/docs/docs/mcp-servers.mdx)) advertise tool forwarding only. +- **Tools forwarded to the model** in [`packages/opencode/src/mcp/index.ts`](https://github.com/anomalyco/opencode/blob/main/packages/opencode/src/mcp/index.ts) via `client.callTool()`; tool naming convention `{server_name}_{tool_name}` (sanitized, underscore-separated — `sanitize(clientName) + "_" + sanitize(mcpTool.name)`). The model-tool bridge in [`packages/opencode/src/session/tools.ts`](https://github.com/anomalyco/opencode/blob/main/packages/opencode/src/session/tools.ts) forwards only `mcp.tools()`. +- **Resource-read is UI-only:** `readResource()` in the same file is invoked only from the file picker (`session/prompt.ts` attachment path), never registered as an LLM tool. Docs ([`mcp-servers.mdx`](https://github.com/anomalyco/opencode/blob/main/packages/web/src/content/docs/mcp-servers.mdx)) advertise tool forwarding only. --- ### IDE extensions #### vscode (GitHub Copilot) -Verified at commits [`530cb5d`](https://github.com/microsoft/vscode/commit/530cb5de713aec2e96059e2f6cf41a95403cdb3d) (vscode core) and [`9e668cb`](https://github.com/microsoft/vscode-copilot-chat/commit/9e668cb12144c701cf0f2c6b3458c00fe3da20f1) (Copilot Chat extension). VS Code is the unique pattern here: no MCP-specific tool — generic `copilot_readFile` / `copilot_listDirectory` tools transparently reach MCP servers via filesystem-provider indirection on a custom URI scheme. +Verified at commit [`ebb335f`](https://github.com/microsoft/vscode/commit/ebb335fad02) (vscode core, 2026-06-03); the Copilot Chat extension was re-checked against current `microsoft/vscode-copilot-chat` main. VS Code is the unique pattern here: no MCP-specific tool — generic `copilot_readFile` / `copilot_listDirectory` tools transparently reach MCP servers via filesystem-provider indirection on a custom URI scheme. - **URI scheme + FS provider:** [`McpResourceURI`](https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/mcp/common/mcpTypes.ts) defines `mcp-resource://` URIs that encode the MCP server's definition ID in the authority — self-routing. [`McpResourceFilesystem`](https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.ts) is registered for that scheme; `_readURIInner` decodes the URI, looks up the `McpServer`, and calls `r.readResource(...)` — the MCP `resources/read` RPC. Capability-gated on `McpCapability.Resources`. -- **`resource_link` pre-wrap:** when an MCP tool returns a `resource_link`, [`mcpLanguageModelToolContribution.ts`](https://github.com/microsoft/vscode-copilot-chat/blob/main/src/extension/conversation/vscode-node/mcpLanguageModelToolContribution.ts) converts it into an `mcp-resource://` URI so the model can re-read it later via `copilot_readFile`. -- **Caveat — discoverability:** the model can only read a URI it has been handed (user attachment, or an MCP tool's `resource_link`). No `list_mcp_resources`-equivalent. [Connor Peet on PR #2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527#issuecomment-4282395437) is the clearest write-up of this pattern. +- **`resource_link` pre-wrap — removed:** the doc previously described `mcpLanguageModelToolContribution.ts` converting an MCP tool's `resource_link` into an `mcp-resource://` URI for later re-reading via `copilot_readFile`. As of current main that file is gone and `microsoft/vscode-copilot-chat` no longer references the `mcp-resource://` scheme at all. The core scheme + FS provider in vscode itself remain intact, but the extension no longer auto-wraps `resource_link`s — so the model now has fewer built-in ways to obtain such a URI (the live forwarding path observed in the local clone renders `resource_link`s as plain text). *Worth re-confirming the current intended mechanism upstream.* +- **Caveat — discoverability:** the model can only read a URI it has been handed (e.g. a user attachment). No `list_mcp_resources`-equivalent **for the model**. Note vscode core *does* now expose `IMcpServer.resources()` / `resourceTemplates()` ([`mcpTypes.ts`](https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/mcp/common/mcpTypes.ts)), but these feed a *user-facing* resource quick-pick (`mcpResourceQuickAccess.ts`), not a model tool. [Connor Peet on PR #2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527#issuecomment-4282395437) is the clearest write-up of this pattern. --- #### cline -Verified at commit [`8a6441f`](https://github.com/cline/cline/commit/8a6441fddd3b4d372d086886ebe4ee11e78dc993) (2026-05-22). +Verified at commit [`81792d2`](https://github.com/cline/cline/commit/81792d20c) (2026-06-04). Note the repo restructured into a monorepo — the VS Code extension source now lives under `apps/vscode/src/` (was `src/`). -- **MCP integration:** Depends on `@modelcontextprotocol/sdk` `^1.25.1` per `package.json:504`. -- **Resource RPC wired:** Yes. [`McpHub.readResource(serverName, uri)`](https://github.com/cline/cline/blob/main/src/services/mcp/McpHub.ts) (lines 1174–1192) issues a raw `resources/read` request against the named connection's client and decodes with `ReadResourceResultSchema`. -- **Model-facing tool:** Yes. [`AccessMcpResourceHandler`](https://github.com/cline/cline/blob/main/src/core/task/tools/handlers/AccessMcpResourceHandler.ts) (line 145) calls `mcpHub.readResource(...)` from the model-tool execution pipeline. The model sees `access_mcp_resource` as a registered tool taking `(server_name, uri)`. -- **Discoverability:** The [system-prompt formatter](https://github.com/cline/cline/blob/main/src/core/prompts/system-prompt/components/mcp.ts) (`mcp.ts:56–102`) enumerates each connected server's `resources` (line 72–74) and `resourceTemplates` (line 68–70) in `formatMcpServersList()`. Populated by `fetchResourcesList()` and `fetchResourceTemplatesList()` in `McpHub.ts:658, 713–730`. +- **MCP integration:** Depends on `@modelcontextprotocol/sdk` `^1.25.1` per `apps/vscode/package.json`. +- **Resource RPC wired:** Yes. [`McpHub.readResource(serverName, uri)`](https://github.com/cline/cline/blob/main/apps/vscode/src/services/mcp/McpHub.ts) issues a raw `resources/read` request against the named connection's client and decodes with `ReadResourceResultSchema`. +- **Model-facing tool:** Yes. [`AccessMcpResourceHandler`](https://github.com/cline/cline/blob/main/apps/vscode/src/core/task/tools/handlers/AccessMcpResourceHandler.ts) calls `mcpHub.readResource(...)` from the model-tool execution pipeline. The model sees `access_mcp_resource` as a registered tool taking `(server_name, uri)`. +- **Discoverability:** The [system-prompt formatter](https://github.com/cline/cline/blob/main/apps/vscode/src/core/prompts/system-prompt/components/mcp.ts) enumerates each connected server's `resources` and `resourceTemplates` in `formatMcpServersList()`. Populated by `fetchResourcesList()` and `fetchResourceTemplatesList()` in `McpHub.ts`. - **End-user docs:** none found in `README.md`; no `docs/` directory in the repo root. - **Why interesting:** Cline has the most extensive skills implementation in the parallel survey (incl. the admin-locked enterprise `globalSkills` primitive), so the *presence* of full resource-read support, in-prompt enumeration, and dedicated handler is the natural complement. @@ -188,15 +199,16 @@ Verified at commit [`8a6441f`](https://github.com/cline/cline/commit/8a6441fddd3 Verified at commit [`b867ec9`](https://github.com/RooCodeInc/Roo-Code/commit/b867ec9145750d0ae1ff7f02d35406e9bf2a0b16) (2026-05-15). -- **MCP integration:** [`McpHub.ts:15`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) imports `ReadResourceResultSchema` from `@modelcontextprotocol/sdk/types.js`. -- **Resource RPC wired:** Yes. [`McpHub.readResource(serverName, uri, source?)`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) (lines 1711–1728) finds the named connection and issues `client.request({ method: "resources/read", params: { uri } }, ReadResourceResultSchema)`. The optional `source: "global" | "project"` disambiguates same-named servers from different scopes. -- **Model-facing tool:** Yes. [`accessMcpResourceTool.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/core/tools/accessMcpResourceTool.ts) (line 53) calls `McpHub.readResource(...)`. `access_mcp_resource` is registered in the `mcp` tool group in `src/shared/tools.ts` alongside `use_mcp_tool`. -- **Tools-vs-resources mapping:** Tools are dynamically mapped per-server via `tools = (response?.tools || []).map(...)` at `McpHub.ts:1027` (`fetchToolsList`). Resources are *not* mapped to per-resource tools — they remain data, accessed through the single dedicated `access_mcp_resource` tool. +- **MCP integration:** [`McpHub.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) imports `ReadResourceResultSchema` from `@modelcontextprotocol/sdk/types.js`. +- **Resource RPC wired:** Yes. [`McpHub.readResource(serverName, uri, source?)`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) finds the named connection and issues `client.request({ method: "resources/read", params: { uri } }, ReadResourceResultSchema)`. The optional `source: "global" | "project"` disambiguates same-named servers from different scopes. +- **Model-facing tool:** Yes. [`accessMcpResourceTool.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/core/tools/accessMcpResourceTool.ts) calls `McpHub.readResource(...)`. `access_mcp_resource` is registered in the `mcp` tool group in `src/shared/tools.ts` alongside `use_mcp_tool`. +- **Tools-vs-resources mapping:** Tools are dynamically mapped per-server via `tools = (response?.tools || []).map(...)` in `McpHub.ts` (`fetchToolsList`). Resources are *not* mapped to per-resource tools — they remain data, accessed through the single dedicated `access_mcp_resource` tool. - **End-user docs:** Yes — [`access-mcp-resource.md`](https://github.com/RooCodeInc/Roo-Code/blob/main/apps/docs/docs/advanced-usage/available-tools/access-mcp-resource.md) is a dedicated user-facing guide. - **Why interesting:** Roo-Code has both a skills implementation and an MCP hub, and also ships explicit user-facing documentation for the resource affordance — joining hermes-agent and Goose as the third client to document this for end users. ## Takeaways for SEP-2640 (skills extension) +- **First shipped client + server pair.** **fast-agent** is the first surveyed client to ship a SEP-2640 implementation — but scoped to *registry/install*: it consumes the `io.modelcontextprotocol/skills` extension to install SHA256-verified skills into its managed skills directory, and does not (yet) read skill resources at model runtime. It was verified live against the **Hugging Face MCP server**, the first server-side implementation we've interoperated with (advertises the extension + `resources: { subscribe: false, listChanged: false }`, serves `skill://` resources; tracked in [skills-extension-candidates.md](skills-extension-candidates.md)). Notably, the first real-world wrinkle was operational, not protocol-level: a client that retry-loops `resources/subscribe` (cursor-vscode) flooded the HF server, prompting a client-denylist mitigation ([hf-mcp-server#164](https://github.com/huggingface/hf-mcp-server/pull/164)) — a reminder that serving skills as resources inherits the resource subsystem's failure modes. - **Eight of fourteen open-source clients surveyed** (Codex, Goose, fast-agent, VS Code, hermes-agent, adk-python, Cline, Roo-Code) satisfy #2527's SHOULD; closed-source Claude Code's public docs confirm it does too. Goose, hermes-agent, and Roo-Code also satisfy the implicit expectation that this be documented for end users; the other implementers ship the affordance with no user-facing documentation. - **Four implementation patterns** for model-facing MCP resource access — all support the layering Peter sketches in his #2640 comment, but with different costs: - **Dedicated tools, `(server, uri)`** (Codex, Goose, Claude Code, fast-agent, Cline, Roo-Code — fast-agent is also multiplexed across `internal://`): explicit `read_resource` / `access_mcp_resource` registered alongside other MCP tools. Most discoverable; closest literal reading of #2527. By volume, this is the dominant pattern. diff --git a/docs/skills-extension-candidates.md b/docs/skills-extension-candidates.md index 75858c9..4228b05 100644 --- a/docs/skills-extension-candidates.md +++ b/docs/skills-extension-candidates.md @@ -12,7 +12,7 @@ A tracker of MCP servers, dev tools, SDKs, and skills repositories that are cand | :--- | :--- | :--- | :--- | :--- | | FastMCP 3.0 Skills | [jlowin/fastmcp](https://github.com/jlowin/fastmcp) — [docs](https://gofastmcp.com/servers/providers/skills) | FastMCP | [#2694](https://github.com/jlowin/fastmcp/issues/2694) | Framework with its own native skills provider using MCP Resources; doesn't yet reflect SEP-2640 | | chrome-devtools-mcp | [ChromeDevTools/chrome-devtools-mcp](https://github.com/ChromeDevTools/chrome-devtools-mcp) | Google (ChromeDevTools) | _none yet_ | Bundles a [`skills/`](https://github.com/ChromeDevTools/chrome-devtools-mcp/tree/main/skills) folder, but requires separate install — not served via MCP | -| hf-mcp-server | [huggingface/hf-mcp-server](https://github.com/huggingface/hf-mcp-server) | Hugging Face | _none yet_ | Official HF MCP server (Hub APIs + Gradio); could serve the associated skills from [huggingface/skills](https://github.com/huggingface/skills) instead of installing separately | +| hf-mcp-server | [huggingface/hf-mcp-server](https://github.com/huggingface/hf-mcp-server) | Hugging Face | [#164](https://github.com/huggingface/hf-mcp-server/pull/164) (merged); [#174](https://github.com/huggingface/hf-mcp-server/pull/174) (draft) | **SEP-2640 implemented (server side).** Advertises the `io.modelcontextprotocol/skills` extension + `resources: { subscribe: false, listChanged: false }` and serves `skill://` resources incl. `skill://index.json` ([`capability-utils.ts`](https://github.com/huggingface/hf-mcp-server/blob/main/packages/app/src/server/utils/capability-utils.ts), `registerSkillResources` in [`mcp-server.ts`](https://github.com/huggingface/hf-mcp-server/blob/main/packages/app/src/server/mcp-server.ts)). First server we've interoperated with end-to-end — verified live against **fast-agent** (see [client-mcp-support.md](client-mcp-support.md)). #164 adds a client denylist (default `cursor-vscode`) after that client's `resources/subscribe` retry-loop flooded the server (~100k req/min). **In flight — [#174](https://github.com/huggingface/hf-mcp-server/pull/174)** realigns to the current SEP-2640 wire contract (new `frontmatter` + per-skill `archives[]` index schema; adds paginated `resources/directory/read`); paired with client [fast-agent#825](https://github.com/evalstate/fast-agent/pull/825) and distribution producer [huggingface/skills#172](https://github.com/huggingface/skills/pull/172) | | github-mcp-server | [github/github-mcp-server](https://github.com/github/github-mcp-server) | GitHub | [#2428](https://github.com/github/github-mcp-server/pull/2428) (WIP demo, not for merge) | SEP-2640 demo branch | | Azure Skills Plugin | [microsoft/azure-skills](https://github.com/microsoft/azure-skills) | Microsoft | _none yet_ | 25 Azure SKILL.md skills bundled with [Azure MCP Server](https://github.com/microsoft/mcp/tree/main/servers/Azure.Mcp.Server) + Foundry MCP; distributed as a plugin, not via MCP | | Figma MCP | _TBD_ | Figma | _none yet_ | Contact: Discord `adityamuttur` — candidate for SEP-2640 testing | From 4f9d1321a6d92bed753b2ae6b137aebe10b15446 Mon Sep 17 00:00:00 2001 From: olaservo Date: Fri, 19 Jun 2026 07:16:42 -0700 Subject: [PATCH 11/12] docs: add Slack (interested) and Bloomberg (internal use) as SEP-2640 candidates --- docs/skills-extension-candidates.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/skills-extension-candidates.md b/docs/skills-extension-candidates.md index 4228b05..2ce9d22 100644 --- a/docs/skills-extension-candidates.md +++ b/docs/skills-extension-candidates.md @@ -17,3 +17,5 @@ A tracker of MCP servers, dev tools, SDKs, and skills repositories that are cand | Azure Skills Plugin | [microsoft/azure-skills](https://github.com/microsoft/azure-skills) | Microsoft | _none yet_ | 25 Azure SKILL.md skills bundled with [Azure MCP Server](https://github.com/microsoft/mcp/tree/main/servers/Azure.Mcp.Server) + Foundry MCP; distributed as a plugin, not via MCP | | Figma MCP | _TBD_ | Figma | _none yet_ | Contact: Discord `adityamuttur` — candidate for SEP-2640 testing | | Adobe MCP | _TBD_ | Adobe | _none yet_ | Contact: Discord `justinmathew8592` — candidate for SEP-2640 testing | +| Slack | _TBD_ | Slack | _none yet_ | Expressed interest in SEP-2640 — candidate for testing | +| Bloomberg | _internal_ | Bloomberg | _none yet_ | Using skills-over-MCP internally; not public | From ba0de5a1f5521a2ab1162790db420879998e836c Mon Sep 17 00:00:00 2001 From: olaservo Date: Fri, 19 Jun 2026 08:28:15 -0700 Subject: [PATCH 12/12] docs: remove archived Roo-Code from client survey, update strands repo to harness-sdk --- docs/client-mcp-support.md | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/docs/client-mcp-support.md b/docs/client-mcp-support.md index 876b4d6..b06dfb6 100644 --- a/docs/client-mcp-support.md +++ b/docs/client-mcp-support.md @@ -22,7 +22,7 @@ Category values: **Framework** = SDK/library you build agents on top of · **CLI | **vscode** (GitHub Copilot) | IDE | Yes (FS-provider indirection) | `copilot_readFile`, `copilot_listDirectory` (general-purpose, not MCP-specific) | `(path)` — accepts `mcp-resource://…` URIs as paths; the FS provider routes to MCP RPC | Yes — `mcp-resource://` URIs route via `IFileService` → `McpResourceFilesystem` provider → `r.readResource(...)` MCP RPC ([`mcpResourceFilesystem.ts`](https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.ts)) | Server must advertise `McpCapability.Resources`; model needs a URI to pass (typically obtained from a user attachment — the earlier Copilot Chat `resource_link`→`mcp-resource://` pre-wrap has since been removed; see deep dive) | No explicit doc, but mechanism is operational. [Connor Peet's comment on #2527](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2527#issuecomment-4282395437) is the clearest write-up | _none yet — add as found_ | | **opencode** | CLI | No | — (internal `readResource` only) | — | Internal only — `readResource()` exists in [`packages/opencode/src/mcp/index.ts`](https://github.com/anomalyco/opencode/blob/main/packages/opencode/src/mcp/index.ts) but is invoked only when the user attaches a resource via file picker; `mcp.tools()` in `prompt.ts` forwards MCP *tools* but never a resource-read tool | n/a | Docs (`mcp-servers.mdx`) advertise tool forwarding only | _none yet — add as found_ | | **deepagents** (LangChain) | Framework | No | — | — | n/a — delegates MCP wiring to [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters) (via `convert_mcp_tool_to_langchain_tool()` / `_build_cached_mcp_tool()` in [`mcp_tools.py`](https://github.com/langchain-ai/deepagents/blob/main/libs/code/deepagents_code/mcp_tools.py)); that adapter only converts MCP tools, not resources | n/a | No mention in README | **Upstream-blocked**: needs a change in `langchain-mcp-adapters` (or a deepagents wrapper around `client.read_resource()`) | -| **strands-agents** (AWS) | Framework | No (internal SDK only) | — | — | Internal only — `MCPClient.read_resource_sync()` and `list_resources_sync()` in [`mcp_client.py`](https://github.com/strands-agents/sdk-python/blob/main/strands-py/src/strands/tools/mcp/mcp_client.py) call MCP `resources/read` / `resources/list`, but `MCPAgentTool` (the only adapter) wraps `mcp.types.Tool` only and `MCPClient.load_tools()` (the `ToolProvider` interface) returns tools only | n/a | No — `docs/MCP_CLIENT_ARCHITECTURE.md` and `AGENTS.md` do not mention MCP resources | _none yet — add as found_ | +| **strands-agents** (AWS) | Framework | No (internal SDK only) | — | — | Internal only — `MCPClient.read_resource_sync()` and `list_resources_sync()` in [`mcp_client.py`](https://github.com/strands-agents/harness-sdk/blob/main/strands-py/src/strands/tools/mcp/mcp_client.py) call MCP `resources/read` / `resources/list`, but `MCPAgentTool` (the only adapter) wraps `mcp.types.Tool` only and `MCPClient.load_tools()` (the `ToolProvider` interface) returns tools only | n/a | No — `docs/MCP_CLIENT_ARCHITECTURE.md` and `AGENTS.md` do not mention MCP resources | _none yet — add as found_ | | **Claude Code** (closed source, reference) | CLI | Yes | `ReadMcpResourceTool` | `(server, uri)` per [public docs](https://code.claude.com/docs/en/tools-reference) | Documented; source not verifiable | n/a | Yes — public tools reference page | n/a | | **adk-python** (Google ADK) | Framework | Yes (by name, not URI) | `load_mcp_resource` | `(resource_names: array[string])` — model passes catalog names; framework resolves each to a URI and calls `session.read_resource(uri=…)`. The catalog is injected into the model's context by `_append_resources_to_llm_request()` rather than via a separate list call | Yes — `McpToolset.read_resource()` calls `session.read_resource(uri=…)` ([`mcp_toolset.py`](https://github.com/google/adk-python/blob/main/src/google/adk/tools/mcp_tool/mcp_toolset.py)) | Opt-in via `use_mcp_resources=True` on `McpToolset` (default `False`) | No — no user-facing docs found | _none yet — add as found_ | | **agent-framework** (Microsoft) | Framework | No (tools-only client bridge) | — | — | n/a — `MCPTool` / `MCPStdioTool` / `MCPStreamableHTTPTool` / `MCPWebsocketTool` in [`_mcp.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/_mcp.py) materialize MCP *tools* into the agent's tool registry; no `read_resource` callsite found in client code (only in a test) | n/a | Samples cover MCP tool integration only | _none yet — add as found_ | @@ -30,18 +30,17 @@ Category values: **Framework** = SDK/library you build agents on top of · **CLI | **crewAI** | Framework | No | — | — | n/a — `crewai-tools` MCP adapter ([`mcp_adapter.py`](https://github.com/crewAIInc/crewAI-tools/blob/main/crewai_tools/adapters/mcp_adapter.py)) is built on `mcpadapt` and converts MCP tools only — same upstream-blocked pattern as smolagents | n/a | MCP adapter docs cover tools only | **Upstream-blocked** by `mcpadapt` (shared with smolagents) | | **hermes-agent** (Nous Research) | CLI | Yes | `mcp_{server}_read_resource`, `mcp_{server}_list_resources` (one pair per connected server) | `(uri)` — server is encoded in the tool name | Yes — `_make_read_resource_handler()` in [`tools/mcp_tool.py`](https://github.com/NousResearch/hermes-agent/blob/main/tools/mcp_tool.py) calls `session.read_resource(uri)` and registers the tool per server | Two gates: `tools.resources` config flag (default on) AND server's advertised `capabilities.resources` | Yes — [`features/mcp.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/mcp.md) and [`guides/use-mcp-with-hermes.md`](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/guides/use-mcp-with-hermes.md) | _none yet — add as found_ | | **mastra** | Framework | No (internal SDK only) | — | — | Internal only — [`resource.ts`](https://github.com/mastra-ai/mastra/blob/main/packages/mcp/src/client/actions/resource.ts) exposes a `read(uri)` SDK method that calls `client.readResource(uri)`, but it is **not** registered as an LLM-facing tool; the model-facing tool bridge converts MCP tools only | n/a | SDK docs cover the action; no LLM-tool exposure | _none yet — add as found_ | -| **Roo-Code** | IDE | Yes | `access_mcp_resource` | `(server_name, uri)` | Yes — [`McpHub.readResource(serverName, uri, source?)`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) called from [`accessMcpResourceTool.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/core/tools/accessMcpResourceTool.ts) | `access_mcp_resource` is a member of the `mcp` tool group; server must advertise `resources` capability | Yes — [`access-mcp-resource.md`](https://github.com/RooCodeInc/Roo-Code/blob/main/apps/docs/docs/advanced-usage/available-tools/access-mcp-resource.md) | _none yet — add as found_ | ## Cross-cutting observations 1. **Three implementation patterns for model-facing MCP resource access.** - 1. **Dedicated MCP resource tools** — Codex, Goose, Claude Code, Cline, Roo-Code: explicit `read_mcp_resource` / `read_resource` / `access_mcp_resource` (+ optional `list_*`) registered alongside other MCP tools. Most discoverable by the model; closest literal reading of #2527. adk-python is a near-relative — its `load_mcp_resource` takes a batch of `resource_names` in one call rather than a single URI, but the affordance shape is the same. + 1. **Dedicated MCP resource tools** — Codex, Goose, Claude Code, Cline: explicit `read_mcp_resource` / `read_resource` / `access_mcp_resource` (+ optional `list_*`) registered alongside other MCP tools. Most discoverable by the model; closest literal reading of #2527. adk-python is a near-relative — its `load_mcp_resource` takes a batch of `resource_names` in one call rather than a single URI, but the affordance shape is the same. 2. **Multiplexed resource tool** — fast-agent: one `get_resource` tool handles both bundled (`internal://`) and MCP URIs behind a single name. Simpler surface for the model; relies on URI scheme to disambiguate. 3. **FS-provider indirection via namespaced URIs** — VS Code: no MCP-specific tool. A dedicated URI scheme (`mcp-resource://`) is registered with the filesystem service so the generic `readFile` / `listDirectory` tools transparently reach MCP `resources/read`. Reuses the agent's existing file-reading affordance; costs nothing in tool-count budget. Downside: no `list` equivalent — the model can only read URIs it's been handed. -2. **Dedicated-tool implementers converge on `(server, uri)`.** Codex, Goose, fast-agent, Claude Code, Cline, and Roo-Code all take an explicit server identifier alongside the URI. hermes-agent is the remaining variant in pattern (1)'s family: it encodes server-in-tool-name (one tool per server) and takes only `(uri)`. adk-python is the outlier — it takes `(resource_names: array[string])` and resolves URIs via a model-visible catalog injected into context. +2. **Dedicated-tool implementers converge on `(server, uri)`.** Codex, Goose, fast-agent, Claude Code, and Cline all take an explicit server identifier alongside the URI. hermes-agent is the remaining variant in pattern (1)'s family: it encodes server-in-tool-name (one tool per server) and takes only `(uri)`. adk-python is the outlier — it takes `(resource_names: array[string])` and resolves URIs via a model-visible catalog injected into context. -3. **Trust models diverge.** Per-server enablement (Goose), unconditional-when-MCP-configured (Codex), capability-gated FS provider (VS Code), capability-gated dedicated tool (Cline, Roo-Code), or framework opt-in flag (adk-python, `use_mcp_resources=True`, default off). For skills-over-MCP this matters because the "who can read what" boundary is currently set by each host individually — a portable skill that depends on `resources/read` will work or not based on whether the host considers MCP resource access a model-grade affordance. +3. **Trust models diverge.** Per-server enablement (Goose), unconditional-when-MCP-configured (Codex), capability-gated FS provider (VS Code), capability-gated dedicated tool (Cline), or framework opt-in flag (adk-python, `use_mcp_resources=True`, default off). For skills-over-MCP this matters because the "who can read what" boundary is currently set by each host individually — a portable skill that depends on `resources/read` will work or not based on whether the host considers MCP resource access a model-grade affordance. 4. **Discoverability differs sharply between patterns — and within them.** Within pattern (1), discovery shapes diverge: Codex, Goose, hermes-agent (per server), and Claude Code pair `read_*` with a `list_*` tool so the model can enumerate resources on its own; Cline instead injects each server's `resources` and `resourceTemplates` into the system prompt via its `mcp.ts` formatter; adk-python injects an in-context catalog of resource names via `_append_resources_to_llm_request()`. Pattern (2) (fast-agent) has *no* model-facing `list_resources` on current main — only the `get_resource` tool is registered (an internal `smart_list_resources` method exists but isn't exposed to the model). Pattern (3) (VS Code) has *no list equivalent* — the model can only read a URI it's been handed (user attachment → chat context, or an MCP tool returning a `resource_link`). For skills this matters: a `skill://index.json`-style enumeration model implicitly assumes the model can either *list* or be *told* what's available. Pattern (3) needs the index handed in via attachment or a dedicated tool result. @@ -120,10 +119,10 @@ Verified at commit [`f82cc72`](https://github.com/mastra-ai/mastra/commit/f82cc7 --- #### strands-agents -Verified at commit [`0e0035f`](https://github.com/strands-agents/sdk-python/commit/0e0035fb) (2026-06). Strands matches the **mastra pattern**: resource RPC wired in the SDK, but no model-facing tool. Note the repo restructured to a `strands-py/` top-level package since the prior `8638fc2` check (verified 1108 commits later — the pattern is unchanged). +Verified at commit [`0e0035f`](https://github.com/strands-agents/harness-sdk/commit/0e0035fb) (2026-06). Strands matches the **mastra pattern**: resource RPC wired in the SDK, but no model-facing tool. The Python SDK lives in the `strands-py/` package of the `strands-agents/harness-sdk` monorepo. -- **Resource RPC wired but unbridged:** `MCPClient.read_resource_sync()`, `list_resources_sync()`, and `list_resource_templates_sync()` in [`mcp_client.py`](https://github.com/strands-agents/sdk-python/blob/main/strands-py/src/strands/tools/mcp/mcp_client.py) are SDK-public methods, but [`MCPAgentTool`](https://github.com/strands-agents/sdk-python/blob/main/strands-py/src/strands/tools/mcp/mcp_agent_tool.py) only wraps `mcp.types.Tool` and delegates to `call_tool_async(...)`. Outside tests, nothing in the repo invokes the resource methods. -- **Why on the list:** Strands has its own local-filesystem skills implementation at [`agent_skills.py`](https://github.com/strands-agents/sdk-python/blob/main/strands-py/src/strands/vended_plugins/skills/agent_skills.py), so the framework already does progressive disclosure. Wiring resource-read to the model is the obvious next step for an MCP-backed skill story. +- **Resource RPC wired but unbridged:** `MCPClient.read_resource_sync()`, `list_resources_sync()`, and `list_resource_templates_sync()` in [`mcp_client.py`](https://github.com/strands-agents/harness-sdk/blob/main/strands-py/src/strands/tools/mcp/mcp_client.py) are SDK-public methods, but [`MCPAgentTool`](https://github.com/strands-agents/harness-sdk/blob/main/strands-py/src/strands/tools/mcp/mcp_agent_tool.py) only wraps `mcp.types.Tool` and delegates to `call_tool_async(...)`. Outside tests, nothing in the repo invokes the resource methods. +- **Why on the list:** Strands has its own local-filesystem skills implementation at [`agent_skills.py`](https://github.com/strands-agents/harness-sdk/blob/main/strands-py/src/strands/vended_plugins/skills/agent_skills.py), so the framework already does progressive disclosure. Wiring resource-read to the model is the obvious next step for an MCP-backed skill story. --- @@ -159,7 +158,7 @@ Verified at commit [`03ba06e`](https://github.com/NousResearch/hermes-agent/comm #### Claude Code (closed source — reference only) -Claude Code is closed source so we cannot verify the loader, but the [public tools reference](https://code.claude.com/docs/en/tools-reference) documents `ReadMcpResourceTool` accepting `server` and `uri` parameters. Listed here as a reference data point for the `(server, uri)` signature shape also adopted by Codex, Goose, fast-agent, Cline, and Roo-Code. +Claude Code is closed source so we cannot verify the loader, but the [public tools reference](https://code.claude.com/docs/en/tools-reference) documents `ReadMcpResourceTool` accepting `server` and `uri` parameters. Listed here as a reference data point for the `(server, uri)` signature shape also adopted by Codex, Goose, fast-agent, and Cline. --- @@ -193,25 +192,12 @@ Verified at commit [`81792d2`](https://github.com/cline/cline/commit/81792d20c) - **End-user docs:** none found in `README.md`; no `docs/` directory in the repo root. - **Why interesting:** Cline has the most extensive skills implementation in the parallel survey (incl. the admin-locked enterprise `globalSkills` primitive), so the *presence* of full resource-read support, in-prompt enumeration, and dedicated handler is the natural complement. ---- - -#### Roo-Code - -Verified at commit [`b867ec9`](https://github.com/RooCodeInc/Roo-Code/commit/b867ec9145750d0ae1ff7f02d35406e9bf2a0b16) (2026-05-15). - -- **MCP integration:** [`McpHub.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) imports `ReadResourceResultSchema` from `@modelcontextprotocol/sdk/types.js`. -- **Resource RPC wired:** Yes. [`McpHub.readResource(serverName, uri, source?)`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/mcp/McpHub.ts) finds the named connection and issues `client.request({ method: "resources/read", params: { uri } }, ReadResourceResultSchema)`. The optional `source: "global" | "project"` disambiguates same-named servers from different scopes. -- **Model-facing tool:** Yes. [`accessMcpResourceTool.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/core/tools/accessMcpResourceTool.ts) calls `McpHub.readResource(...)`. `access_mcp_resource` is registered in the `mcp` tool group in `src/shared/tools.ts` alongside `use_mcp_tool`. -- **Tools-vs-resources mapping:** Tools are dynamically mapped per-server via `tools = (response?.tools || []).map(...)` in `McpHub.ts` (`fetchToolsList`). Resources are *not* mapped to per-resource tools — they remain data, accessed through the single dedicated `access_mcp_resource` tool. -- **End-user docs:** Yes — [`access-mcp-resource.md`](https://github.com/RooCodeInc/Roo-Code/blob/main/apps/docs/docs/advanced-usage/available-tools/access-mcp-resource.md) is a dedicated user-facing guide. -- **Why interesting:** Roo-Code has both a skills implementation and an MCP hub, and also ships explicit user-facing documentation for the resource affordance — joining hermes-agent and Goose as the third client to document this for end users. - ## Takeaways for SEP-2640 (skills extension) - **First shipped client + server pair.** **fast-agent** is the first surveyed client to ship a SEP-2640 implementation — but scoped to *registry/install*: it consumes the `io.modelcontextprotocol/skills` extension to install SHA256-verified skills into its managed skills directory, and does not (yet) read skill resources at model runtime. It was verified live against the **Hugging Face MCP server**, the first server-side implementation we've interoperated with (advertises the extension + `resources: { subscribe: false, listChanged: false }`, serves `skill://` resources; tracked in [skills-extension-candidates.md](skills-extension-candidates.md)). Notably, the first real-world wrinkle was operational, not protocol-level: a client that retry-loops `resources/subscribe` (cursor-vscode) flooded the HF server, prompting a client-denylist mitigation ([hf-mcp-server#164](https://github.com/huggingface/hf-mcp-server/pull/164)) — a reminder that serving skills as resources inherits the resource subsystem's failure modes. -- **Eight of fourteen open-source clients surveyed** (Codex, Goose, fast-agent, VS Code, hermes-agent, adk-python, Cline, Roo-Code) satisfy #2527's SHOULD; closed-source Claude Code's public docs confirm it does too. Goose, hermes-agent, and Roo-Code also satisfy the implicit expectation that this be documented for end users; the other implementers ship the affordance with no user-facing documentation. +- **Seven of thirteen open-source clients surveyed** (Codex, Goose, fast-agent, VS Code, hermes-agent, adk-python, Cline) satisfy #2527's SHOULD; closed-source Claude Code's public docs confirm it does too. Goose and hermes-agent also satisfy the implicit expectation that this be documented for end users; the other implementers ship the affordance with no user-facing documentation. - **Four implementation patterns** for model-facing MCP resource access — all support the layering Peter sketches in his #2640 comment, but with different costs: - - **Dedicated tools, `(server, uri)`** (Codex, Goose, Claude Code, fast-agent, Cline, Roo-Code — fast-agent is also multiplexed across `internal://`): explicit `read_resource` / `access_mcp_resource` registered alongside other MCP tools. Most discoverable; closest literal reading of #2527. By volume, this is the dominant pattern. + - **Dedicated tools, `(server, uri)`** (Codex, Goose, Claude Code, fast-agent, Cline — fast-agent is also multiplexed across `internal://`): explicit `read_resource` / `access_mcp_resource` registered alongside other MCP tools. Most discoverable; closest literal reading of #2527. By volume, this is the dominant pattern. - **Dedicated tool, `(resource_names: array[string])`** (adk-python): batch read; the available resources are surfaced to the model via context injection rather than a separate list tool. Same affordance shape as the `(server, uri)` family but with the server identifier embedded in the catalogued resource name rather than passed as a parameter. - **One tool per server, `(uri)`** (hermes-agent): server is encoded in the tool name (`mcp_{server}_read_resource`), so the model selects the server by selecting the tool. Trades catalog tokens for unambiguity. Pairs with `mcp_{server}_list_resources` so the model has a per-server discovery affordance. - **FS-provider indirection via namespaced URIs** (VS Code): no MCP-specific tool. `mcp-resource://` URIs are registered with the file service; generic `readFile` / `listDirectory` tools transparently reach `resources/read`. Costs nothing in tool-count budget; loses `list` affordance.