From c1fa4f315ec4881c3badfd2179f1e3cf3dabaee8 Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Fri, 28 Aug 2026 09:49:18 -0700 Subject: [PATCH] docs: add skills-extension-candidates and client-mcp-support trackers (#92) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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. * docs: add Issue/PR tracker column to candidates table * docs: add client-mcp-support survey alongside candidates tracker * docs: link Azure MCP Server source in candidates table * docs: remove gemini-cli from client MCP support survey * 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: 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: add Figma and Adobe MCP as SEP-2640 testing candidates * docs: update FastMCP 3.0 Skills entry with detailed notes on SEP-2640 compliance * 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: add Slack (interested) and Bloomberg (internal use) as SEP-2640 candidates * docs: remove archived Roo-Code from client survey, update strands repo to harness-sdk * docs: re-verify SEP-2640 implementations against current upstream main Both reference implementations have migrated to the July 2026 v1 shape, verified against fresh clones rather than the prior June commit pins: - hf-mcp-server (d794b10, v0.4.6): skills/list + skills/get, per-file {uri,digest} resources manifest, directoryRead:true, no index.json or archives. Migrated in #219 (merged 2026-08-03). Also records the snapshot/TTL model and HTTP-transport-only constraint. - fast-agent (79b903c, 0.10.1): pins SEP-2640 revision d7490ec, treats legacy index.json skill-md/archive entries as unsupported. Requires --prerelease=allow (pins fastmcp-slim 4.0.0b1), per @evalstate. Corrects the earlier note claiming implementations lagged the SEP: the #174/#825/#172 round merged 2026-06-19 and was never in flight, and a second realignment followed the v1 rework. Also fixes drift found while re-checking fast-agent's resource tool: smart_agent.py is gone (now core/harness_tools.py), get_resource is opt-in via harness_tools (default False, was unconditional), and server_name is now optional - the one surveyed client where the model may omit server identity. Runtime skill loading is still unshipped; #816 remains open. πŸ¦‰ Generated with [Claude Code](https://claude.com/claude-code) * docs: track SEP revision 0eb05fe and add mcpkit to the candidates tracker The SEP moved from d7490ec to 0eb05fe (2026-08-05). The delta is editorial for the wire contract -- skills/list, skills/get, and the per-file resources manifest are unchanged -- so d7490ec-pinned implementations stay compatible. Records what it does change: a soft reg-name constraint on the first skill-path segment, the skill root URI fixed as skill:// with no trailing slash, whether skills/get carries ttlMs/cacheScope reopened, and normative host obligations in the security section. Adds mcpkit (panyam/mcpkit, Go, v0.3.0) from #118 as a candidate. It implements the pre-v1 index.json catalog shape with per-file digests, so the ecosystem is now split across draft revisions rather than uniformly caught up. πŸ¦‰ Generated with [Claude Code](https://claude.com/claude-code) * docs: refine mcpkit entry β€” deliberate tracking, partial v1 migration Checked mcpkit's issues and PRs rather than inferring alignment from code shape. Its lag is a tracked decision, not drift: - #1185 (merged 2026-08-04) implements origin-tagging and per-origin resolve citing SEP L179/L183/L185 -- the host obligations 0eb05fe made normative -- so it is already on v1 for the security section. #1187 adds a SEP-2640 security/conformance harness as a WG demo. - #780 is an explicit index-schema tracking issue that has absorbed the archives removal and the resources:[{uri,digest}] direction but waits on WG confirmation; its conformance fork pins provenance at 556154c. - The carrier change is still unbooked: nothing references skills/list or skills/get. - Archives are kept as a non-spec extended surface rather than deleted, unlike fast-agent -- a counter-case for whether deferring a feature removes it from the ecosystem. Sharpens the callout accordingly: the draft split runs within an implementation, not only between them, so "which draft does X implement" often has no single answer. πŸ¦‰ Generated with [Claude Code](https://claude.com/claude-code) --- README.md | 2 + docs/client-mcp-support.md | 215 ++++++++++++++++++++++++++++ docs/related-work.md | 2 + docs/skills-extension-candidates.md | 24 ++++ 4 files changed, 243 insertions(+) create mode 100644 docs/client-mcp-support.md create mode 100644 docs/skills-extension-candidates.md diff --git a/README.md b/README.md index 197b001..0ad9278 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ 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 | | [Threat Model](docs/threat-model.md) | Threat model for skills served over MCP (SEP-2640), with delivery-model recommendations and an archive appendix | +| [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 | | [Rationale](docs/rationale.md) | Design rationale for SEP-2640's Resources-based skills extension | diff --git a/docs/client-mcp-support.md b/docs/client-mcp-support.md new file mode 100644 index 0000000..683cf0c --- /dev/null +++ b/docs/client-mcp-support.md @@ -0,0 +1,215 @@ +# 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 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** β€” 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. +> +> ℹ️ **SEP-2640 claims here are pinned to a draft revision.** The July 8–15, 2026 v1 rework ([2026-07-16 decision record](decisions.md)) removed archives, replaced `skill://index.json` with a `skills/list` method, replaced the single per-entry digest with a per-file `resources` manifest, added `skills/get`, and gated `resources/directory/read` behind a `directoryRead` capability. **fast-agent has since realigned to that shape** β€” its docs pin draft revision [`d7490ec`](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640/commits/d7490ecd1a250f7bc8c3ebb0d65450dfec274bad) and explicitly drop the older index/archive path β€” as has its server counterpart, both confirmed by [@evalstate](https://github.com/evalstate) in Discord (2026-08-04). Note the client side ships behind a prerelease install (`--prerelease=allow`; see its deep dive). This is the second realignment (the first was 2026-06-19); since the SEP is still a draft under review, expect further churn and re-verify against the SEP's current revision. The SEP is now at [`0eb05fe`](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/0eb05fe9fbd6b4c5e3fbe7e097028dd0b68a10cf/seps/2640-skills-extension.md) (2026-08-05), but that delta leaves the wire contract intact, so `d7490ec` pins remain compatible β€” see [skills-extension-candidates.md](skills-extension-candidates.md) for what it does change. +> +> **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_ | +| **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` (no model-facing `list_resources`) | `(uri, server_name=None)` β€” `server_name` optional; also handles bundled `internal://` URIs through the same tool | Yes for MCP URIs β€” `_read_resource()` β†’ `agent.get_resource(resource_uri=uri, namespace=server_name)`; `internal://` URIs short-circuit to bundled resources | Opt-in β€” `config.harness_tools`, default `False` (also stripped when `tool_only`) | Partial β€” `skills-over-mcp.md` covers the SEP-2640 install flow; the `get_resource` tool itself has no dedicated docs section | **SEP-2640 v1 shipped** (registry/install scope) β€” consumes the `io.modelcontextprotocol/skills` extension to install skills via `skills/list` / `skills/get` + per-file digest-verified `resources/read` ([`skills_extension.py`](https://github.com/evalstate/fast-agent/blob/main/src/fast_agent/mcp/skills_extension.py), [`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)); pins draft `d7490ec` and treats legacy `skill://index.json` `skill-md`/archive entries as unsupported; still does not read skill resources at model runtime. Verified live against [hf-mcp-server](https://github.com/huggingface/hf-mcp-server). **Watch:** [#816](https://github.com/evalstate/fast-agent/pull/816) (still open) 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 `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/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_ | +| **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_ | + +## Cross-cutting observations + +1. **Three implementation patterns for model-facing MCP resource access.** + 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, Claude Code, and Cline all take an explicit *required* server identifier alongside the URI. fast-agent takes the same pair but with `server_name` **optional** β€” the one surveyed implementation where the model may omit server identity entirely, which is the failure mode the takeaways flag below. 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), 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 β€” of its two harness tools only `get_resource` reads resources; `list_resources` exists on the agent/aggregator but is never registered as a tool. 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 less than it once did: v1 moved enumeration to a `skills/list` *method*, which the host calls directly rather than routing through the model's resource-read tool β€” so a client's missing `list_resources` no longer blocks skill discovery. It still matters for the L2/L3 step, where the model reads specific skill files by URI. + +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 at commit [`79b903c`](https://github.com/evalstate/fast-agent/commit/79b903c) (0.10.1, 2026-08-04). **Restructured since the prior `10a996b` (2026-06-02) check:** `smart_agent.py` is gone and the `smart` tool with it; the model-facing harness tools now live in [`core/harness_tools.py`](https://github.com/evalstate/fast-agent/blob/main/src/fast_agent/core/harness_tools.py). + +- **Model-facing tool:** `get_resource`, registered via `agent.add_tool(...)` in `set_harness_tools()` alongside `slash_command` (the two members of `HARNESS_TOOL_NAMES`). `_read_resource()` routes `internal://` to bundled resources; everything else hits the connected MCP server via `agent.get_resource(resource_uri=uri, namespace=server_name)` β†’ MCP `resources/read`. +- **Signature:** `(uri, server_name=None)` β€” multiplexed across bundled and MCP URIs by scheme, and `server_name` is now **optional**, so the model can omit the server identifier (see the server-identity point in the takeaways). +- **Enablement changed β€” now opt-in, default off.** Gated on `agent.config.harness_tools`, which defaults to `False` ([`agent_types.py:115`](https://github.com/evalstate/fast-agent/blob/main/src/fast_agent/agents/agent_types.py)); harness tools are also stripped when `tool_only` is set. This page previously recorded fast-agent as unconditional for every `SmartAgent` β€” that is no longer accurate, and it moves fast-agent into the same opt-in category as adk-python's `use_mcp_resources=True`. +- **No model-facing `list_resources`:** unchanged β€” `list_resources` exists on the agent/aggregator but is not registered as a tool, so the model can only read a URI it's been handed. + +**SEP-2640 v1 skills extension (shipped β€” registry/install scope).** Verified at commit [`79b903c`](https://github.com/evalstate/fast-agent/commit/79b903c). fast-agent is the first surveyed client to ship a SEP-2640 implementation, and has now realigned to the v1 shape. + +- **Pinned draft revision.** [`skills-over-mcp.md`](https://github.com/evalstate/fast-agent/blob/main/docs/docs/mcp/skills-over-mcp.md) pins compatibility to SEP-2640 revision [`d7490ec`](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640/commits/d7490ecd1a250f7bc8c3ebb0d65450dfec274bad) and states plainly that this is "draft compatibility, not support for a ratified MCP standard." Legacy servers publishing `skill://index.json` with `skill-md` or archive artifacts are **explicitly unsupported** β€” the older path was removed, not kept alongside. Pinning the SEP revision in user-facing docs is a practice worth noting for other implementers. +- **What it implements:** the *registry and installation* portion of the SEP, not model-facing resource loading. When a connected server advertises the `io.modelcontextprotocol/skills` extension capability (`server_supports_mcp_skills()` checks `capabilities.extensions` 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 (v1):** `/skills registry` calls paginated `skills/list`; installing an entry refreshes it via `skills/get`, then fetches every file named in its `resources` manifest through `resources/read` and requires each to match its declared SHA-256 before writing the local copy. Sidecar metadata records host-assigned server identity, skill URI, and the manifest. Entries omitting `resources` (dynamically generated skills) are listed but **not installable** β€” no complete digest manifest means no integrity check and no update revision. +- **Exercises v1's unlisted-skill path.** `/skills add skill://acme/example/SKILL.md` installs a skill absent from the listing, with the server confirming the URI via `skills/get` β€” the exact gap the [2026-07-15 `skills/get` decision](decisions.md) was written to close, now with a working implementation behind it. Name-collision handling is implemented per v1 too: same-named listing entries are preserved and disambiguated by URI, though the local managed directory still admits only one skill per name. +- **Integrity β‰  trust.** The docs carry an explicit warning that a passing SHA-256 check only means the bytes match the manifest *that server supplied* β€” it does not authenticate server or publisher, nor vouch for the skill's instructions. Useful framing for the [threat model](threat-model.md). +- **Provisional wire models.** The pinned MCP Python SDK ships no typed SEP-2640 models, so fast-agent carries its own for `skills/list`, `skills/get`, and `resources/directory/read` ([`skills_extension.py`](https://github.com/evalstate/fast-agent/blob/main/src/fast_agent/mcp/skills_extension.py)). A concrete data point on what adopting the extension costs while SDK support lags. +- **Install requires opting into prereleases.** Per [@evalstate](https://github.com/evalstate) (fast-agent's author) in Discord, v1 support must be installed as `uv tool install -U --prerelease=allow fast-agent-mcp` β€” `fast-agent-mcp` 0.10.1 is published on PyPI, but it pins `fastmcp-slim[server]==4.0.0b1` (plus `mcp==2.0.0` / `mcp-types==2.0.0`), and uv refuses prerelease dependencies unless told otherwise. So the first end-to-end SEP-2640 v1 client stack is reachable only through a prerelease install path β€” worth knowing before treating "shipped" as "generally available." +- **Still not model-facing at runtime.** Active skills do **not** read supporting files from the MCP server during a session; [PR #816](https://github.com/evalstate/fast-agent/pull/816) ("Add MCP-served skill runtime support") remains **open**. The SEP-2640 path is still host-driven install, distinct from the model-facing `get_resource` tool above. (The `SkillReader` in main serves local skill files in non-ACP contexts, not MCP-served ones.) +- **Realignment history:** two rounds. [#825](https://github.com/evalstate/fast-agent/pull/825) (merged 2026-06-19, with [#831](https://github.com/evalstate/fast-agent/pull/831) hardening) moved it to the 2026-06-05 contract; the v1 migration landed later inside the 0.10 release series ([#892](https://github.com/evalstate/fast-agent/pull/892)/[#905](https://github.com/evalstate/fast-agent/pull/905)) rather than as a standalone skills PR. +- **Verified against a live server:** the [Hugging Face MCP server](https://github.com/huggingface/hf-mcp-server) is the server-side counterpart, which migrated to v1 in [#219](https://github.com/huggingface/hf-mcp-server/pull/219) (merged 2026-08-03); 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 [`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)` 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()` 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 [`c3901a4`](https://github.com/microsoft/agent-framework/commit/c3901a4dd) (2026-06-03). + +- **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 [`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/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. + +--- + +#### deepagents (LangChain) +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` β€” [`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 [`f82cc72`](https://github.com/mastra-ai/mastra/commit/f82cc72edc) (2026-06). + +- **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 [`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/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. + +--- + +### Coding agents / CLIs + +#### codex (OpenAI) +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`, 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`. + +--- + +#### 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). +- **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) +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)`; 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.) +- **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, Goose, fast-agent, and Cline. + +--- + +#### opencode +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}` (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 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 β€” 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 [`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 `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. + +## Takeaways for SEP-2640 (skills extension) + +- **v1's protocol surface has a working client/server pair, and realignment is fast but not free.** fast-agent and hf-mcp-server have both migrated to the July v1 shape (fast-agent pinning revision `d7490ec`; hf-mcp-server via [#219](https://github.com/huggingface/hf-mcp-server/pull/219), 2026-08-03), so `skills/list`, `skills/get`, per-file digest verification, and `directoryRead` gating are all exercised end-to-end β€” including v1-specific paths like installing an unlisted skill by URI through `skills/get`. Two observations for the WG: (a) this pair has now realigned **twice in seven weeks** (2026-06-19, then early August), and each round was a breaking change β€” both implementations dropped the old shape rather than supporting both, and fast-agent's archive download/extract hardening was discarded outright when archives became a deferred feature; (b) neither can lean on the SDK β€” fast-agent carries provisional local wire models because the pinned MCP Python SDK has no typed SEP-2640 models, which is a standing cost for every adopter until the SDKs catch up. Implementation experience is real evidence for the SEP's readiness here, but it is evidence about a pinned revision, so it should be re-dated whenever the draft moves β€” and about a prerelease install path on the client side, not a generally-available one. +- **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 digest-verified skills into its managed skills directory, and does not (yet) read skill resources at model runtime ([#816](https://github.com/evalstate/fast-agent/pull/816) still open). It was verified live against the **Hugging Face MCP server**, the first server-side implementation we've interoperated with (advertises the extension with `directoryRead: true` plus `resources: { subscribe: false, listChanged: false }`; tracked in [skills-extension-candidates.md](skills-extension-candidates.md)). One deployment detail worth carrying into the SEP discussion: HF serves skills **over HTTP transports only**, not over long-lived STDIO. 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. +- **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 β€” 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), 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. fast-agent's optional `server_name` is the live instance of this: notably, its SEP-2640 install path does *not* inherit the ambiguity, since `/skills registry ` binds a specific server and skill provenance is recorded per install β€” a useful signal that skill-scoped operations want stronger server binding than a general resource-read tool. +- **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. diff --git a/docs/related-work.md b/docs/related-work.md index fb9802a..e6b3f8a 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..badd53a --- /dev/null +++ b/docs/skills-extension-candidates.md @@ -0,0 +1,24 @@ +# 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. + +> ℹ️ **Implementations track the SEP by draft revision, and have realigned twice.** SEP-2640 was reworked into a v1 scope between July 8–15, 2026 (see the [2026-07-16 decision record](decisions.md)): archives removed, `skill://index.json` replaced by a `skills/list` method, the single per-entry digest replaced by a per-file `resources` manifest, `skills/get` added, and `resources/directory/read` made optional behind a `directoryRead` capability. As of **2026-08-04 the reference server and client have both caught up** β€” hf-mcp-server migrated in [#219](https://github.com/huggingface/hf-mcp-server/pull/219) (merged 2026-08-03) and fast-agent pins draft revision [`d7490ec`](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640/commits/d7490ecd1a250f7bc8c3ebb0d65450dfec274bad) β€” after an earlier realignment round on 2026-06-19 ([hf#174](https://github.com/huggingface/hf-mcp-server/pull/174), [fast-agent#825](https://github.com/evalstate/fast-agent/pull/825), [huggingface/skills#172](https://github.com/huggingface/skills/pull/172)). Both now reject the older `skill://index.json` + archive shape outright β€” while mcpkit (below) still serves the index-catalog shape, so **the ecosystem is split across draft revisions**. Note that the split runs *within* an implementation, not just between them: mcpkit is current on v1's normative security obligations while deliberately holding its index schema pending WG confirmation. Adoption tracks the SEP section by section, so "which draft does X implement" often has no single answer. Since the SEP is still a draft under review, treat any "implemented" claim here as *implements a pinned draft revision* and re-verify against the revision the SEP is at when you read this. The SEP has since moved to [`0eb05fe`](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/0eb05fe9fbd6b4c5e3fbe7e097028dd0b68a10cf/seps/2640-skills-extension.md) (2026-08-05); that delta is editorial for the wire contract β€” `skills/list`, `skills/get`, and the per-file `resources` manifest are unchanged β€” so `d7490ec`-pinned implementations remain compatible. It does add one soft constraint (the first `` segment SHOULD be a valid RFC 3986 `reg-name`, since it occupies the authority component), pins the skill root URI as `skill://` with no trailing slash, reopens whether `skills/get` should carry `ttlMs`/`cacheScope`, and makes the security section's host obligations normative rather than a recorded WG position. + +> 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 | +| :--- | :--- | :--- | :--- | :--- | +| 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 | [#219](https://github.com/huggingface/hf-mcp-server/pull/219), [#174](https://github.com/huggingface/hf-mcp-server/pull/174), [#164](https://github.com/huggingface/hf-mcp-server/pull/164) (all merged) | **SEP-2640 v1 implemented (server side).** Verified at [`d794b10`](https://github.com/huggingface/hf-mcp-server/commit/d794b10) (v0.4.6, 2026-08-03). Implements `skills/list`, `skills/get`, `resources/read`, and optional `resources/directory/read`; entries carry `uri` + verbatim `frontmatter` + a per-file `{uri, digest}` `resources` manifest ([`skill-types.ts`](https://github.com/huggingface/hf-mcp-server/blob/main/packages/app/src/server/skills/skill-types.ts), [`skill-resources.ts`](https://github.com/huggingface/hf-mcp-server/blob/main/packages/app/src/server/skills/skill-resources.ts)). Advertises `io.modelcontextprotocol/skills` with `directoryRead: true` plus `resources: { subscribe: false, listChanged: false }` ([`capability-utils.ts`](https://github.com/huggingface/hf-mcp-server/blob/main/packages/app/src/server/utils/capability-utils.ts)). No `skill://index.json`, no archives β€” both removed by [#219](https://github.com/huggingface/hf-mcp-server/pull/219) (merged 2026-08-03), which migrated from the 2026-06-05 shape that [#174](https://github.com/huggingface/hf-mcp-server/pull/174) had landed. Operational shape: skills come from a prebuilt snapshot (`HF_SKILLS_DIR`) with every digest verified before an atomic in-memory swap, a three-hour freshness TTL with stale-while-revalidate, and **HTTP transports only β€” skills are not served over long-lived STDIO**. First server we interoperated with end-to-end (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). Distribution producer: [huggingface/skills#172](https://github.com/huggingface/skills/pull/172) | +| mcpkit (`ext/skills`) | [panyam/mcpkit](https://github.com/panyam/mcpkit) | Sri Panyam | [#780](https://github.com/panyam/mcpkit/issues/780) (open, index-schema tracking); [#1185](https://github.com/panyam/mcpkit/pull/1185), [#1187](https://github.com/panyam/mcpkit/pull/1187) (merged) | **Partially migrated, and tracking the SEP deliberately.** Go SDK covering both server and host: SKILL.md, `skill://` resources, progressive disclosure via a `skill://index.json` catalog + a host-side `load_skill` tool, per-supporting-file digests with verified reads, resource-fetch size and per-server byte budgets, and `resources/directory/read`; no code-execution surface (enforced by a build-failing test). Released in v0.3.0. **Already on v1 for the security section** β€” [#1185](https://github.com/panyam/mcpkit/pull/1185) (merged 2026-08-04) implements origin-tagging and per-origin resolve, citing SEP lines L179/L183/L185, i.e. the host obligations `0eb05fe` made normative; [#1187](https://github.com/panyam/mcpkit/pull/1187) adds a SEP-2640 security/conformance harness as a WG demo. **Deliberately holding on the index schema** β€” [#780](https://github.com/panyam/mcpkit/issues/780) is an explicit tracking vehicle (body rewritten 2026-07-14) that has already absorbed the archives removal and the `resources: [{uri, digest}]` direction, but is waiting on WG confirmation before refactoring; its conformance fork "deliberately holds provenance at pre-PR-97 commit `556154c`." Not yet absorbed: the carrier change β€” no issue or code references `skills/list`/`skills/get`, so the index-resource β†’ method move is still unbooked. Also **resolved the archive deferral differently from fast-agent**: archives are retained as an explicitly non-spec "extended surface" rather than deleted, a useful counter-case for whether deferring a feature actually removes it from the ecosystem. The only Go implementation tracked, and the only one pairing a server and host in one SDK | +| 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 | +| 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 |