From 1a01b32004d1bfdf8db345b146cbdd8e0c7408d8 Mon Sep 17 00:00:00 2001 From: Peter Alexander Date: Tue, 17 Mar 2026 15:34:03 +0000 Subject: [PATCH 1/6] Add draft SEP for Skills Extension Pre-submission Extensions Track SEP defining the skill:// resource convention: skills as MCP resources following the Agent Skills spec, discovered via scoped resources/list (SEP-2093). Includes implementation guidelines for host-provided read_resource tools, virtual-filesystem unification with local skills, and SDK convenience wrappers. --- README.md | 1 + docs/sep-draft-skills-extension.md | 268 +++++++++++++++++++++++++++++ 2 files changed, 269 insertions(+) create mode 100644 docs/sep-draft-skills-extension.md diff --git a/README.md b/README.md index 0f779cd..cd48275 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,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 | | [Decision Log](docs/decisions.md) | Record of key decisions with context and rationale | +| [Draft SEP: Skills Extension](docs/sep-draft-skills-extension.md) | Pre-submission SEP draft defining the `skill://` resource convention | ## Contributing diff --git a/docs/sep-draft-skills-extension.md b/docs/sep-draft-skills-extension.md new file mode 100644 index 0000000..3f7d6a5 --- /dev/null +++ b/docs/sep-draft-skills-extension.md @@ -0,0 +1,268 @@ +# SEP-0000: Skills Extension + +- **Status**: Draft (pre-submission) +- **Type**: Extensions Track +- **Created**: 2026-03-17 +- **Author(s)**: Skills Over MCP Interest Group +- **Sponsor**: _(seeking)_ +- **Extension Identifier**: `io.modelcontextprotocol/skills` +- **PR**: _(to be assigned on submission)_ + +> This document is a pre-submission draft maintained by the [Skills Over MCP Interest Group](https://github.com/modelcontextprotocol/experimental-ext-skills). It has not yet been submitted to the main MCP repository. Discussion welcome via [GitHub Issues](https://github.com/modelcontextprotocol/experimental-ext-skills/issues) or [Discord #skills-over-mcp-ig](https://discord.com/channels/1358869848138059966/1464745826629976084). + +## 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 under the `skill://` URI scheme, with skill discovery achieved through scoped `resources/list` calls (per [SEP-2093]). The skill format itself — directory structure, YAML frontmatter, naming rules — is delegated entirely to the [Agent Skills specification](https://agentskills.io/specification); this SEP defines only the transport binding. + +Because the extension adds no new protocol methods or capabilities, hosts that already treat MCP resources as a virtual filesystem can consume MCP-served skills identically to local filesystem skills. The specification is accompanied by implementation guidelines for host-provided resource-reading tools and SDK-level convenience wrappers. + +## Motivation + +Native skills support in host applications demonstrates strong demand for rich, progressively disclosed workflow instructions. MCP does not currently offer a conventional way to ship this content alongside the tools it describes, which leads to: + +- **Fragmented distribution.** A server and the skill that teaches an agent to use it are versioned, discovered, and installed separately. Users installing a server from a registry have no signal that a companion skill exists. ([problem-statement.md](problem-statement.md)) +- **Instruction size limits.** Server instructions load once at initialization and are practically bounded in size. Complex workflows — such as the 875-line [mcpGraph skill](https://github.com/TeamSparkAI/mcpGraph/blob/main/skills/mcpgraphtoolkit/SKILL.md) — do not fit this model. ([experimental-findings.md](experimental-findings.md#mcpgraph-skills-in-mcp-server-repo)) +- **Inconsistent ad-hoc solutions.** Absent a convention, four independent implementations have each invented their own `skill://` URI structure, with diverging semantics for authority, path, and sub-resource addressing. ([skill-uri-scheme.md](skill-uri-scheme.md#survey-of-existing-patterns)) + +This SEP codifies that answer. + +## Specification + +### Dependencies + +This extension depends on [SEP-2093] (Resource Contents Metadata and Capabilities) for scoped `resources/list`. Servers implementing this extension MUST support `resources/list` with a `uri` parameter. + +### Skill Format + +A skill served over MCP MUST conform to the [Agent Skills specification](https://agentskills.io/specification). In particular: + +- A skill is a directory identified by a _skill name_. +- Every skill MUST contain a `SKILL.md` file at its root. +- `SKILL.md` MUST begin with YAML frontmatter containing at minimum the `name` and `description` fields as defined by the Agent Skills specification. +- A skill MAY contain additional files and subdirectories (references, scripts, examples, assets). + +This extension does not redefine, constrain, or extend the skill format. Future revisions of the Agent Skills specification apply automatically. + +### Resource Mapping + +Each file within a skill directory MUST be exposed as an MCP resource. The resource URI MUST follow the form: + +``` +skill:/// +``` + +where: + +- `` is the skill's directory name, which MUST follow the Agent Skills specification [naming rules](https://agentskills.io/specification#name-field) (1–64 characters, lowercase alphanumeric and hyphens, no leading/trailing or consecutive hyphens). +- `` is the file's path relative to the skill directory root, using `/` as the path separator. + +The resource for the skill's required `SKILL.md` is therefore always: + +``` +skill:///SKILL.md +``` + +Per [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986), `` occupies the authority component and `` is the path. Skill names are not network hosts; clients MUST NOT attempt DNS or network resolution of the authority. + +#### Examples + +| File in skill directory | Resource URI | +|---|---| +| `git-workflow/SKILL.md` | `skill://git-workflow/SKILL.md` | +| `pdf-processing/SKILL.md` | `skill://pdf-processing/SKILL.md` | +| `pdf-processing/references/FORMS.md` | `skill://pdf-processing/references/FORMS.md` | +| `pdf-processing/scripts/extract.py` | `skill://pdf-processing/scripts/extract.py` | + +#### Resource Metadata + +For each `skill:///SKILL.md` resource: + +- `mimeType` SHOULD be `text/markdown`. +- `name` SHOULD be set from the `name` field of the `SKILL.md` YAML frontmatter. +- `description` SHOULD be set from the `description` field of the `SKILL.md` YAML frontmatter. + +Servers MAY expose additional frontmatter fields via the resource's `_meta` object. Other files in the skill use the `mimeType` appropriate to their content. + +### Discovery + +Servers implementing this extension MUST respond to a scoped list request for the `skill://` scheme root: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "resources/list", + "params": { + "uri": "skill://" + } +} +``` + +The response MUST include, for each skill the server provides, the resource entry for that skill's `SKILL.md`: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "resources": [ + { + "uri": "skill://git-workflow/SKILL.md", + "name": "git-workflow", + "description": "Follow this team's Git conventions for branching and commits", + "mimeType": "text/markdown" + }, + { + "uri": "skill://pdf-processing/SKILL.md", + "name": "pdf-processing", + "description": "Extract, transform, and annotate PDF documents", + "mimeType": "text/markdown" + } + ] + } +} +``` + +Servers MAY additionally list supporting files in this response, but MUST at minimum list each `SKILL.md`. Clients enumerate the skills a server provides by filtering the response for URIs matching `skill://*/SKILL.md`. + +Servers SHOULD also respond to `resources/list` with `uri` set to `skill:///` by listing all files within that skill directory, enabling clients to discover a skill's supporting files without reading `SKILL.md` first. + +#### Capability Declaration + +Per [SEP-2133] extension negotiation, servers declare support for this extension in their `initialize` response: + +```json +{ + "capabilities": { + "extensions": { + "io.modelcontextprotocol/skills": {} + } + } +} +``` + +No extension-specific settings are currently defined; an empty object indicates support. + +### Reading + +Skill files are read via the standard `resources/read` method. No skill-specific read semantics are defined. + +Internal references within a skill (e.g., `SKILL.md` linking to `references/GUIDE.md`) are relative paths, as in the filesystem form of the Agent Skills specification. A client resolves a relative reference against the skill's root — `references/GUIDE.md` in `skill://pdf-processing/SKILL.md` resolves to `skill://pdf-processing/references/GUIDE.md` — exactly as a filesystem path would resolve. + +## Implementation Guidelines + +The following are recommendations for interoperable implementations. They are not part of the normative specification. + +### Hosts: Model-Driven Resource Loading + +Hosts SHOULD expose a tool to the model that reads MCP resources by server and URI, enabling the model to load skill content on demand: + +```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"] + } +} +``` + +Including the server name disambiguates identical `skill://` URIs served by different connected servers. This tool is general-purpose — it reads any MCP resource — and benefits resource use cases beyond skills. + +The typical flow: the host calls `resources/list(uri="skill://")` on each connected server at initialization, surfaces the returned names and descriptions in the model's context, and the model calls `read_resource` when a skill is relevant to the task. + +### Hosts: Unified Treatment of Filesystem and MCP Skills + +Hosts that support both filesystem-based skills (loaded from local directories) and MCP-served skills SHOULD treat them identically, as though the set of connected servers' `skill://` resources were mounted into a virtual filesystem alongside local skill directories. + +Concretely: the same discovery surface, the same loading tool, and the same relative-path resolution. A model that has learned to follow `references/GUIDE.md` from a local `SKILL.md` should find that MCP-served skills behave the same way. Divergence between the two paths is a source of model confusion and implementation complexity. + +### SDKs: Convenience Wrappers + +SDK maintainers SHOULD provide affordances that wrap the underlying resource operations in skill-specific terms. For example: + +**Server-side** — declare a skill from a directory: + +```python +@server.skill("git-workflow") +def git_workflow(): + return Path("./skills/git-workflow") # directory containing SKILL.md +``` + +The SDK handles: reading `SKILL.md` frontmatter to populate resource metadata, registering a `skill://git-workflow/{+path}` resource template, responding to scoped `resources/list` calls, and serving file content on `resources/read`. + +**Client-side** — enumerate and fetch skills: + +```python +skills = await client.list_skills() # wraps resources/list(uri="skill://") +content = await client.read_skill("git-workflow") # wraps resources/read(uri="skill://git-workflow/SKILL.md") +``` + +These wrappers are thin — each is a single underlying protocol call with a fixed URI pattern — but they give server authors an ergonomic way to declare skills and give client authors a discoverable entry point. + +## Rationale + +### Why Resources Instead of a New Primitive? + +The Interest Group's [decision log](decisions.md#2026-02-26-prioritize-skills-as-resources-with-client-helper-tools) records this as settled. Skills are files; Resources exist to expose files. Reusing Resources inherits URI addressability, `resources/read`, `resources/subscribe`, templates, and the existing client tooling for free. A new primitive would duplicate most of this and add [ecosystem complexity the community has explicitly pushed back on](https://github.com/modelcontextprotocol/experimental-ext-skills/issues/14). + +[SEP-2076] proposes the new-primitive alternative. That approach offers cleaner capability negotiation and dedicated list-changed notifications, but at the cost of flattening skills to name-addressed blobs — losing the directory model that the Agent Skills specification defines and that supporting files depend on. + +### Why `skill:///` With an Explicit `SKILL.md`? + +Four independent implementations converged on `skill://` as the scheme without coordination — a strong signal. They diverged on structure. The [URI scheme survey](skill-uri-scheme.md) evaluates each; this SEP adopts the FastMCP-style explicit-file structure because: + +- It directly mirrors the Agent Skills specification's directory model. A skill _is_ a directory; its URI space should look like one. +- `SKILL.md` being explicit means supporting files are siblings at the same level, with no special casing for "the skill URI" versus "a file in the skill." +- Hosts implementing both filesystem and MCP skills can use one path-resolution codepath. + +The cost — `SKILL.md` is always typed out rather than implied — is small, and the discovery response already points clients at the right URI. + +### Why Delegate the Format to agentskills.io? + +The Agent Skills specification already defines YAML frontmatter fields, naming rules, directory conventions, and the progressive-disclosure model. It has its own governance, contributing process, and multi-vendor participation. Redefining any of this in an MCP SEP would create a second source of truth and a drift risk. This SEP is a transport binding; the payload format is someone else's concern. + +### Why Depend on SEP-2093? + +Without scoped `resources/list`, a client discovers skills by calling unscoped `resources/list` and filtering the response for `skill://` URIs client-side. This works but is inefficient on servers with many non-skill resources and gives servers no signal to apply skill-specific listing behavior. [SEP-2093]'s `uri` parameter fixes both: the client asks specifically for skills, and the server knows it is being asked. + +## Backward Compatibility + +This extension introduces no new protocol methods, message types, or schema changes beyond those already proposed in [SEP-2093]. A server that does not implement this extension simply exposes no `skill://` resources; existing clients are unaffected. A client that does not implement this extension sees `skill://` resources as ordinary resources, which they are. + +Existing implementations using other `skill://` URI structures (NimbleBrain's `skill://server/skill`, skilljack's implicit-`SKILL.md` `skill://name`) will need to adjust their URI paths to conform. These are small, mechanical changes, and the [survey](skill-uri-scheme.md#survey-of-existing-patterns) documents each implementation's current structure. + +## Reference Implementation + +Will be provided prior to reaching Final status. + +## Security Implications + +Skill content is instructional text delivered to a model, which makes it a prompt-injection surface. The Interest Group's position, recorded in [open-questions.md §10](open-questions.md#10-how-should-skills-handle-security-and-trust-boundaries), is: + +- **Trust inherits from the server.** A user who connects a server has already extended their trust boundary to it; a malicious server can cause more harm via tools than via a skill document. Skills do not introduce a new trust tier. +- **Skills are data, not directives.** Hosts MUST NOT treat `skill://` resources as higher-authority than other context. Explicit user policy governs whether a skill is loaded. +- **Provenance SHOULD be surfaced.** Hosts SHOULD indicate which server a skill originates from when presenting it, and MAY let users approve skills per-server. +- **Not a third-party marketplace.** This extension is for servers to ship skills that describe their own tools, not for distributing arbitrary third-party content through a connected server. + +The instructor-only scope of this extension ([decisions.md, 2026-02-14](decisions.md#2026-02-14-skills-served-over-mcp-use-the-instructor-format)) excludes the helper model of local code execution, which bounds the attack surface to text that influences model behavior rather than code that executes on the host. + +## References + +- [Agent Skills specification](https://agentskills.io/specification) +- [SEP-2093]: Resource Contents Metadata and Capabilities +- [SEP-2133]: Extensions +- [SEP-2076]: Agent Skills as first-class primitive (alternative approach) +- [Skill URI Scheme Proposal](skill-uri-scheme.md) — survey of existing patterns and recommended convention +- [Decision Log](decisions.md) — Interest Group decisions and rationale +- [Experimental Findings](experimental-findings.md) — results from implementations +- [RFC 3986: URIs](https://datatracker.ietf.org/doc/html/rfc3986) + +[SEP-2076]: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2076 +[SEP-2093]: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2093 +[SEP-2133]: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133 From 7e459dcfe9dd7e3273d492c90a1f89c6f0a69300 Mon Sep 17 00:00:00 2001 From: Peter Alexander Date: Tue, 17 Mar 2026 19:12:36 +0000 Subject: [PATCH 2/6] Relax URI structure and make discovery optional - skill-path may be arbitrarily nested and need not match the frontmatter name; the URI is a locator, identity lives in SKILL.md - resources/list(uri="skill://") is SHOULD not MUST; response is SKILL.md entries only, supporting files excluded - resource templates are MAY, framed as user-facing (completion API) - direct URI readability is the baseline; hosts must support loading skills they have never seen listed - SEP-2093 dependency is now conditional on whether the server supports enumeration --- docs/sep-draft-skills-extension.md | 142 ++++++++++++++++++++--------- 1 file changed, 98 insertions(+), 44 deletions(-) diff --git a/docs/sep-draft-skills-extension.md b/docs/sep-draft-skills-extension.md index 3f7d6a5..176f395 100644 --- a/docs/sep-draft-skills-extension.md +++ b/docs/sep-draft-skills-extension.md @@ -12,7 +12,7 @@ ## 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 under the `skill://` URI scheme, with skill discovery achieved through scoped `resources/list` calls (per [SEP-2093]). The skill format itself — directory structure, YAML frontmatter, naming rules — is delegated entirely to the [Agent Skills specification](https://agentskills.io/specification); this SEP defines only the transport binding. +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 under the `skill://` URI scheme. Skills are addressed by URI and may be read directly; enumeration via `resources/list` and discovery via resource templates are supported but not required, accommodating servers whose skill catalogs are large, generated, or otherwise unenumerable. The skill format itself — directory structure, YAML frontmatter, naming rules — is delegated entirely to the [Agent Skills specification](https://agentskills.io/specification); this SEP defines only the transport binding. Because the extension adds no new protocol methods or capabilities, hosts that already treat MCP resources as a virtual filesystem can consume MCP-served skills identically to local filesystem skills. The specification is accompanied by implementation guidelines for host-provided resource-reading tools and SDK-level convenience wrappers. @@ -22,21 +22,19 @@ Native skills support in host applications demonstrates strong demand for rich, - **Fragmented distribution.** A server and the skill that teaches an agent to use it are versioned, discovered, and installed separately. Users installing a server from a registry have no signal that a companion skill exists. ([problem-statement.md](problem-statement.md)) - **Instruction size limits.** Server instructions load once at initialization and are practically bounded in size. Complex workflows — such as the 875-line [mcpGraph skill](https://github.com/TeamSparkAI/mcpGraph/blob/main/skills/mcpgraphtoolkit/SKILL.md) — do not fit this model. ([experimental-findings.md](experimental-findings.md#mcpgraph-skills-in-mcp-server-repo)) -- **Inconsistent ad-hoc solutions.** Absent a convention, four independent implementations have each invented their own `skill://` URI structure, with diverging semantics for authority, path, and sub-resource addressing. ([skill-uri-scheme.md](skill-uri-scheme.md#survey-of-existing-patterns)) - -This SEP codifies that answer. +- **Inconsistent ad-hoc solutions.** Absent a convention, four independent implementations have each invented their own `skill://` URI structure, with diverging semantics for authority, path, and sub-resource addressing. ## Specification ### Dependencies -This extension depends on [SEP-2093] (Resource Contents Metadata and Capabilities) for scoped `resources/list`. Servers implementing this extension MUST support `resources/list` with a `uri` parameter. +Servers that support skill enumeration (see [Discovery](#discovery)) SHOULD implement scoped `resources/list` as defined in [SEP-2093] (Resource Contents Metadata and Capabilities). This dependency is conditional: a server that exposes skills only by direct URI reference or by resource template has no hard dependency on SEP-2093. ### Skill Format A skill served over MCP MUST conform to the [Agent Skills specification](https://agentskills.io/specification). In particular: -- A skill is a directory identified by a _skill name_. +- A skill is a directory. Its _skill name_ is the value of the `name` field in its `SKILL.md` frontmatter. - Every skill MUST contain a `SKILL.md` file at its root. - `SKILL.md` MUST begin with YAML frontmatter containing at minimum the `name` and `description` fields as defined by the Agent Skills specification. - A skill MAY contain additional files and subdirectories (references, scripts, examples, assets). @@ -45,37 +43,39 @@ This extension does not redefine, constrain, or extend the skill format. Future ### Resource Mapping -Each file within a skill directory MUST be exposed as an MCP resource. The resource URI MUST follow the form: +Each file within a skill directory is exposed as an MCP resource under the `skill://` scheme. The resource URI has the form: ``` -skill:/// +skill:/// ``` where: -- `` is the skill's directory name, which MUST follow the Agent Skills specification [naming rules](https://agentskills.io/specification#name-field) (1–64 characters, lowercase alphanumeric and hyphens, no leading/trailing or consecutive hyphens). -- `` is the file's path relative to the skill directory root, using `/` as the path separator. +- `` is a `/`-separated path of one or more segments locating the skill directory within the server's skill namespace. It MAY be a single segment (`git-workflow`) or nested to arbitrary depth (`acme/billing/refunds`). +- `` is the file's path relative to the skill directory root, using `/` as the separator. -The resource for the skill's required `SKILL.md` is therefore always: +The resource for the skill's required `SKILL.md` is therefore always addressable as `skill:///SKILL.md`, and the skill's root directory is the URI obtained by stripping the trailing `SKILL.md`. -``` -skill:///SKILL.md -``` +The `` is a locator, not an identifier. It need not match the skill's `name` (which comes from frontmatter), and servers MAY organize skills hierarchically by domain, team, version, or any other axis. Two constraints follow: + +- A `SKILL.md` MUST NOT appear in an ancestor directory of another `SKILL.md` under the same `skill://` root. The skill directory is the boundary; skills do not nest inside other skills. +- Each `` segment SHOULD be a valid URI path segment per [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986). No further naming constraints are imposed on the path; naming constraints on the skill itself are governed by the Agent Skills specification and apply to the frontmatter `name` field. -Per [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986), `` occupies the authority component and `` is the path. Skill names are not network hosts; clients MUST NOT attempt DNS or network resolution of the authority. +Per RFC 3986, the first segment of `` occupies the authority component. This carries no special semantics under this convention and clients MUST NOT attempt DNS or network resolution of it. #### Examples -| File in skill directory | Resource URI | -|---|---| -| `git-workflow/SKILL.md` | `skill://git-workflow/SKILL.md` | -| `pdf-processing/SKILL.md` | `skill://pdf-processing/SKILL.md` | -| `pdf-processing/references/FORMS.md` | `skill://pdf-processing/references/FORMS.md` | -| `pdf-processing/scripts/extract.py` | `skill://pdf-processing/scripts/extract.py` | +| Skill path | File | Resource URI | +|---|---|---| +| `git-workflow` | `SKILL.md` | `skill://git-workflow/SKILL.md` | +| `pdf-processing` | `references/FORMS.md` | `skill://pdf-processing/references/FORMS.md` | +| `pdf-processing` | `scripts/extract.py` | `skill://pdf-processing/scripts/extract.py` | +| `acme/billing/refunds` | `SKILL.md` | `skill://acme/billing/refunds/SKILL.md` | +| `acme/billing/refunds` | `templates/email.md` | `skill://acme/billing/refunds/templates/email.md` | #### Resource Metadata -For each `skill:///SKILL.md` resource: +For each `skill:///SKILL.md` resource: - `mimeType` SHOULD be `text/markdown`. - `name` SHOULD be set from the `name` field of the `SKILL.md` YAML frontmatter. @@ -85,7 +85,13 @@ Servers MAY expose additional frontmatter fields via the resource's `_meta` obje ### Discovery -Servers implementing this extension MUST respond to a scoped list request for the `skill://` scheme root: +A server is not required to make its skills enumerable. A `skill://` URI is directly readable via `resources/read` whether or not it appears in any list response, and hosts MUST support loading a skill given only its URI (see [Hosts: Model-Driven Resource Loading](#hosts-model-driven-resource-loading)). This is the baseline: if a model has the URI — from server instructions, from another skill, from the user — it can read the skill. + +On top of that baseline, three discovery mechanisms are defined. A server MAY support any combination. + +#### Enumeration via `resources/list` + +A server whose skill set is small enough to list SHOULD respond to a scoped list request for the `skill://` scheme root: ```json { @@ -98,7 +104,7 @@ Servers implementing this extension MUST respond to a scoped list request for th } ``` -The response MUST include, for each skill the server provides, the resource entry for that skill's `SKILL.md`: +with the `SKILL.md` resource entry for each enumerable skill: ```json { @@ -113,9 +119,9 @@ The response MUST include, for each skill the server provides, the resource entr "mimeType": "text/markdown" }, { - "uri": "skill://pdf-processing/SKILL.md", - "name": "pdf-processing", - "description": "Extract, transform, and annotate PDF documents", + "uri": "skill://acme/billing/refunds/SKILL.md", + "name": "refund-handling", + "description": "Process customer refund requests per company policy", "mimeType": "text/markdown" } ] @@ -123,9 +129,41 @@ The response MUST include, for each skill the server provides, the resource entr } ``` -Servers MAY additionally list supporting files in this response, but MUST at minimum list each `SKILL.md`. Clients enumerate the skills a server provides by filtering the response for URIs matching `skill://*/SKILL.md`. +The response to `resources/list(uri="skill://")` SHOULD contain only `SKILL.md` entries — one per skill. Supporting files SHOULD NOT appear here; this request enumerates skills, not their contents. Clients MAY rely on every entry in the response being a skill entry point. + +A server MAY also respond to `resources/list` with `uri` set to a skill's directory (e.g. `skill://acme/billing/refunds/`) by listing that skill's files. + +A server whose skill catalog is large, generated on demand, or backed by an external index MAY return an empty or partial result for `resources/list(uri="skill://")`, or MAY decline to support the scoped list entirely. Hosts MUST NOT treat an empty enumeration as proof that a server has no skills. + +#### Discovery via Resource Templates + +Servers MAY register one or more [resource templates](https://modelcontextprotocol.io/specification/2025-11-25/server/resources#resource-templates) with a `skill://` URI template, enabling hosts to discover the shape of the server's skill namespace and, where the template variables are completable, to enumerate skills interactively: + +```json +{ + "resourceTemplates": [ + { + "uriTemplate": "skill://docs/{product}/SKILL.md", + "name": "Product documentation skill", + "description": "Usage guidance for a named product", + "mimeType": "text/markdown" + }, + { + "uriTemplate": "skill://acme/{domain}/{workflow}/SKILL.md", + "name": "Acme workflow skill", + "description": "Domain-specific workflow instructions" + } + ] +} +``` + +Resource templates are primarily a user-facing discovery mechanism. Hosts SHOULD recognize resource templates whose `uriTemplate` begins with `skill://` as skill discovery points and surface them in the host UI, wiring template variables to the MCP [completion API](https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/completion) so the user can interactively fill in values and browse available skills. The user selects a skill; the host passes the resolved URI into the conversation. + +This mechanism scales to servers with unbounded skill catalogs: the template describes the addressable space without requiring the server to materialize every entry, and completion narrows it as the user types. + +#### Pointer from Server Instructions -Servers SHOULD also respond to `resources/list` with `uri` set to `skill:///` by listing all files within that skill directory, enabling clients to discover a skill's supporting files without reading `SKILL.md` first. +A server MAY direct the agent to specific `skill://` URIs from its `instructions` field. This requires no discovery machinery on the host; the URI is simply present in the model's context and readable via `resources/read`. #### Capability Declaration @@ -147,7 +185,7 @@ No extension-specific settings are currently defined; an empty object indicates Skill files are read via the standard `resources/read` method. No skill-specific read semantics are defined. -Internal references within a skill (e.g., `SKILL.md` linking to `references/GUIDE.md`) are relative paths, as in the filesystem form of the Agent Skills specification. A client resolves a relative reference against the skill's root — `references/GUIDE.md` in `skill://pdf-processing/SKILL.md` resolves to `skill://pdf-processing/references/GUIDE.md` — exactly as a filesystem path would resolve. +Internal references within a skill (e.g., `SKILL.md` linking to `references/GUIDE.md`) are relative paths, as in the filesystem form of the Agent Skills specification. A client resolves a relative reference against the skill's root — `references/GUIDE.md` in `skill://acme/billing/refunds/SKILL.md` resolves to `skill://acme/billing/refunds/references/GUIDE.md` — exactly as a filesystem path would resolve. The skill's root is the directory containing `SKILL.md`, not the `skill://` scheme root. ## Implementation Guidelines @@ -174,7 +212,9 @@ Hosts SHOULD expose a tool to the model that reads MCP resources by server and U Including the server name disambiguates identical `skill://` URIs served by different connected servers. This tool is general-purpose — it reads any MCP resource — and benefits resource use cases beyond skills. -The typical flow: the host calls `resources/list(uri="skill://")` on each connected server at initialization, surfaces the returned names and descriptions in the model's context, and the model calls `read_resource` when a skill is relevant to the task. +A typical flow: the host calls `resources/list(uri="skill://")` on each connected server at initialization and surfaces any returned skill entries in the model's context. The model calls `read_resource` with a concrete URI — one returned by enumeration, one handed to it by the user (who may have found it via a `skill://` resource template in the host UI), or one obtained out-of-band — when a skill is relevant to the task. + +Because enumeration is optional, a `read_resource` call for a `skill://` URI that the host has never seen listed is normal and expected. The host forwards it to the named server; the server either serves the resource or returns a not-found error. ### Hosts: Unified Treatment of Filesystem and MCP Skills @@ -186,21 +226,26 @@ Concretely: the same discovery surface, the same loading tool, and the same rela SDK maintainers SHOULD provide affordances that wrap the underlying resource operations in skill-specific terms. For example: -**Server-side** — declare a skill from a directory: +**Server-side** — declare a skill from a directory, at a given path: ```python -@server.skill("git-workflow") +@server.skill("git-workflow") # → skill://git-workflow/SKILL.md def git_workflow(): - return Path("./skills/git-workflow") # directory containing SKILL.md + return Path("./skills/git-workflow") + +@server.skill("acme/billing/refunds") # → skill://acme/billing/refunds/SKILL.md +def refunds(): + return Path("./skills/refunds") ``` -The SDK handles: reading `SKILL.md` frontmatter to populate resource metadata, registering a `skill://git-workflow/{+path}` resource template, responding to scoped `resources/list` calls, and serving file content on `resources/read`. +The SDK handles: reading `SKILL.md` frontmatter to populate resource metadata, registering a `skill:///{+path}` resource template, serving file content on `resources/read`, and (where the server's skill set is bounded) responding to scoped `resources/list` calls. **Client-side** — enumerate and fetch skills: ```python -skills = await client.list_skills() # wraps resources/list(uri="skill://") -content = await client.read_skill("git-workflow") # wraps resources/read(uri="skill://git-workflow/SKILL.md") +skills = await client.list_skills() # wraps resources/list(uri="skill://"), may be empty +content = await client.read_skill_uri( + "skill://acme/billing/refunds/SKILL.md") # wraps resources/read, works regardless of enumeration ``` These wrappers are thin — each is a single underlying protocol call with a fixed URI pattern — but they give server authors an ergonomic way to declare skills and give client authors a discoverable entry point. @@ -213,29 +258,39 @@ The Interest Group's [decision log](decisions.md#2026-02-26-prioritize-skills-as [SEP-2076] proposes the new-primitive alternative. That approach offers cleaner capability negotiation and dedicated list-changed notifications, but at the cost of flattening skills to name-addressed blobs — losing the directory model that the Agent Skills specification defines and that supporting files depend on. -### Why `skill:///` With an Explicit `SKILL.md`? +### Why `skill:///` With an Explicit `SKILL.md`? -Four independent implementations converged on `skill://` as the scheme without coordination — a strong signal. They diverged on structure. The [URI scheme survey](skill-uri-scheme.md) evaluates each; this SEP adopts the FastMCP-style explicit-file structure because: +Four independent implementations converged on `skill://` as the scheme without coordination — a strong signal. They diverged on structure. This SEP adopts the explicit-file form because: - It directly mirrors the Agent Skills specification's directory model. A skill _is_ a directory; its URI space should look like one. - `SKILL.md` being explicit means supporting files are siblings at the same level, with no special casing for "the skill URI" versus "a file in the skill." - Hosts implementing both filesystem and MCP skills can use one path-resolution codepath. -The cost — `SKILL.md` is always typed out rather than implied — is small, and the discovery response already points clients at the right URI. +The cost — `SKILL.md` is always typed out rather than implied — is small, and where discovery is supported the response already points clients at the right URI. + +### Why Decouple the URI Path From the Skill Name? + +Earlier drafts required `` to equal the frontmatter `name`. That coupling breaks down when a server needs hierarchy — a large organization serving `acme/billing/refunds` and `acme/support/refunds` cannot satisfy both "path is a single segment" and "path equals name" without renaming one skill. Decoupling lets the server's URI layout serve navigational needs while the frontmatter `name` serves the Agent Skills specification's identity rules. The URI is where to find the skill; the frontmatter says what it is. + +### Why Is Enumeration Optional? + +Requiring every server to list every skill in `resources/list(uri="skill://")` fails for at least three server shapes: a documentation server that synthesizes a skill per API endpoint (thousands), a skill gateway fronting an external index (unbounded), and a server that generates skills from templates parameterized at read time (unenumerable by construction). For these, the list is either too large to be useful in the model's context or does not meaningfully exist. + +The baseline is therefore direct readability — a `skill://` URI is always a valid argument to `resources/read`. Enumeration and template discovery are layered on top for servers where they make sense. A host that assumes enumeration is exhaustive will miss skills on servers where it is not, hence the requirement that hosts MUST NOT treat empty enumeration as proof of absence. ### Why Delegate the Format to agentskills.io? The Agent Skills specification already defines YAML frontmatter fields, naming rules, directory conventions, and the progressive-disclosure model. It has its own governance, contributing process, and multi-vendor participation. Redefining any of this in an MCP SEP would create a second source of truth and a drift risk. This SEP is a transport binding; the payload format is someone else's concern. -### Why Depend on SEP-2093? +### Why Reference SEP-2093? -Without scoped `resources/list`, a client discovers skills by calling unscoped `resources/list` and filtering the response for `skill://` URIs client-side. This works but is inefficient on servers with many non-skill resources and gives servers no signal to apply skill-specific listing behavior. [SEP-2093]'s `uri` parameter fixes both: the client asks specifically for skills, and the server knows it is being asked. +Without scoped `resources/list`, a client that wants to enumerate skills calls unscoped `resources/list` and filters for `skill://` URIs client-side. This works but is inefficient on servers with many non-skill resources and gives servers no signal to apply skill-specific listing behavior. [SEP-2093]'s `uri` parameter fixes both where enumeration is supported. The dependency is conditional because enumeration itself is: a server that exposes skills only by direct URI or by template never fields a scoped list call. ## Backward Compatibility This extension introduces no new protocol methods, message types, or schema changes beyond those already proposed in [SEP-2093]. A server that does not implement this extension simply exposes no `skill://` resources; existing clients are unaffected. A client that does not implement this extension sees `skill://` resources as ordinary resources, which they are. -Existing implementations using other `skill://` URI structures (NimbleBrain's `skill://server/skill`, skilljack's implicit-`SKILL.md` `skill://name`) will need to adjust their URI paths to conform. These are small, mechanical changes, and the [survey](skill-uri-scheme.md#survey-of-existing-patterns) documents each implementation's current structure. +Existing implementations using other `skill://` URI structures (NimbleBrain's `skill://server/skill`, skilljack's implicit-`SKILL.md` `skill://name`) will need to adjust their URI paths to conform. These are small, mechanical changes. ## Reference Implementation @@ -258,7 +313,6 @@ The instructor-only scope of this extension ([decisions.md, 2026-02-14](decision - [SEP-2093]: Resource Contents Metadata and Capabilities - [SEP-2133]: Extensions - [SEP-2076]: Agent Skills as first-class primitive (alternative approach) -- [Skill URI Scheme Proposal](skill-uri-scheme.md) — survey of existing patterns and recommended convention - [Decision Log](decisions.md) — Interest Group decisions and rationale - [Experimental Findings](experimental-findings.md) — results from implementations - [RFC 3986: URIs](https://datatracker.ietf.org/doc/html/rfc3986) From f1759a3ba22a01fa90c205afc3e8e8235012b863 Mon Sep 17 00:00:00 2001 From: Peter Alexander Date: Thu, 19 Mar 2026 14:54:06 +0000 Subject: [PATCH 3/6] Constrain final path segment to match frontmatter name The previous draft fully decoupled from the skill name, which meant the name could not be read from the URI without fetching and parsing SKILL.md. Now: the final segment of MUST equal the frontmatter name. Preceding segments remain an optional server-chosen prefix for organizational hierarchy. This keeps the hierarchy capability while making the skill name recoverable from the URI alone. --- docs/sep-draft-skills-extension.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/sep-draft-skills-extension.md b/docs/sep-draft-skills-extension.md index 176f395..1d01a96 100644 --- a/docs/sep-draft-skills-extension.md +++ b/docs/sep-draft-skills-extension.md @@ -56,10 +56,12 @@ where: The resource for the skill's required `SKILL.md` is therefore always addressable as `skill:///SKILL.md`, and the skill's root directory is the URI obtained by stripping the trailing `SKILL.md`. -The `` is a locator, not an identifier. It need not match the skill's `name` (which comes from frontmatter), and servers MAY organize skills hierarchically by domain, team, version, or any other axis. Two constraints follow: +The final segment of `` MUST equal the skill's `name` as declared in its `SKILL.md` frontmatter. Preceding segments, if any, are a server-chosen organizational prefix — servers MAY organize skills hierarchically by domain, team, version, or any other axis. In `skill://acme/billing/refunds/SKILL.md`, the prefix is `acme/billing` and the skill's `name` is `refunds`; in `skill://git-workflow/SKILL.md` there is no prefix and the `name` is `git-workflow`. This means the skill name is always recoverable from the URI alone, without reading frontmatter. + +Further constraints: - A `SKILL.md` MUST NOT appear in an ancestor directory of another `SKILL.md` under the same `skill://` root. The skill directory is the boundary; skills do not nest inside other skills. -- Each `` segment SHOULD be a valid URI path segment per [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986). No further naming constraints are imposed on the path; naming constraints on the skill itself are governed by the Agent Skills specification and apply to the frontmatter `name` field. +- The final `` segment, being the skill `name`, MUST satisfy the Agent Skills specification's naming rules. Prefix segments SHOULD be valid URI path segments per [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986); no further constraints are imposed on them. Per RFC 3986, the first segment of `` occupies the authority component. This carries no special semantics under this convention and clients MUST NOT attempt DNS or network resolution of it. @@ -78,7 +80,7 @@ Per RFC 3986, the first segment of `` occupies the authority compone For each `skill:///SKILL.md` resource: - `mimeType` SHOULD be `text/markdown`. -- `name` SHOULD be set from the `name` field of the `SKILL.md` YAML frontmatter. +- `name` SHOULD be set from the `name` field of the `SKILL.md` YAML frontmatter. By the path constraint above, this will equal the final segment of ``. - `description` SHOULD be set from the `description` field of the `SKILL.md` YAML frontmatter. Servers MAY expose additional frontmatter fields via the resource's `_meta` object. Other files in the skill use the `mimeType` appropriate to their content. @@ -120,7 +122,7 @@ with the `SKILL.md` resource entry for each enumerable skill: }, { "uri": "skill://acme/billing/refunds/SKILL.md", - "name": "refund-handling", + "name": "refunds", "description": "Process customer refund requests per company policy", "mimeType": "text/markdown" } @@ -268,9 +270,13 @@ Four independent implementations converged on `skill://` as the scheme without c The cost — `SKILL.md` is always typed out rather than implied — is small, and where discovery is supported the response already points clients at the right URI. -### Why Decouple the URI Path From the Skill Name? +### Why Allow a Path Prefix But Constrain the Final Segment? + +Earlier drafts required `` to be a single segment equal to the frontmatter `name`. That breaks down when a server needs hierarchy: an organization serving both `acme/billing/refunds` and `acme/support/refunds` cannot satisfy "single segment" without renaming one skill to dodge the collision. Allowing a prefix (`acme/billing/`, `acme/support/`) solves this — both skills can be named `refunds` and the prefix disambiguates. + +A subsequent draft went further and fully decoupled the path from the name. That was too loose: a URI like `skill://a/b/c/SKILL.md` tells you nothing about what the skill is called until you fetch and parse frontmatter. Clients listing skills, hosts displaying them in a picker, and models reasoning over URIs all want the name visible without a round trip. -Earlier drafts required `` to equal the frontmatter `name`. That coupling breaks down when a server needs hierarchy — a large organization serving `acme/billing/refunds` and `acme/support/refunds` cannot satisfy both "path is a single segment" and "path equals name" without renaming one skill. Decoupling lets the server's URI layout serve navigational needs while the frontmatter `name` serves the Agent Skills specification's identity rules. The URI is where to find the skill; the frontmatter says what it is. +Constraining the final segment to match the frontmatter `name` gets both properties. The prefix carries the server's organizational structure; the final segment carries the skill's identity; and the two together form a locator from which the name can be read directly. ### Why Is Enumeration Optional? From 495a2e570cc7ac85c21468ea60f8bc851da19155 Mon Sep 17 00:00:00 2001 From: Peter Alexander Date: Tue, 24 Mar 2026 11:52:32 +0000 Subject: [PATCH 4/6] Replace scoped resources/list enumeration with skill://index.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enumeration now uses a well-known skill://index.json resource whose format mirrors the Agent Skills .well-known discovery index: same $schema, same skills[] shape. Two deltas from the HTTP index: url holds the full skill:// URI, and digest is omitted (transport handles integrity over an authenticated connection). type MUST be "skill-md" since archives don't apply when every file is individually addressable. This drops the SEP-2093 dependency entirely — the extension now has zero protocol dependencies beyond resources/read. Also includes review feedback from PR #69: - Security: skill content MUST be treated as untrusted input; hosts MUST NOT honor local-execution mechanisms (hooks, scripts) without explicit opt-in; "more harm" softened to "as much harm"; user inspection SHOULD be supported - Cite agentskills.io parent-directory rule for the final-segment constraint - No-nesting constraint reworded per cliffhall suggestion - Abstract mentions progressive disclosure as delegated concern - Hosts section: SHOULD load frontmatter into context, SHOULD surface skills for user enable/disable - read_resource signature marked illustrative - "community has explicitly pushed back" softened --- docs/sep-draft-skills-extension.md | 108 ++++++++++++++--------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/docs/sep-draft-skills-extension.md b/docs/sep-draft-skills-extension.md index 1d01a96..3c3cc8d 100644 --- a/docs/sep-draft-skills-extension.md +++ b/docs/sep-draft-skills-extension.md @@ -12,7 +12,7 @@ ## 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 under the `skill://` URI scheme. Skills are addressed by URI and may be read directly; enumeration via `resources/list` and discovery via resource templates are supported but not required, accommodating servers whose skill catalogs are large, generated, or otherwise unenumerable. The skill format itself — directory structure, YAML frontmatter, naming rules — is delegated entirely to the [Agent Skills specification](https://agentskills.io/specification); this SEP defines only the transport binding. +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 under the `skill://` URI scheme. Skills are addressed by URI and may be read directly; enumeration via a well-known `skill://index.json` resource and discovery via resource templates are supported but 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. Because the extension adds no new protocol methods or capabilities, hosts that already treat MCP resources as a virtual filesystem can consume MCP-served skills identically to local filesystem skills. The specification is accompanied by implementation guidelines for host-provided resource-reading tools and SDK-level convenience wrappers. @@ -28,7 +28,7 @@ Native skills support in host applications demonstrates strong demand for rich, ### Dependencies -Servers that support skill enumeration (see [Discovery](#discovery)) SHOULD implement scoped `resources/list` as defined in [SEP-2093] (Resource Contents Metadata and Capabilities). This dependency is conditional: a server that exposes skills only by direct URI reference or by resource template has no hard dependency on SEP-2093. +This extension has no dependencies beyond the base MCP Resources primitive. ### Skill Format @@ -56,11 +56,11 @@ where: The resource for the skill's required `SKILL.md` is therefore always addressable as `skill:///SKILL.md`, and the skill's root directory is the URI obtained by stripping the trailing `SKILL.md`. -The final segment of `` MUST equal the skill's `name` as declared in its `SKILL.md` frontmatter. Preceding segments, if any, are a server-chosen organizational prefix — servers MAY organize skills hierarchically by domain, team, version, or any other axis. In `skill://acme/billing/refunds/SKILL.md`, the prefix is `acme/billing` and the skill's `name` is `refunds`; in `skill://git-workflow/SKILL.md` there is no prefix and the `name` is `git-workflow`. This means the skill name is always recoverable from the URI alone, without reading frontmatter. +The final segment of `` MUST equal the skill's `name` as declared in its `SKILL.md` frontmatter. This mirrors the Agent Skills specification's requirement that `name` [match the parent directory name](https://agentskills.io/specification#name-field). Preceding segments, if any, are a server-chosen organizational prefix — servers MAY organize skills hierarchically by domain, team, version, or any other axis. In `skill://acme/billing/refunds/SKILL.md`, the prefix is `acme/billing` and the skill's `name` is `refunds`; in `skill://git-workflow/SKILL.md` there is no prefix and the `name` is `git-workflow`. This means the skill name is always recoverable from the URI alone, without reading frontmatter. Further constraints: -- A `SKILL.md` MUST NOT appear in an ancestor directory of another `SKILL.md` under the same `skill://` root. The skill directory is the boundary; skills do not nest inside other skills. +- A `SKILL.md` MUST NOT appear in any descendant directory of a skill. The skill directory is the boundary; skills do not nest inside other skills. - The final `` segment, being the skill `name`, MUST satisfy the Agent Skills specification's naming rules. Prefix segments SHOULD be valid URI path segments per [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986); no further constraints are imposed on them. Per RFC 3986, the first segment of `` occupies the authority component. This carries no special semantics under this convention and clients MUST NOT attempt DNS or network resolution of it. @@ -87,55 +87,52 @@ Servers MAY expose additional frontmatter fields via the resource's `_meta` obje ### Discovery -A server is not required to make its skills enumerable. A `skill://` URI is directly readable via `resources/read` whether or not it appears in any list response, and hosts MUST support loading a skill given only its URI (see [Hosts: Model-Driven Resource Loading](#hosts-model-driven-resource-loading)). This is the baseline: if a model has the URI — from server instructions, from another skill, from the user — it can read the skill. +A server is not required to make its skills enumerable. A `skill://` URI is directly readable via `resources/read` whether or not it appears in any index, and hosts MUST support loading a skill given only its URI (see [Hosts: Model-Driven Resource Loading](#hosts-model-driven-resource-loading)). This is the baseline: if a model has the URI — from server instructions, from another skill, from the user — it can read the skill. On top of that baseline, three discovery mechanisms are defined. A server MAY support any combination. -#### Enumeration via `resources/list` +#### Enumeration via `skill://index.json` -A server whose skill set is small enough to list SHOULD respond to a scoped list request for the `skill://` scheme root: +A server whose skill set is enumerable SHOULD expose a resource at the well-known URI `skill://index.json` whose content is a JSON index of available skills. The index format follows the [Agent Skills well-known URI discovery index](https://agentskills.io/well-known-uri#index-format), with two differences: the `url` field contains the full `skill://` URI of the skill's `SKILL.md`, and the `digest` field is omitted (integrity is the transport's concern over an authenticated MCP connection). ```json { - "jsonrpc": "2.0", - "id": 1, - "method": "resources/list", - "params": { - "uri": "skill://" - } + "$schema": "https://schemas.agentskills.io/discovery/0.2.0/schema.json", + "skills": [ + { + "name": "git-workflow", + "type": "skill-md", + "description": "Follow this team's Git conventions for branching and commits", + "url": "skill://git-workflow/SKILL.md" + }, + { + "name": "refunds", + "type": "skill-md", + "description": "Process customer refund requests per company policy", + "url": "skill://acme/billing/refunds/SKILL.md" + } + ] } ``` -with the `SKILL.md` resource entry for each enumerable skill: +Index fields: -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "resources": [ - { - "uri": "skill://git-workflow/SKILL.md", - "name": "git-workflow", - "description": "Follow this team's Git conventions for branching and commits", - "mimeType": "text/markdown" - }, - { - "uri": "skill://acme/billing/refunds/SKILL.md", - "name": "refunds", - "description": "Process customer refund requests per company policy", - "mimeType": "text/markdown" - } - ] - } -} -``` +| Field | Required | Description | +|---|---|---| +| `$schema` | Yes | Schema version URI. Clients SHOULD match against known URIs before processing. | +| `skills` | Yes | Array of skill entries. | +| `skills[].name` | Yes | The skill's `name`, matching its `SKILL.md` frontmatter and the final segment of its ``. | +| `skills[].description` | Yes | The skill's `description`, matching its `SKILL.md` frontmatter. | +| `skills[].type` | Yes | MUST be `"skill-md"` in the MCP context. Archive distribution does not apply; supporting files are individually addressable as resources. | +| `skills[].url` | Yes | The full `skill:///SKILL.md` URI. | + +Clients SHOULD ignore unrecognized fields and SHOULD skip entries with an unrecognized `type`. -The response to `resources/list(uri="skill://")` SHOULD contain only `SKILL.md` entries — one per skill. Supporting files SHOULD NOT appear here; this request enumerates skills, not their contents. Clients MAY rely on every entry in the response being a skill entry point. +The `skill://index.json` resource is served via `resources/read` like any other resource, with `mimeType` of `application/json`. A server MAY also surface it in `resources/list` so clients can detect its presence, but clients MAY attempt to read it directly without prior discovery. -A server MAY also respond to `resources/list` with `uri` set to a skill's directory (e.g. `skill://acme/billing/refunds/`) by listing that skill's files. +A server whose skill catalog is large, generated on demand, or otherwise unenumerable MAY decline to expose `skill://index.json`, or MAY expose a partial index. Hosts MUST NOT treat an absent or empty index as proof that a server has no skills. -A server whose skill catalog is large, generated on demand, or backed by an external index MAY return an empty or partial result for `resources/list(uri="skill://")`, or MAY decline to support the scoped list entirely. Hosts MUST NOT treat an empty enumeration as proof that a server has no skills. +The URI `skill://index.json` is reserved and does not conflict with any valid ``: skill names may contain only lowercase letters, digits, and hyphens, so `index.json` cannot be a skill name. #### Discovery via Resource Templates @@ -212,9 +209,11 @@ Hosts SHOULD expose a tool to the model that reads MCP resources by server and U } ``` -Including the server name disambiguates identical `skill://` URIs served by different connected servers. This tool is general-purpose — it reads any MCP resource — and benefits resource use cases beyond skills. +The signature shown is illustrative. Including the server name is one disambiguation strategy for identical `skill://` URIs served by different connected servers; hosts MAY instead prefix URIs on conflict, scope by session, or use any other scheme appropriate to their architecture. The tool is general-purpose — it reads any MCP resource — and benefits resource use cases beyond skills. + +Hosts SHOULD load the frontmatter (`name`, `description`) of available and enabled skills into the model's context so the model can judge relevance and construct a `read_resource` call when a skill applies. Hosts SHOULD surface available skills in their UI for user inspection and per-skill enable/disable, analogous to how tools are typically exposed. -A typical flow: the host calls `resources/list(uri="skill://")` on each connected server at initialization and surfaces any returned skill entries in the model's context. The model calls `read_resource` with a concrete URI — one returned by enumeration, one handed to it by the user (who may have found it via a `skill://` resource template in the host UI), or one obtained out-of-band — when a skill is relevant to the task. +A typical flow: the host reads `skill://index.json` from each connected server and surfaces the `name` and `description` of each entry in the model's context. The model calls `read_resource` with a concrete URI — one returned by enumeration, one handed to it by the user (who may have found it via a `skill://` resource template in the host UI), or one obtained out-of-band — when a skill is relevant to the task. Because enumeration is optional, a `read_resource` call for a `skill://` URI that the host has never seen listed is normal and expected. The host forwards it to the named server; the server either serves the resource or returns a not-found error. @@ -240,12 +239,12 @@ def refunds(): return Path("./skills/refunds") ``` -The SDK handles: reading `SKILL.md` frontmatter to populate resource metadata, registering a `skill:///{+path}` resource template, serving file content on `resources/read`, and (where the server's skill set is bounded) responding to scoped `resources/list` calls. +The SDK handles: reading `SKILL.md` frontmatter to populate resource metadata, registering a `skill:///{+path}` resource template, serving file content on `resources/read`, and (where the server's skill set is bounded) generating the `skill://index.json` resource. **Client-side** — enumerate and fetch skills: ```python -skills = await client.list_skills() # wraps resources/list(uri="skill://"), may be empty +skills = await client.list_skills() # reads skill://index.json, may be empty or absent content = await client.read_skill_uri( "skill://acme/billing/refunds/SKILL.md") # wraps resources/read, works regardless of enumeration ``` @@ -256,7 +255,7 @@ These wrappers are thin — each is a single underlying protocol call with a fix ### Why Resources Instead of a New Primitive? -The Interest Group's [decision log](decisions.md#2026-02-26-prioritize-skills-as-resources-with-client-helper-tools) records this as settled. Skills are files; Resources exist to expose files. Reusing Resources inherits URI addressability, `resources/read`, `resources/subscribe`, templates, and the existing client tooling for free. A new primitive would duplicate most of this and add [ecosystem complexity the community has explicitly pushed back on](https://github.com/modelcontextprotocol/experimental-ext-skills/issues/14). +The Interest Group's [decision log](decisions.md#2026-02-26-prioritize-skills-as-resources-with-client-helper-tools) records this as settled. Skills are files; Resources exist to expose files. Reusing Resources inherits URI addressability, `resources/read`, `resources/subscribe`, templates, and the existing client tooling for free. A new primitive would duplicate most of this and add ecosystem complexity — a concern raised in [community discussion](https://github.com/modelcontextprotocol/experimental-ext-skills/issues/14). [SEP-2076] proposes the new-primitive alternative. That approach offers cleaner capability negotiation and dedicated list-changed notifications, but at the cost of flattening skills to name-addressed blobs — losing the directory model that the Agent Skills specification defines and that supporting files depend on. @@ -280,7 +279,7 @@ Constraining the final segment to match the frontmatter `name` gets both propert ### Why Is Enumeration Optional? -Requiring every server to list every skill in `resources/list(uri="skill://")` fails for at least three server shapes: a documentation server that synthesizes a skill per API endpoint (thousands), a skill gateway fronting an external index (unbounded), and a server that generates skills from templates parameterized at read time (unenumerable by construction). For these, the list is either too large to be useful in the model's context or does not meaningfully exist. +Requiring every server to expose a complete `skill://index.json` fails for at least three server shapes: a documentation server that synthesizes a skill per API endpoint (thousands), a skill gateway fronting an external index (unbounded), and a server that generates skills from templates parameterized at read time (unenumerable by construction). For these, the list is either too large to be useful in the model's context or does not meaningfully exist. The baseline is therefore direct readability — a `skill://` URI is always a valid argument to `resources/read`. Enumeration and template discovery are layered on top for servers where they make sense. A host that assumes enumeration is exhaustive will miss skills on servers where it is not, hence the requirement that hosts MUST NOT treat empty enumeration as proof of absence. @@ -288,13 +287,13 @@ The baseline is therefore direct readability — a `skill://` URI is always a va The Agent Skills specification already defines YAML frontmatter fields, naming rules, directory conventions, and the progressive-disclosure model. It has its own governance, contributing process, and multi-vendor participation. Redefining any of this in an MCP SEP would create a second source of truth and a drift risk. This SEP is a transport binding; the payload format is someone else's concern. -### Why Reference SEP-2093? +### Why an Index Resource Rather Than `resources/list`? -Without scoped `resources/list`, a client that wants to enumerate skills calls unscoped `resources/list` and filters for `skill://` URIs client-side. This works but is inefficient on servers with many non-skill resources and gives servers no signal to apply skill-specific listing behavior. [SEP-2093]'s `uri` parameter fixes both where enumeration is supported. The dependency is conditional because enumeration itself is: a server that exposes skills only by direct URI or by template never fields a scoped list call. +An earlier draft enumerated skills via a scoped `resources/list(uri="skill://")` call. Moving to a well-known index resource aligns discovery with the Agent Skills [well-known URI index](https://agentskills.io/well-known-uri) — the same JSON shape, the same schema URI, the same client-side parsing. A host that already consumes `.well-known/agent-skills/index.json` over HTTP can consume `skill://index.json` over MCP with the same code. It also drops the dependency on scoped `resources/list` (which the base spec does not guarantee), leaving this extension with zero protocol dependencies beyond `resources/read`. ## Backward Compatibility -This extension introduces no new protocol methods, message types, or schema changes beyond those already proposed in [SEP-2093]. A server that does not implement this extension simply exposes no `skill://` resources; existing clients are unaffected. A client that does not implement this extension sees `skill://` resources as ordinary resources, which they are. +This extension introduces no new protocol methods, message types, or schema changes. A server that does not implement this extension simply exposes no `skill://` resources; existing clients are unaffected. A client that does not implement this extension sees `skill://` resources as ordinary resources, which they are. Existing implementations using other `skill://` URI structures (NimbleBrain's `skill://server/skill`, skilljack's implicit-`SKILL.md` `skill://name`) will need to adjust their URI paths to conform. These are small, mechanical changes. @@ -306,17 +305,19 @@ Will be provided prior to reaching Final status. Skill content is instructional text delivered to a model, which makes it a prompt-injection surface. The Interest Group's position, recorded in [open-questions.md §10](open-questions.md#10-how-should-skills-handle-security-and-trust-boundaries), is: -- **Trust inherits from the server.** A user who connects a server has already extended their trust boundary to it; a malicious server can cause more harm via tools than via a skill document. Skills do not introduce a new trust tier. -- **Skills are data, not directives.** Hosts MUST NOT treat `skill://` resources as higher-authority than other context. Explicit user policy governs whether a skill is loaded. -- **Provenance SHOULD be surfaced.** Hosts SHOULD indicate which server a skill originates from when presenting it, and MAY let users approve skills per-server. +- **Skill content is untrusted input.** Hosts MUST treat `skill://` resource content as untrusted model input, subject to the same prompt-injection defenses applied to any server-provided text. A server being connected does not make its skill content authoritative. +- **Skills do not introduce a new trust tier.** A user who connects a server has already extended their trust boundary to it; a malicious server can do as much harm via tools as via a skill document. Serving skills over MCP adds no risk beyond what skills already carry in any transport — but the defensive posture above applies regardless. +- **No implicit local execution.** Hosts MUST NOT honor mechanisms in skill content that would cause local code execution without explicit user opt-in. This includes, non-exhaustively: hook declarations, pre/post-invocation scripts, shell commands embedded in frontmatter, or any field that a filesystem-sourced skill might use to register executable behavior on the host. Hosts MUST either ignore such fields entirely when the skill arrives over MCP, or gate them behind an explicit per-skill user approval that states what will execute and where. Silently executing server-provided code because it appeared in a skill directory is a remote code execution vector. +- **Skills are data, not directives.** Hosts MUST NOT treat `skill://` resources as higher-authority than other context. Explicit user policy governs whether a skill is loaded at all. +- **Provenance and inspection.** Hosts SHOULD indicate which server a skill originates from when presenting it, SHOULD let users inspect a skill's content before it is loaded into model context, and MAY gate loading behind per-skill or per-server user approval. - **Not a third-party marketplace.** This extension is for servers to ship skills that describe their own tools, not for distributing arbitrary third-party content through a connected server. -The instructor-only scope of this extension ([decisions.md, 2026-02-14](decisions.md#2026-02-14-skills-served-over-mcp-use-the-instructor-format)) excludes the helper model of local code execution, which bounds the attack surface to text that influences model behavior rather than code that executes on the host. +The instructor-only scope of this extension ([decisions.md, 2026-02-14](decisions.md#2026-02-14-skills-served-over-mcp-use-the-instructor-format)) deliberately excludes the helper model. A filesystem skill might reasonably carry scripts the user has audited; an MCP skill arrives from a remote party and MUST be handled as text that influences model behavior, not as code that executes on the host. ## References - [Agent Skills specification](https://agentskills.io/specification) -- [SEP-2093]: Resource Contents Metadata and Capabilities +- [Agent Skills well-known URI discovery](https://agentskills.io/well-known-uri) - [SEP-2133]: Extensions - [SEP-2076]: Agent Skills as first-class primitive (alternative approach) - [Decision Log](decisions.md) — Interest Group decisions and rationale @@ -324,5 +325,4 @@ The instructor-only scope of this extension ([decisions.md, 2026-02-14](decision - [RFC 3986: URIs](https://datatracker.ietf.org/doc/html/rfc3986) [SEP-2076]: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2076 -[SEP-2093]: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2093 [SEP-2133]: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133 From 236c894dce749305542f125cbef3b8ae025e0004 Mon Sep 17 00:00:00 2001 From: Peter Alexander Date: Mon, 30 Mar 2026 13:26:42 +0100 Subject: [PATCH 5/6] Relax skill:// scheme to SHOULD; add urlTemplate to index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The index is now the authoritative record of which resources are skills, so the scheme prefix is no longer required for identification. Servers SHOULD use skill:// but MAY serve skills under a domain-native scheme (github://, etc.) provided they're listed in skill://index.json. Structural constraints (final segment = name, explicit SKILL.md, no nesting) apply regardless of scheme. Index entries now carry exactly one of url or urlTemplate. type stays "skill-md" either way — it describes what the resolved URL points to, not whether the entry is parameterized. Template entries omit name. Servers SHOULD register the same urlTemplate as an MCP resource template so the completion API works. The Resource Templates subsection is deleted; templates are now an index feature (a "template entry") rather than a parallel discovery mechanism. Discovery is down to two mechanisms: the index and server instructions. skill://index.json remains the one fixed URI. --- docs/sep-draft-skills-extension.md | 64 ++++++++++++------------------ 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/docs/sep-draft-skills-extension.md b/docs/sep-draft-skills-extension.md index 3c3cc8d..c392c28 100644 --- a/docs/sep-draft-skills-extension.md +++ b/docs/sep-draft-skills-extension.md @@ -12,7 +12,7 @@ ## 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 under the `skill://` URI scheme. Skills are addressed by URI and may be read directly; enumeration via a well-known `skill://index.json` resource and discovery via resource templates are supported but 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. +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. Because the extension adds no new protocol methods or capabilities, hosts that already treat MCP resources as a virtual filesystem can consume MCP-served skills identically to local filesystem skills. The specification is accompanied by implementation guidelines for host-provided resource-reading tools and SDK-level convenience wrappers. @@ -43,12 +43,16 @@ This extension does not redefine, constrain, or extend the skill format. Future ### Resource Mapping -Each file within a skill directory is exposed as an MCP resource under the `skill://` scheme. The resource URI has the form: +Each file within a skill directory is exposed as an MCP resource. Servers SHOULD use the `skill://` URI scheme, under which the resource URI has the form: ``` skill:/// ``` +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 below — `` ending in the skill name, `SKILL.md` explicit in the URI, no nesting — apply regardless of scheme. + where: - `` is a `/`-separated path of one or more segments locating the skill directory within the server's skill namespace. It MAY be a single segment (`git-workflow`) or nested to arbitrary depth (`acme/billing/refunds`). @@ -87,13 +91,13 @@ Servers MAY expose additional frontmatter fields via the resource's `_meta` obje ### Discovery -A server is not required to make its skills enumerable. A `skill://` URI is directly readable via `resources/read` whether or not it appears in any index, and hosts MUST support loading a skill given only its URI (see [Hosts: Model-Driven Resource Loading](#hosts-model-driven-resource-loading)). This is the baseline: if a model has the URI — from server instructions, from another skill, from the user — it can read the skill. +A server is not required to make its skills enumerable. A skill's URI is directly readable via `resources/read` whether or not it appears in any index, and hosts MUST support loading a skill given only its URI (see [Hosts: Model-Driven Resource Loading](#hosts-model-driven-resource-loading)). This is the baseline: if a model has the URI — from server instructions, from another skill, from the user — it can read the skill. -On top of that baseline, three discovery mechanisms are defined. A server MAY support any combination. +On top of that baseline, two discovery mechanisms are defined. A server MAY support either or both. #### Enumeration via `skill://index.json` -A server whose skill set is enumerable SHOULD expose a resource at the well-known URI `skill://index.json` whose content is a JSON index of available skills. The index format follows the [Agent Skills well-known URI discovery index](https://agentskills.io/well-known-uri#index-format), with two differences: the `url` field contains the full `skill://` URI of the skill's `SKILL.md`, and the `digest` field is omitted (integrity is the transport's concern over an authenticated MCP connection). +A server SHOULD expose a resource at the well-known URI `skill://index.json` whose content is a JSON index of the skills it serves. The index format follows the [Agent Skills well-known URI discovery index](https://agentskills.io/well-known-uri#index-format), with three differences: the `url` field contains a full MCP resource URI (any scheme the server serves), the `digest` field is omitted (integrity is the transport's concern over an authenticated MCP connection), and entries may carry `urlTemplate` in place of `url` to describe a parameterized skill namespace. ```json { @@ -110,6 +114,11 @@ A server whose skill set is enumerable SHOULD expose a resource at the well-know "type": "skill-md", "description": "Process customer refund requests per company policy", "url": "skill://acme/billing/refunds/SKILL.md" + }, + { + "type": "skill-md", + "description": "Per-product documentation skill", + "urlTemplate": "skill://docs/{product}/SKILL.md" } ] } @@ -121,48 +130,25 @@ Index fields: |---|---|---| | `$schema` | Yes | Schema version URI. Clients SHOULD match against known URIs before processing. | | `skills` | Yes | Array of skill entries. | -| `skills[].name` | Yes | The skill's `name`, matching its `SKILL.md` frontmatter and the final segment of its ``. | -| `skills[].description` | Yes | The skill's `description`, matching its `SKILL.md` frontmatter. | | `skills[].type` | Yes | MUST be `"skill-md"` in the MCP context. Archive distribution does not apply; supporting files are individually addressable as resources. | -| `skills[].url` | Yes | The full `skill:///SKILL.md` URI. | +| `skills[].description` | Yes | For concrete entries, the skill's `description` matching its `SKILL.md` frontmatter. For template entries, a description of the addressable skill space. | +| `skills[].url` | — | The full resource URI of the skill's `SKILL.md`. Exactly one of `url` or `urlTemplate` MUST be present. | +| `skills[].urlTemplate` | — | An [RFC 6570](https://datatracker.ietf.org/doc/html/rfc6570) URI template resolving to `SKILL.md` resource URIs. Exactly one of `url` or `urlTemplate` MUST be present. | +| `skills[].name` | Conditional | Required when `url` is present; matches the `SKILL.md` frontmatter `name` and the final path segment. Omitted when `urlTemplate` is present. | Clients SHOULD ignore unrecognized fields and SHOULD skip entries with an unrecognized `type`. +**Template entries** describe a parameterized skill namespace without materializing every entry. A server SHOULD register the same `urlTemplate` as an MCP [resource template](https://modelcontextprotocol.io/specification/2025-11-25/server/resources#resource-templates) so hosts can wire template variables to the [completion API](https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/completion). Hosts SHOULD surface template entries in their UI as interactive discovery points: the user fills in variables via completion, selects a skill, and the host passes the resolved URI into the conversation. This scales to servers with unbounded skill catalogs. + The `skill://index.json` resource is served via `resources/read` like any other resource, with `mimeType` of `application/json`. A server MAY also surface it in `resources/list` so clients can detect its presence, but clients MAY attempt to read it directly without prior discovery. A server whose skill catalog is large, generated on demand, or otherwise unenumerable MAY decline to expose `skill://index.json`, or MAY expose a partial index. Hosts MUST NOT treat an absent or empty index as proof that a server has no skills. The URI `skill://index.json` is reserved and does not conflict with any valid ``: skill names may contain only lowercase letters, digits, and hyphens, so `index.json` cannot be a skill name. -#### Discovery via Resource Templates - -Servers MAY register one or more [resource templates](https://modelcontextprotocol.io/specification/2025-11-25/server/resources#resource-templates) with a `skill://` URI template, enabling hosts to discover the shape of the server's skill namespace and, where the template variables are completable, to enumerate skills interactively: - -```json -{ - "resourceTemplates": [ - { - "uriTemplate": "skill://docs/{product}/SKILL.md", - "name": "Product documentation skill", - "description": "Usage guidance for a named product", - "mimeType": "text/markdown" - }, - { - "uriTemplate": "skill://acme/{domain}/{workflow}/SKILL.md", - "name": "Acme workflow skill", - "description": "Domain-specific workflow instructions" - } - ] -} -``` - -Resource templates are primarily a user-facing discovery mechanism. Hosts SHOULD recognize resource templates whose `uriTemplate` begins with `skill://` as skill discovery points and surface them in the host UI, wiring template variables to the MCP [completion API](https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/completion) so the user can interactively fill in values and browse available skills. The user selects a skill; the host passes the resolved URI into the conversation. - -This mechanism scales to servers with unbounded skill catalogs: the template describes the addressable space without requiring the server to materialize every entry, and completion narrows it as the user types. - #### Pointer from Server Instructions -A server MAY direct the agent to specific `skill://` URIs from its `instructions` field. This requires no discovery machinery on the host; the URI is simply present in the model's context and readable via `resources/read`. +A server MAY direct the agent to specific skill URIs from its `instructions` field. This requires no discovery machinery on the host; the URI is simply present in the model's context and readable via `resources/read`. #### Capability Declaration @@ -213,7 +199,7 @@ The signature shown is illustrative. Including the server name is one disambigua Hosts SHOULD load the frontmatter (`name`, `description`) of available and enabled skills into the model's context so the model can judge relevance and construct a `read_resource` call when a skill applies. Hosts SHOULD surface available skills in their UI for user inspection and per-skill enable/disable, analogous to how tools are typically exposed. -A typical flow: the host reads `skill://index.json` from each connected server and surfaces the `name` and `description` of each entry in the model's context. The model calls `read_resource` with a concrete URI — one returned by enumeration, one handed to it by the user (who may have found it via a `skill://` resource template in the host UI), or one obtained out-of-band — when a skill is relevant to the task. +A typical flow: the host reads `skill://index.json` from each connected server and surfaces the `name` and `description` of each entry in the model's context. The model calls `read_resource` with a concrete URI — one returned by enumeration, one handed to it by the user (who may have resolved it from a template entry in the host UI), or one obtained out-of-band — when a skill is relevant to the task. Because enumeration is optional, a `read_resource` call for a `skill://` URI that the host has never seen listed is normal and expected. The host forwards it to the named server; the server either serves the resource or returns a not-found error. @@ -281,7 +267,7 @@ Constraining the final segment to match the frontmatter `name` gets both propert Requiring every server to expose a complete `skill://index.json` fails for at least three server shapes: a documentation server that synthesizes a skill per API endpoint (thousands), a skill gateway fronting an external index (unbounded), and a server that generates skills from templates parameterized at read time (unenumerable by construction). For these, the list is either too large to be useful in the model's context or does not meaningfully exist. -The baseline is therefore direct readability — a `skill://` URI is always a valid argument to `resources/read`. Enumeration and template discovery are layered on top for servers where they make sense. A host that assumes enumeration is exhaustive will miss skills on servers where it is not, hence the requirement that hosts MUST NOT treat empty enumeration as proof of absence. +The baseline is therefore direct readability — a skill URI is always a valid argument to `resources/read`. The index (concrete entries and templates) is layered on top for servers where it makes sense. A host that assumes enumeration is exhaustive will miss skills on servers where it is not, hence the requirement that hosts MUST NOT treat empty enumeration as proof of absence. ### Why Delegate the Format to agentskills.io? @@ -305,10 +291,10 @@ Will be provided prior to reaching Final status. Skill content is instructional text delivered to a model, which makes it a prompt-injection surface. The Interest Group's position, recorded in [open-questions.md §10](open-questions.md#10-how-should-skills-handle-security-and-trust-boundaries), is: -- **Skill content is untrusted input.** Hosts MUST treat `skill://` resource content as untrusted model input, subject to the same prompt-injection defenses applied to any server-provided text. A server being connected does not make its skill content authoritative. +- **Skill content is untrusted input.** Hosts MUST treat MCP-served skill content as untrusted model input, subject to the same prompt-injection defenses applied to any server-provided text. A server being connected does not make its skill content authoritative. - **Skills do not introduce a new trust tier.** A user who connects a server has already extended their trust boundary to it; a malicious server can do as much harm via tools as via a skill document. Serving skills over MCP adds no risk beyond what skills already carry in any transport — but the defensive posture above applies regardless. - **No implicit local execution.** Hosts MUST NOT honor mechanisms in skill content that would cause local code execution without explicit user opt-in. This includes, non-exhaustively: hook declarations, pre/post-invocation scripts, shell commands embedded in frontmatter, or any field that a filesystem-sourced skill might use to register executable behavior on the host. Hosts MUST either ignore such fields entirely when the skill arrives over MCP, or gate them behind an explicit per-skill user approval that states what will execute and where. Silently executing server-provided code because it appeared in a skill directory is a remote code execution vector. -- **Skills are data, not directives.** Hosts MUST NOT treat `skill://` resources as higher-authority than other context. Explicit user policy governs whether a skill is loaded at all. +- **Skills are data, not directives.** Hosts MUST NOT treat skill resources as higher-authority than other context. Explicit user policy governs whether a skill is loaded at all. - **Provenance and inspection.** Hosts SHOULD indicate which server a skill originates from when presenting it, SHOULD let users inspect a skill's content before it is loaded into model context, and MAY gate loading behind per-skill or per-server user approval. - **Not a third-party marketplace.** This extension is for servers to ship skills that describe their own tools, not for distributing arbitrary third-party content through a connected server. From f9ddc65213c52459a7787ed19c99a446cf01a113 Mon Sep 17 00:00:00 2001 From: Peter Alexander Date: Tue, 7 Apr 2026 17:04:48 +0100 Subject: [PATCH 6/6] Use type:"mcp-resource-template" for template index entries Template entries now reuse the url field with type as the discriminator, rather than a separate urlTemplate field. This is consistent with the upstream schema where type already discriminates how to interpret url (skill-md vs archive). The mcp-resource-template type is namespaced so upstream consumers skip it safely per the existing unrecognized-type rule. --- docs/sep-draft-skills-extension.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/sep-draft-skills-extension.md b/docs/sep-draft-skills-extension.md index c392c28..799c604 100644 --- a/docs/sep-draft-skills-extension.md +++ b/docs/sep-draft-skills-extension.md @@ -97,7 +97,7 @@ On top of that baseline, two discovery mechanisms are defined. A server MAY supp #### Enumeration via `skill://index.json` -A server SHOULD expose a resource at the well-known URI `skill://index.json` whose content is a JSON index of the skills it serves. The index format follows the [Agent Skills well-known URI discovery index](https://agentskills.io/well-known-uri#index-format), with three differences: the `url` field contains a full MCP resource URI (any scheme the server serves), the `digest` field is omitted (integrity is the transport's concern over an authenticated MCP connection), and entries may carry `urlTemplate` in place of `url` to describe a parameterized skill namespace. +A server SHOULD expose a resource at the well-known URI `skill://index.json` whose content is a JSON index of the skills it serves. The index format follows the [Agent Skills well-known URI discovery index](https://agentskills.io/well-known-uri#index-format), with two differences: the `url` field contains a full MCP resource URI (any scheme the server serves), and the `digest` field is omitted (integrity is the transport's concern over an authenticated MCP connection). This binding also defines one additional `type` value, `"mcp-resource-template"`, for entries that describe a parameterized skill namespace. ```json { @@ -116,9 +116,9 @@ A server SHOULD expose a resource at the well-known URI `skill://index.json` who "url": "skill://acme/billing/refunds/SKILL.md" }, { - "type": "skill-md", + "type": "mcp-resource-template", "description": "Per-product documentation skill", - "urlTemplate": "skill://docs/{product}/SKILL.md" + "url": "skill://docs/{product}/SKILL.md" } ] } @@ -130,15 +130,14 @@ Index fields: |---|---|---| | `$schema` | Yes | Schema version URI. Clients SHOULD match against known URIs before processing. | | `skills` | Yes | Array of skill entries. | -| `skills[].type` | Yes | MUST be `"skill-md"` in the MCP context. Archive distribution does not apply; supporting files are individually addressable as resources. | -| `skills[].description` | Yes | For concrete entries, the skill's `description` matching its `SKILL.md` frontmatter. For template entries, a description of the addressable skill space. | -| `skills[].url` | — | The full resource URI of the skill's `SKILL.md`. Exactly one of `url` or `urlTemplate` MUST be present. | -| `skills[].urlTemplate` | — | An [RFC 6570](https://datatracker.ietf.org/doc/html/rfc6570) URI template resolving to `SKILL.md` resource URIs. Exactly one of `url` or `urlTemplate` MUST be present. | -| `skills[].name` | Conditional | Required when `url` is present; matches the `SKILL.md` frontmatter `name` and the final path segment. Omitted when `urlTemplate` is present. | +| `skills[].type` | Yes | MUST be `"skill-md"` or `"mcp-resource-template"`. Archive distribution does not apply; supporting files are individually addressable as resources. | +| `skills[].description` | Yes | For `"skill-md"`, the skill's `description` matching its `SKILL.md` frontmatter. For `"mcp-resource-template"`, a description of the addressable skill space. | +| `skills[].url` | Yes | For `"skill-md"`, the full resource URI of the skill's `SKILL.md`. For `"mcp-resource-template"`, an [RFC 6570](https://datatracker.ietf.org/doc/html/rfc6570) URI template that resolves to `SKILL.md` resource URIs. | +| `skills[].name` | Conditional | Required for `"skill-md"`; matches the `SKILL.md` frontmatter `name` and the final path segment. Omitted for `"mcp-resource-template"`. | Clients SHOULD ignore unrecognized fields and SHOULD skip entries with an unrecognized `type`. -**Template entries** describe a parameterized skill namespace without materializing every entry. A server SHOULD register the same `urlTemplate` as an MCP [resource template](https://modelcontextprotocol.io/specification/2025-11-25/server/resources#resource-templates) so hosts can wire template variables to the [completion API](https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/completion). Hosts SHOULD surface template entries in their UI as interactive discovery points: the user fills in variables via completion, selects a skill, and the host passes the resolved URI into the conversation. This scales to servers with unbounded skill catalogs. +**Template entries** (`type: "mcp-resource-template"`) describe a parameterized skill namespace without materializing every entry. A server SHOULD register the same `url` value as an MCP [resource template](https://modelcontextprotocol.io/specification/2025-11-25/server/resources#resource-templates) so hosts can wire template variables to the [completion API](https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/completion). Hosts SHOULD surface template entries in their UI as interactive discovery points: the user fills in variables via completion, selects a skill, and the host passes the resolved URI into the conversation. This scales to servers with unbounded skill catalogs. The `skill://index.json` resource is served via `resources/read` like any other resource, with `mimeType` of `application/json`. A server MAY also surface it in `resources/list` so clients can detect its presence, but clients MAY attempt to read it directly without prior discovery.