SEP-2640: Skills Extension#2640
Conversation
1f35055 to
7b35855
Compare
2216f34 to
8d51b62
Compare
|
|
||
| Per RFC 3986, the first segment of `<skill-path>` occupies the authority component. This carries no special semantics under this convention and clients MUST NOT attempt DNS or network resolution of it. | ||
|
|
||
| A server MAY instead serve skills under another scheme native to its domain (e.g., `github://owner/repo/skills/refunds/SKILL.md`), provided each skill is listed in the [`skill://index.json`](#enumeration-via-skillindexjson) resource. The index is the authoritative record of which resources are skills; outside the index, hosts recognize skills by the `skill://` scheme prefix. The structural constraints above — `<skill-path>` ending in the skill name, `SKILL.md` explicit in the URI, no nesting — apply regardless of scheme. |
There was a problem hiding this comment.
So the skill path for the github:// example is owner/repo/skills/refunds, right?
| ```json | ||
| { | ||
| "name": "read_resource", | ||
| "description": "Read an MCP resource from a connected server.", | ||
| "inputSchema": { | ||
| "type": "object", | ||
| "properties": { | ||
| "server": { | ||
| "type": "string", | ||
| "description": "Name of the connected MCP server" | ||
| }, | ||
| "uri": { | ||
| "type": "string", | ||
| "description": "The resource URI, e.g. skill://git-workflow/SKILL.md" | ||
| } | ||
| }, | ||
| "required": ["server", "uri"] | ||
| } | ||
| } | ||
| ``` |
There was a problem hiding this comment.
I know this is just an example - but I don't think the model typically knows about MCP servers in most client implementations (or do they in your investigations into existing read_resource impls?).
For tools, the host keeps track of which tools exposed to the model come from MCP servers; it doesn't disclose to the model which MCP servers are available or how tools map to individual MCP servers.
Similarly, I would expect hosts to potentially have something like a single read_skill progressive disclosure tool that can read skills locally on disk and from MCP servers. Especially wrt the section below "Unified Treatement of Filesystem and MCP Skills". It's not clear to me how this signature would support unified treatment, since local file-based skills wouldn't have a server input value.
There was a problem hiding this comment.
@olaservo did an exploration here: #2527 (comment)
I did some digging in code and:
- claude code, codex, and fast-agent all have a single
read_resourcetool with a server param. - gemini-cli and goose just take uri alone and seem to probe servers one-by-one until one hits... which seems pretty janky and IMO should be fixed regardless of skills.
but yes, it's non-normative and implementations are free to do what they like here.
Similarly, I would expect hosts to potentially have something like a single read_skill progressive disclosure tool that can read skills locally on disk and from MCP servers. Especially wrt the section below "Unified Treatement of Filesystem and MCP Skills". It's not clear to me how this signature would support unified treatment, since local file-based skills wouldn't have a server input value.
What I expect (but again, non-normative):
- Client enumerate skills for all servers by reading
skill://index.json - They create a map of skill-name to skill metadata. The skill metadata says whether it is a local file or MCP-backed skill + which server it came from (or anything else).
- They have a single
read_skilltool that keys on skill-name and when invoked uses the metadata to decide whether to do a local file read or MCPresources/read(note: the model doesn't need to useread_resourcefor this -- justread_skilland it is backed by aresource/readfor MCP skills). read_resourceis mostly needed for reading related files as part of the skill, e.g. if the skill referencesskill://code-review/checklist.jsonthen the model will need to read that using aread_resourcetool and make sure it is disambiguated.
There was a problem hiding this comment.
That matches how I'm thinking about too, I recommend adding it to the SEP
|
|
||
| ## Abstract | ||
|
|
||
| This SEP defines a convention for serving [Agent Skills](https://agentskills.io/) over MCP using the existing Resources primitive. A _skill_ is a directory of files (minimally a `SKILL.md`) that provides structured workflow instructions to an agent. This extension specifies that each file in a skill directory is exposed as an MCP resource, conventionally under the `skill://` URI scheme. Skills are addressed by URI and may be read directly; a well-known `skill://index.json` resource enumerates concrete skills and parameterized skill templates, but is not required — accommodating servers whose skill catalogs are large, generated, or otherwise unenumerable. The skill format itself — directory structure, YAML frontmatter, naming rules, and the [progressive disclosure](https://agentskills.io/specification#progressive-disclosure) model that governs how hosts stage content into context — is delegated entirely to the [Agent Skills specification](https://agentskills.io/specification); this SEP defines only the transport binding. |
There was a problem hiding this comment.
Good callout on boundaries here 👍🏼
Probably a good idea to wait until this SEP lands, but was curious if there is an RFC on how we could leverage this in Agent Skills specs, or if there has already been a conversation. Sorry if my question had already been addressed. I'm still catching up on the topic.
There was a problem hiding this comment.
I'm in touch with the Agent Skills folks and they are happy with this proposal since it keeps the Agent Skills format and just focuses on delivery. Once it lands can maybe chat with them about linking to it from the agentskills.io site as a reference.
* Align resource layer with SEP-2640 (Skills Extension)
Replace legacy `skill://{name}` and `skill://{name}/` URIs with the SEP-2640
shape: `skill://<skill-path>/SKILL.md` for skill markdown, individual files
addressable as siblings, and a new `skill://index.json` discovery resource.
Declares the `io.modelcontextprotocol/skills` extension in initialize
capabilities, and adds `getSkillPath` / `buildSkillResourceUri` /
`parseSkillResourceUri` / `buildSkillIndex` helpers in skill-discovery.ts.
This is a breaking change to the URI scheme; pre-1.0, draft SEP, no shims.
SEP: modelcontextprotocol/modelcontextprotocol#2640
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Update CLAUDE.md for SEP-2640 resource layer
Document the new URI shapes, the `extensions["io.modelcontextprotocol/skills"]`
capability, and the four SEP helpers in skill-discovery.ts. Note the explicit
`skill://index.json` update notification fired from `refreshSkills()`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|
||
| **Archive entries** (`type: "archive"`) point `url` at a single resource whose content is a packed skill directory. Per the [Agent Skills archive distribution format](https://agentskills.io/well-known-uri#archive-distribution), the archive MUST be `.tar.gz` (gzip-compressed tar, `mimeType` `application/gzip`) or `.zip` (`mimeType` `application/zip`); hosts MUST support both and SHOULD determine the format from the resource's `mimeType`, falling back to the URL suffix. Archive contents represent the skill directory directly — `SKILL.md` MUST be at the archive root, not nested inside a wrapper directory, and the archive MUST NOT contain path-traversal sequences (`..`) or absolute paths. | ||
|
|
||
| The `<skill-path>` is the archive `url` with its archive suffix (`.tar.gz` or `.zip`) stripped — `skill://pdf-processing.tar.gz` unpacks to `skill://pdf-processing/`, `skill://acme/billing/refunds.zip` to `skill://acme/billing/refunds/` — and the archive contents populate `skill://<skill-path>/<file-path>` exactly as if each file were served individually. A server chooses per-skill whether to distribute as individual files or as an archive; hosts observe an identical virtual namespace either way. Archive distribution delivers a multi-file skill atomically in one round trip and can carry UNIX file metadata (executable bits, symlinks) that individual-resource distribution cannot represent — robustly for `.tar.gz`, variably for `.zip`. |
There was a problem hiding this comment.
Does the index.json have a constraint on unique way to expose the skill?
For instance, if I have a skill folder, few agents may prefer to download the archive at startup time, while other agents would prefer to load in only the skill.md file and load in related resources at runtime.
Can we expose the skill as "skill-md" and "archive" resource types to let agent/harness know about the two styles? Any other alternatives for this
There was a problem hiding this comment.
Thanks for linking that. We are trying to implement this spec in Microsoft Foundry Toolbox as well to expose skills as resources. As part of that we want to explore both methods of distribution:
- discover skills (single file + folders), download them at agent session init time
- discover skills (single file + folders), but only download the resources into the agent sandbox/session as needed.
- Retrieve only the skill://index.json at init time
- If an "example skill" needs to be activated, then resource/read on
skill://example_skill/SKILL.md - If the SKILL.md references other documents (doc X.md), then do a resource/read on that
skill://example_skill/X.md
Though downloading the archive on session init might probably be the best for long-lived sessions. There are cases where if my skill is massive folder of instructions (>10MB), we can just download few files we need and not the entire archive. With size hints provided, the agent/harness can make a determination on choosing to download archive or only certain files.
The skills spec https://agentskills.io/client-implementation/adding-skills-support assumes the agent is reading from file system (so archive makes immediate sense). But there is a growing use case for having progressive disclosure over the network than even having all skills locally in file system (especially in case of sandboxes with limited memory and in cases where there are just too many skills). Perhaps this is best delegated to agent skills spec itself.
For now, we are experimenting by exposing a skill folder in index.json in 2 ways (one skill-md entry and one archive entry), so the agent/harness can use the approach of their choice. Ideally if each skill could have offer a list of possible discovery and load mechanism, it would be nicer but this likely requires alignment with agentskills.io spec as well.
|
Coming back to this since the same shape of concern came up again from @viswabalaji -- I think it's worth a closer look at where the question is actually live, because most cases really do reduce to "server picks per skill" the way you said. Looking at
For this kind of skill the format isn't determined by the content; it's determined by the client:
The skill author can't predict which of these the requestor is. For a registry-style server fronting public skills, the consumer distribution is unknown by construction. "Servers SHOULD pick one" forces some fraction of consumers to pay the wrong cost. The cleanest resolution I can see: shared- Worth nailing down either way -- goose r2's current parser would produce two cache entries with the same |
Just for other reading: we're discussing this on Discord https://discord.com/channels/1358869848138059966/1464745826629976084/1508940124803829760 |
## Summary Adds two **[EXPERIMENTAL]** CLI commands for the draft MCP skills extension ([SEP-2640](modelcontextprotocol/modelcontextprotocol#2640), `io.modelcontextprotocol/skills`): - `mcpc @session skills-list` — discover Agent Skills exposed by the server - `mcpc @session skills-get <name> [--raw]` — read a skill's `SKILL.md` Implemented as sugar over `resources-read` using the `skill://` URI convention — no SDK changes required. ## Behavior - **Discovery:** tries `skill://index.json` first; if absent, scans resources for `skill://*/SKILL.md` (spec requires hosts not to treat a missing index as proof of no skills). - **Index entry types** (per current SEP-2640 draft): `skill-md`, `archive` (`.tar.gz`/`.zip`), and `mcp-resource-template`. Entries with unrecognized `type` are skipped. - **Capability surfacing:** `mcpc @session` overview shows `skills (experimental extension)` when the server advertises the extension under either `capabilities.extensions` (per spec) or `capabilities.experimental` (the SDK-preserved escape hatch since current SDKs strip unknown capability fields). - **JSON output** is documented in each command's `--help`: - `skills-list` → `[{ name, description, type, url }, ...]` - `skills-get` → full `ReadResourceResult`; use `jq -r '.contents[0].text'` to extract markdown ## Experimental labeling Help text marks both commands as `[EXPERIMENTAL]` and notes the spec is in draft and the shape may change — in the top-level `mcpc --help`, in the per-command descriptions, and in dedicated "Status:" blocks in each command's `--help` output. ## Tests - Unit (`test/unit/cli/skills.test.ts`, Vitest): URI resolution, index parsing (all three types, unknown-type skipping, malformed entries), resource-scan fallback, pagination, formatters, capability surfacing. - E2E (`test/e2e/suites/basic/skills.test.sh`): three scenarios via opt-in `WITH_SKILLS=true` server flag — index path, no-index fallback (`SKILLS_NO_INDEX=true`), and server without the extension. Covers `--raw`, `--json` shapes, nested paths, archive entries, and unknown-type skipping. ## Test plan - [x] `pnpm run lint` - [x] `pnpm run build` - [x] `pnpm run test:unit` (632 tests) - [x] `./test/e2e/run.sh basic/skills.test.sh` https://claude.ai/code/session_01PyzCAbMiMXTbLrFXUP3nQJ --------- Co-authored-by: Claude <noreply@anthropic.com>
|
Sharing a PHP implementation of this SEP as a reference point (the SEP currently lists none, and the documented implementations so far are Python/TS):
Two pieces of spec-text feedback surfaced while implementing the server side:
Minor note for other SDK authors: an extension advertising an empty For the open question of whether clients consume MCP skills: as of June 2026, Claude Code loads skills from the filesystem/plugins only and treats MCP resources as user-mention attachments rather than model-driven reads, so it can't currently consume MCP-served skills end-to-end. FastMCP 3.0 looks like the right consumer to validate the serving half against next. |
I'm not sure I follow, what exactly is the problem? The path shouldn't be in the name anyway, and the name is already constrained by the agent skills spec:
It is already specified on the sentence immediately following the quoted one:
|
|
Thanks @pja-ant — both fair, and you're right on the spec text in each case. Turns out neither is actually a spec issue; let me separate that from the SDK-side artifact. 1. Resource 2. Thanks for the close read. |
|
Major update: the
|
- "four" → "several" implementations (count will rot) - Fix orphaned "where:" — alternative-scheme paragraph had been inserted between the URI form and its definitions; moved it after the constraints block - Add SHOULD for io.modelcontextprotocol.skills/ _meta prefix - Cite design-principles instead of a transient GH issue for the resources-over-primitive rationale - SEP-2076 "proposes" → "originally proposed" (PR is closed) - Backward Compat: replace named small projects with link to the WG related-work survey; call out FastMCP SkillsProvider explicitly as the high-impact migration - Drop redundant instructor-scope paragraph after the security bullets - Label host/server reference impls as "Prototype" - Mark Experimental Findings as (WIP); add Related Work and _meta Keys to References
Replaces the separate Model-Driven Resource Loading and Unified Treatment sections with a single illustrative flow: host-side name→origin registry, a name-keyed read_skill tool that routes to filesystem or resources/read, and read_resource positioned for supporting files. Addresses review feedback that the previous read_resource(server, uri) example did not actually unify with filesystem skills.
…matter The skill://index.json format is now defined by this extension rather than borrowing an external discovery format. Entries carry the skill's SKILL.md frontmatter verbatim, an optional direct url+digest pair, and optional archive alternatives, each with url, mimeType, and digest. Archive layout and unpacking safety requirements are stated inline.
The index is versioned by the extension capability itself; unrecognized fields are ignored, so the format can grow additively without a per-document version marker.
dfbaebf to
518ca79
Compare
Skills often point agents at a directory of files (templates, scripts) without naming one; resources/list cannot answer this scoped question. The new method lists the direct children of a resource with mimeType inode/directory, with resources/list-style cursor pagination. Support is opt-in via a directoryRead setting in the extension capability.
Extensions Track SEP defining the
skill://resource convention for serving Agent Skills over MCP. Developed by the Skills Over MCP Working Group; transports the design from experimental-ext-skills#69 with archive distribution per experimental-ext-skills#83.Extension identifier:
io.modelcontextprotocol/skills.Reference implementations: TypeScript SDK wrappers, host prototypes in gemini-cli/fast-agent/goose/codex/Claude Code, and the GitHub MCP Server.