Conversation
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.
- 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
Outdated
|
|
||
| The resource for the skill's required `SKILL.md` is therefore always addressable as `skill://<skill-path>/SKILL.md`, and the skill's root directory is the URI obtained by stripping the trailing `SKILL.md`. | ||
|
|
||
| The `<skill-path>` 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: |
There was a problem hiding this comment.
This is a bit odd that the skill name doesn't have to match the skill path, given the skill URI is used to access the resource.
There was a problem hiding this comment.
This is fair, originally they did match, but we wanted to support nested skills (a request from github), e.g. skill://foo/bar/code-review/SKILL.md and skill names cannot contain / so you're either forced to not have nested skills, or replace the / with :. You could perhaps use the last path segment as the skill name (code-review). wdyt @SamMorrowDrums
There was a problem hiding this comment.
Last path segment as name seems totally reasonable to me. You cannot assume all servers are going to be able to be to find skills in certain places if you cannot provide the completions.
That would rule out skill discovery via resource templates entirely. Which is a valid approach, but it doesn't feel complex enough of an idea to reject.
Why shouldn't the spec let somebody install a skill from a known repo this way for example? GH server cannot enumerate them all.
The main alternative we discussed still has this problem, which is resource links could be returned from tools providing skill search but still need paths.
|
|
||
| - `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. |
There was a problem hiding this comment.
nit: Why SHOULD vs MUST? Is there a potential that you might have a description that doesn't match the frontmatter that a user could load that would be deceptively?
There was a problem hiding this comment.
I could be convinced. I think if we say MUST then we need to decide what to do when they don't match. Is that an error and you can't use the skill? If it is an error, it feels like a bit of an unnecessary footgun. If it's not an error, is the MUST accomplishing anything?
There was a problem hiding this comment.
I don't we gain anything by enforcing a mimeType, and we add compatible with patterns like zipped skills if we don't. Clients will still validate skills. I think SHOULD serves the purpose. It goes for all resources that they should have the correct mimeType for what they actually are.
| "inputSchema": { | ||
| "type": "object", | ||
| "properties": { | ||
| "server": { "type": "string", "description": "Name of the connected MCP server" }, |
There was a problem hiding this comment.
AFAIK, it's atypical for the client to expose the server names to the agent.
The way this is handled for tools, is server names are prefixed only if there is a conflict. Would it be better to follow this standard and only expose resource names, and prefix server name if a conflict occurs?
There was a problem hiding this comment.
FWIW, this section is just guidelines and clients are free to expose resource reading in whatever way they find appropriate. The intent was to just guide people to consider that URIs could conflict, so you need some server disambiguation. I could make that clearer. Your suggestion is also fine.
There was a problem hiding this comment.
@kurtisvg This used to be atypical, but I've noticed that with many clients prefixing server names to tools, the models will infer the name of the server quite often - even if it is not explicitly stated.
As for resource reading - they differ from tools in that that aliasing via name-spacing is awkward, so in many cases a client-side list resource tool will include the server name, as otherwise resolving a resource name conflict is impossible.
So I would agree if this was about tools, where server names are very rarely explicitly stated, but for resources it seems the pattern is to expose server names. At least in the agents I'm most familiar with.
docs/sep-draft-skills-extension.md
Outdated
|
|
||
| ### 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). |
There was a problem hiding this comment.
My 2c is it feels like there's more complexity being added by the use of resources for everything vs and a new primitive. (I also think that 1 open issue is not necessarily "community pushback").
E.g. using resources as the distribution mechanism, we lose the ability to have resources that are used for other things being included in a skill. We also have to list every file in skill individually, before the skill is even activated (which is very verbose). There are also the conflicts with how resources are used in existing applications today.
In contrast, a new primitive is clear and unambiguous in it's intent, and could include non-file objects such as tools, resources, and prompts.
There was a problem hiding this comment.
My 2c is it feels like there's more complexity being added by the use of resources for everything vs and a new primitive. (I also think that 1 open issue is not necessarily "community pushback").
I agree that 1 issue is sparse evidence on its own, but the sentiment behind it seems common.
E.g. using resources as the distribution mechanism, we lose the ability to have resources that are used for other things being included in a skill.
I'm not sure this follows? The skill:// URI scheme scopes skill content specifically. A server can still expose other resources under any other URI scheme (file://, db://, etc.), and skills can reference those as dependencies in their frontmatter or content. The skill is a resource and the things it orchestrates like tools, other resources, prompts are still separate and fully available.
There are also the conflicts with how resources are used in existing applications today.
Could you elaborate on which specific conflicts you're seeing? it seems like structured markdown context fits naturally within modeling other entities like databases, ui views, repos, etc. The skill:// URI scheme exists to scope skill content away from other resource usage.
In contrast, a new primitive is clear and unambiguous in it's intent, and could include non-file objects such as tools, resources, and prompts.
A skill referencing tools, resources, and prompts as dependencies seems like it would work the same way regardless of whether the skill itself is delivered as a resource or a new primitive. The SKILL.md frontmatter declares what the skill needs and the host mediates availability. The transport mechanism for the skill content doesn't seem like it would change this.
Also noting a couple of the MCP design principles that seem especially relevant here:
-
Composability over specificity: "MCP provides foundational primitives: resources, tools, prompts, and tasks. We don't add protocol features for use cases that can be constructed from these existing building blocks." Skills are structured context for language models, which seems like exactly what resources are designed to deliver.
-
Standardization over innovation: "MCP standardizes patterns that have already proven valuable. We look for conventions that work across multiple implementations and codify them, rather than inventing new paradigms." Multiple implementations have independently referenced
skill://resources, and it seems like skills are commonly used because they're just files (a.k.a. simple resources) and not an abstract concept.
I think the bar for introducing a new primitive should be demonstrating something that resources genuinely can't do based on evidence in real implementations. Part of this proposal allows for experimenting with resources to be more accessible in general, for example by suggesting common client tools to interact with them. It also allows clients to follow progressive disclosure patterns and prioritize resources using existing annotations (which follows the other unique properties of skills). If there are specific capabilities we think require a new primitive, would love to dig into those concretely.
The previous draft fully decoupled <skill-path> 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 <skill-path> 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
Outdated
|
|
||
| On top of that baseline, three discovery mechanisms are defined. A server MAY support any combination. | ||
|
|
||
| #### Enumeration via `resources/list` |
There was a problem hiding this comment.
Should we have a initialize as well which is called on server initialize where the client would know what this Skills MCP server is about and what it contains?
Example, I might have a 3 Skills MCP servers included and which server brings which skills would be important without loading all the list of skills
There was a problem hiding this comment.
I don't think we should tie this explicitly to connection initialization (I assume that is what you reference). Tools also leave it up to the client when to do this. Having primitives enumerated on server initialized isn't done for any other primitives.
This would also be in conflict with stateless MCP where there are no connections. Enumeration should be a host-design decision. (in practice it often happens after initializing the connection, but it shouldn't have to)
docs/sep-draft-skills-extension.md
Outdated
|
|
||
| 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. | ||
|
|
||
| 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. |
There was a problem hiding this comment.
the host calls
resources/list(uri="skill://")on each connected server at initialization and surfaces any returned skill entries in the model's context.
Isn't this causing a lot of bloat for the LLM that it would read all the skills even though its not required? Like for a question about git-workflows the LLM would only want to list git-workflows and not skills for acme workflow
There was a problem hiding this comment.
The results of the list call aren't put into context as-is, the frontmatter is. Most hosts would make it possible to enable/disable skills - similar to tools. And the frontmatter is required for a model to know if a skill is relevant to load, so if it is not in the frontmatter it cannot be accessed at all - regardless of relevance, unless it done in a non-skill like way (ie direct resource reads without progressive disclosure).
There was a problem hiding this comment.
Got it. I am curious to know how would use this in practice when we want to wrap a stateless agent with MCP servers. Example: I have build a marketing agent which has access to Facebook skills and tools + Youtube Skills and tools. When a question comes in about facebook marketing, how would the agent know to only get facebook skills and tools into the context and not anything else without know which MCP server is for what without reading the tools description. The way that it works right now is that agents call the initialization here to know the description of the MCP server to know what this server does.
But I am curious if this can be solved differently. :) thank you for your insights
|
|
||
| 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 |
There was a problem hiding this comment.
Should we include a standard response format to share what dependencies and scopes that might be required to run this skill?
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"contents": [
{
"uri": "file:///project/src/main.py",
"mimeType": "text/x-python",
"dependencies": [
{
"name": "requests",
"version": ">=2.0.0",
"description": "Used to make HTTP requests to external APIs such as GitHub"
}
],
"scopes": [
{
"name": "github:repo:read",
"description": "Allows reading repository metadata and contents from GitHub"
}
],
"text": "# Example: Fetch repository details from GitHub API\n\nimport requests\n\nrepo = \"octocat/Hello-World\"\nurl = f\"https://api.github.com/repos/{repo}\"\n\nresponse = requests.get(url)\nif response.status_code == 200:\n data = response.json()\n print(f\"Repo: {data['full_name']}\")\n print(f\"Stars: {data['stargazers_count']}\")\nelse:\n print(\"Failed to fetch repository data\")\n"
}
]
}
}
It might add new optional primitives to the MCP spec for resources. But it might be good to add them?
docs/sep-draft-skills-extension.md
Outdated
|
|
||
| ## 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. |
There was a problem hiding this comment.
Suggest changing directory to folder to match agentskills.io verbiage.
|
|
||
| > 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 |
There was a problem hiding this comment.
I think we should mention that the skill format has design that facilitates progressive disclosure, whether this is implemented and if so, how, is up to the client host.
I think we should use client host over agent to match general MCP verbiage. I could be mistaken, but I don't think we use agent elsewhere to describe client host? (It might actually be a good idea, though - as client and client host are so often conflated).
|
|
||
| ### 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: |
There was a problem hiding this comment.
I think we need to mention frontmatter loading if we begin to give guidance on implementation.
Something like
Hosts SHOULD load the frontmatter of all available and enabled tools into model context in an implementation-specific manner, so that the model has the server and URI information to be able call the exposed tool when a skill is relevant.
Hosts SHOULD make expose the available tools to the user so they can be inspected and enabled/disabled in a similar manner to tools.
|
I think a security guidance section for client hosts would be good. Skills are high risk in that they are context injection. Users should as a minimum be able to inspect skills from connected servers if the host loads them into context / makes them available to the model. In some cases HITL approval before even making the skills available is advisably. Malicious skills are very common, and while connecting to an MCP server is always a high-trust action, I think we should make an effort to mitigate unsafe use of skills as that is currently happening a lot in the wild with npm based skill distribution. |
docs/sep-draft-skills-extension.md
Outdated
|
|
||
| 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. |
There was a problem hiding this comment.
| - 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 under the same `skill://` root. The skill directory is the boundary; skills do not nest inside other skills. |
There was a problem hiding this comment.
I took the meaning, but still, this line felt less concise than it should be.
docs/sep-draft-skills-extension.md
Outdated
|
|
||
| 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. |
There was a problem hiding this comment.
| - **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. | |
| - **Trust inherits from the server.** A user who connects a server has already extended their trust boundary to it; a malicious server can cause as much harm via tools as via a skill document. Skills as a class, whether served by MCP or any other agent affordance, have an inherent prompt injection risk. No additional risk from serving them as MCP resources has been identified. |
There was a problem hiding this comment.
The claim of tools posing more of a risk than skills seems hard to substantiate; skills literally tell the model how to behave.
IMO, it's best to not downplay the risk but to make it clear that Skills over MCP isn't adding any new risk to what already exists with skills.
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
|
Updated to use a |
Pre-submission Extensions Track SEP defining the
skill://resource convention.Summary
Skills are MCP Resources following the Agent Skills spec. Each file in a skill directory is exposed under
skill://<skill-path>/<file-path>;SKILL.mdis always explicit in the URI. The skill format itself (YAML frontmatter, naming, directory layout, progressive disclosure) is delegated entirely to agentskills.io — this SEP is a transport binding only.Key design decisions
name.<skill-path>may be nested (acme/billing/refunds) but the last segment is the skill name, mirroring agentskills.io's parent-directory rule. Prefix segments are the server's organizational choice. The name is recoverable from the URI alone.skill://URI is always valid forresources/readwhether or not it appears in any index. Enumeration and templates are layered on top.skill://index.json. Optional well-known resource whose format mirrors the Agent Skills discovery index — same$schema, sameskills[]shape.urlholds the fullskill://URI;digestis omitted. Servers with large/generated/unenumerable catalogs are not required to expose it.resources/list.Security
Skill content MUST be treated as untrusted model input. Hosts MUST NOT honor local-execution mechanisms (hooks, pre/post scripts, shell-in-frontmatter) from MCP-served skills without explicit per-skill user opt-in — silently executing server-provided code is an RCE vector. Hosts SHOULD let users inspect skill content before loading.
Implementation guidelines
read_resource(server, uri)tool for model-driven loading (signature illustrative; prefix-on-conflict or other disambiguation is fine).@server.skill(path)decorator,client.list_skills(),client.read_skill_uri().Extension identifier:
io.modelcontextprotocol/skills.