Skills
INFO
This document is part of the Skills extension (io.modelcontextprotocol/skills).
This extension defines how a server serves Agent Skills over MCP using the existing Resources primitive. Each file in a skill directory is exposed as a resource, conventionally under the skill:// URI scheme, and is read with the standard resources/read method. The extension introduces three methods:
skills/list, which enumerates the skills a server serves.skills/get, which returns the entry for a single skill by URI.resources/directory/read(optional), which lists the direct children of a directory resource.
It also defines a Skill entry shape that carries a skill's verbatim frontmatter and a complete manifest of its files with digests.
The skill format itself (directory structure, YAML frontmatter, naming rules, and the progressive-disclosure model) is delegated entirely to the Agent Skills specification. This extension defines only the transport binding.
The Model Context Protocol (MCP) Skills extension allows servers to publish skills alongside the tools, resources, and prompts they already serve. A skill is a directory of files, minimally a SKILL.md, that provides structured workflow instructions to an agent. Skills are addressed by the URI of their SKILL.md and may be read directly whether or not the server enumerates them.
Skills are useful for shipping the instructions for using a server together with the server itself, for workflows too large to fit in server instructions, and for orchestration that spans several tools or servers.
Extension Identifier
This extension is identified as: io.modelcontextprotocol/skills.
Protocol Revision
This page specifies the extension against base protocol revision 2026-07-28 or later. Type names it references without defining (Result, PaginatedRequest, PaginatedResult, CacheableResult, Resource, Cursor) are those of the base schema at that revision.
For brevity, request examples omit _meta. Every request MUST include the required request metadata.
Capability Negotiation
Servers declare support for this extension in the extensions field of their capabilities in server/discover:
// Server capabilities
{
"capabilities": {
"resources": {},
// Other capabilities...
"extensions": {
"io.modelcontextprotocol/skills": {
"directoryRead": true,
},
},
},
}One extension-specific setting is defined:
| Setting | Type | Default | Meaning |
|---|---|---|---|
directoryRead | boolean | false | The server implements resources/directory/read. |
An empty object indicates support for the extension with no optional features.
- A server that declares this extension MUST implement
skills/listandskills/get. - A server that additionally declares
directoryRead: trueMUST implementresources/directory/read. - Clients MUST NOT call
resources/directory/readagainst a server that has not declareddirectoryRead: true. - This extension depends only on the base protocol's Resources primitive. Skill files are served through
resources/read, and the base Resources specification requires any server that supports resources to declare theresourcescapability. A server declaring this extension therefore MUST also declare theresourcescapability.
Clients issue skills/list and skills/get only after observing the server's declaration. To a client that does not implement this extension, skill:// resources are ordinary resources.
Skill Format
A skill served over MCP MUST conform to the Agent Skills specification. In particular:
- A skill is a directory. Its skill name is the value of the
namefield in itsSKILL.mdfrontmatter. - Every skill MUST contain a
SKILL.mdfile at its root. SKILL.mdMUST begin with YAML frontmatter containing at minimum thenameanddescriptionfields 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. In the event that the Agent Skills specification changes in a backwards incompatible way, clients MUST honor any backwards compatibility mechanisms provided by the Agent Skills specification and SHOULD continue to support the Agent Skills specification as it existed prior to any incompatible change.
Resource Mapping
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://<skill-path>/<file-path>where:
<skill-path>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).<file-path>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 addressable as skill://<skill-path>/SKILL.md. The skill's root directory is skill://<skill-path>, that is, the SKILL.md URI with the /SKILL.md suffix removed and no trailing slash (see Directory Resources).
Constraints on <skill-path>:
- The final segment of
<skill-path>MUST equal the skill'snameas declared in itsSKILL.mdfrontmatter. This mirrors the Agent Skills specification's requirement thatnamematch the parent directory name, and means the skill name is always recoverable from the URI alone, without reading frontmatter. - The final segment, being the skill
name, MUST satisfy the Agent Skills specification's naming rules. - 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.mdthe prefix isacme/billingand the skill'snameisrefunds. Inskill://git-workflow/SKILL.mdthere is no prefix and thenameisgit-workflow. - The first segment occupies the URI authority component and SHOULD be a valid
reg-nameper RFC 3986. Any other prefix segments SHOULD be valid URI path segments. No further constraints are imposed on prefix segments. - The authority component carries no special semantics under this extension, and clients MUST NOT attempt DNS or network resolution of it.
- A
SKILL.mdMAY appear in a descendant directory of a skill (skills can nest). See Nested Skills.
Schemes other than skill://:
- A server MAY serve skills under another scheme native to its domain (for example,
github://owner/repo/skills/refunds/SKILL.md). No scheme is privileged. The structural constraints above (<skill-path>ending in the skill name,SKILL.mdexplicit in the URI) apply regardless of scheme, andskills/listenumerates a server's skills regardless of scheme. - Skill identity does not depend on the scheme. A host learns that a resource is a skill in one of two ways: from a
skills/listentry, which is the authoritative record of the skills a server publishes, or from an explicit reference (in the server'sinstructions, in another skill, or from the user) that the host confirms withskills/get. The server answersskills/getfor a skill it serves and returns an error otherwise. This applies toskill://URIs as well as to any other scheme. - A host MUST NOT conclude that a resource is a skill merely because its URI carries a particular scheme.
Examples
| 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 | examples/email.md | skill://acme/billing/refunds/examples/email.md |
Resource Metadata
For each skill://<skill-path>/SKILL.md resource:
mimeTypeSHOULD betext/markdown.nameSHOULD be set from thenamefield of theSKILL.mdYAML frontmatter. By the path constraint above, this equals the final segment of<skill-path>.descriptionSHOULD be set from thedescriptionfield of theSKILL.mdYAML frontmatter.- Servers MAY expose additional frontmatter fields via the resource's
_metaobject. When_metakeys are used for skill resources, implementations SHOULD use theio.modelcontextprotocol.skills/reverse-domain prefix.
Other files in the skill use the mimeType appropriate to their content.
Nested Skills
A skill directory MAY contain further skills in descendant directories. A nested skill is subject to the same rules as any other skill: its directory name is its name, and the enclosing skill's path becomes part of its organizational prefix. The following additional semantics apply:
- Nested content is supporting content. From the enclosing skill's perspective, a nested skill's directory and files are ordinary supporting files. A nested
SKILL.mdread this way is ordinary markdown, and hosts MUST NOT act on its frontmatter. - Activation requires fresh consent. Approval is per skill. Approving a skill approves that skill alone and not any skill nested within it. Activating a nested skill (loading it as a separate skill, whether through the host's skill-loading machinery or by giving effect to its frontmatter) requires fresh, explicit user consent, and approval of the enclosing skill does not substitute for it. Once activated, a nested skill is an ordinary skill and its frontmatter takes effect under the same rules as any other MCP-served skill, including the approval gate on
allowed-tools(see Security Considerations). - Publication is flat. A nested skill is published like any other, through its own
skills/listentry or by explicit reference. The listing remains flat. An entry for a nested skill is an ordinary entry whoseurishares a path prefix with the enclosing skill'suri, and nothing in the listing marks nesting.
Skill Entries
A Skill entry describes one skill. It is returned by both skills/list and skills/get, with identical shape and meaning in each.
/**
* A file belonging to a skill, with the digest and size of its content.
*/
interface SkillResource {
/** Resource URI of the file. */
uri: string;
/**
* SHA-256 digest of the file's raw bytes, formatted as `sha256:{hex}`
* where {hex} is 64 lowercase hexadecimal characters.
*/
digest: string;
/**
* Length in bytes of the file's raw content (the same bytes that `digest` covers).
*/
size: number;
}
/**
* The entry for a single skill.
*/
interface Skill {
/** Resource URI of the skill's SKILL.md, readable via resources/read. */
uri: string;
/**
* The skill's SKILL.md YAML frontmatter, rendered verbatim as a JSON object.
* `name` and `description` are always present; every other field the author
* wrote passes through unchanged.
*/
frontmatter: {
name: string;
description: string;
[key: string]: unknown;
};
/**
* The skill's files: a complete enumeration of SKILL.md and every supporting
* file, or the string "dynamic" when the skill's content is generated such
* that stable digests cannot be published.
*/
resources: SkillResource[] | "dynamic";
}Skill URIs
uri is the full resource URI of the skill's SKILL.md, readable via resources/read. Supporting files are individually addressable as sibling resources under the same skill path, per Resource Mapping. A skill is always retrieved as individually addressable resources. This extension defines no packed or bundled retrieval form.
A skill URI is scoped to the server that serves it. Two connected servers can both serve skill://refunds/SKILL.md, and those are two unrelated skills. The identity of an MCP-served skill is therefore the pair of the host's identity for the originating server and the skill's uri.
- Hosts MUST preserve both halves wherever a skill is recorded or addressed, including the registry, persisted approvals, the cache, and any tool or path through which the model reaches the skill.
- Hosts MUST NOT key any of these on the
urialone. - Any path at which a host materializes skill content, whether a cache directory or a virtual mount, MUST encode the server identity as well as the
uri, so that same-URI skills from different servers land at distinct paths and the originating server is recoverable from the path.
Frontmatter
frontmatter is the skill's SKILL.md YAML frontmatter rendered verbatim as a JSON object. It contains every field the author wrote, not a curated subset. Because the Agent Skills specification requires name and description, those fields are always present. Everything else (license, metadata, fields added by future revisions of the Agent Skills specification) passes through unchanged. A host can therefore build its skill registry from entries alone, without fetching each SKILL.md.
- The
frontmatterobject MUST be identical in content to the frontmatter of theSKILL.mdit describes. - The final
<skill-path>segment of the entry'suriMUST equalfrontmatter.name, per Resource Mapping. - Within the frontmatter
metadataobject, keys prefixed withio.modelcontextprotocol/are reserved for metadata defined by MCP extensions. This extension currently defines no such keys. Implementations SHOULD ignore keys under this prefix that they do not recognize.
Names
A skill's name is a label, not an identifier. A skill is identified by its uri within a server, and by the pair of server identity and uri across servers (Skill URIs). Two skills at different paths may share a final segment (acme/billing/refunds and acme/support/refunds are both named refunds), and a nested skill may share its name with a top-level one.
- Within a server's listing, names SHOULD be unique, but they are not guaranteed to be. Hosts MUST NOT assume name uniqueness.
- When two entries in one listing collide on
name, hosts MUST disambiguate them (for example by their distinguishing path segments) rather than silently discarding or preferring one. - When skills from different origins collide on
name, hosts MUST resolve the name within a per-origin namespace, identifying servers by a host-assigned label. - An MCP-served skill MUST NOT silently shadow, or be silently substituted for, a same-named skill from any other origin, whether another server or the host's own filesystem skills. See Security Considerations.
Resources
resources is REQUIRED on every skill entry and takes one of two forms: an array of SkillResource objects enumerating the skill's files (SKILL.md and every supporting file), or the string "dynamic". The array is the unit of content that a host verifies and that a user's approval binds to.
- When
resourcesis an array, it MUST be complete. It lists every file of the skill, each exactly once, including an entry whoseuriequals the skill's top-leveluri. That entry carries the digest and size ofSKILL.mditself. - Each
uriMUST be the skill'sSKILL.mdor a file within the skill's directory. - Each entry MUST carry
size, the length in bytes of the file's raw content (the same bytes thedigestcovers). A read whose byte length differs from the entry'ssizeis a verification failure equivalent to a digest mismatch (Integrity and Verification), whether or not the host goes on to compute the digest. - Completeness extends to nested skills. From the enclosing skill's perspective their files are supporting files (Nested Skills), so the enclosing skill's
resourceslists them too, and the same file may appear in both the enclosing and the nested skill's entries. A change to a nested skill is therefore a change to the enclosing skill's set. - When a skill's content is generated dynamically, such that stable digests cannot be published, the server MUST set
resourcesto the string"dynamic"instead of an array. An entry with noresourcesat all, or with any value other than an array or"dynamic", is invalid, and hosts MUST NOT load it. A skill whoseresourcesis"dynamic"offers no content integrity and cannot be content-bound (Security Considerations). Hosts MAY decline to load such skills, and server authors SHOULD expect that some hosts will.
Limits
This extension fixes two per-skill limits so that servers know what every conforming host will accept and hosts know what they must be prepared to handle:
| Limit | Value | Counted over |
|---|---|---|
| Resources per skill | 512 entries | The entries of the skill's resources, SKILL.md included |
| Total file size per skill | 16 MiB (16,777,216 bytes) | The sum of size over the skill's resources |
- Hosts MUST support skills up to and including these limits, and MAY support larger ones.
- Servers SHOULD NOT serve a skill that exceeds either limit. A skill that does is not guaranteed to be loadable by any conforming host.
- Because
resourcesis complete, both limits are checkable from the entry alone before the host retrieves any file. A host that declines a skill on this basis SHOULD tell the user why rather than fail silently on a later read. - For a skill whose
resourcesis"dynamic", the entry offers nothing to count. A host that chooses to load such a skill applies the total-size limit to what it actually retrieves and MAY stop loading the skill once that limit is reached.
These limits bound a host's exposure to a single skill. They do not limit how many skills a server may serve or a host must accept, and a listing may be arbitrarily large.
Listing Skills
A server declaring this extension MUST implement the skills/list method, which returns entries for the skills it serves. This operation supports pagination.
Request
interface ListSkillsRequest extends PaginatedRequest {
method: "skills/list";
}{
"jsonrpc": "2.0",
"id": 4,
"method": "skills/list",
"params": {}
}Response
interface ListSkillsResult extends PaginatedResult, CacheableResult {
skills: Skill[];
}{
"jsonrpc": "2.0",
"id": 4,
"result": {
"resultType": "complete",
"skills": [
{
"uri": "skill://git-workflow/SKILL.md",
"frontmatter": {
"name": "git-workflow",
"description": "Follow this team's Git conventions for branching and commits"
},
"resources": [
{
"uri": "skill://git-workflow/SKILL.md",
"digest": "sha256:b95a384300adeea2d902f7d19cd7c04b378ef58e09759107b9c7db4dcacbaa25",
"size": 190
}
]
},
{
"uri": "skill://acme/billing/refunds/SKILL.md",
"frontmatter": {
"name": "refunds",
"description": "Process customer refund requests per company policy",
"license": "Apache-2.0"
},
"resources": [
{
"uri": "skill://acme/billing/refunds/SKILL.md",
"digest": "sha256:ae7bc7e45f44a6381977ef1f772cbad6e38d8ec78903ea7b87abb373815a8f89",
"size": 175
},
{
"uri": "skill://acme/billing/refunds/examples/email.md",
"digest": "sha256:a724fa5ed3b9e39c0e731fe1f0e866eb46d23969af25ecf0d5f41982e3e36bea",
"size": 58
}
]
},
{
"uri": "skill://reports/daily/SKILL.md",
"frontmatter": {
"name": "daily",
"description": "Assemble today's operational report from live data"
},
"resources": "dynamic"
}
],
"ttlMs": 300000,
"cacheScope": "public"
}
}Semantics:
- The
resultTypefield MUST be set to"complete"onListSkillsResult, as it is the standard result shape for theskills/listrequest. - The result MAY be empty. A server whose skill catalog is large, generated on demand, or otherwise unenumerable MAY return an empty or partial listing.
- Hosts MUST NOT treat an empty or partial listing as proof that a server has no skills, and MUST support loading a skill given only its URI (Getting a Skill).
- Pagination mirrors the base protocol's list methods: the request accepts an optional
cursor, and when the result includesnextCursorthe client passes it back to retrieve the next page. An entry is atomic, and a skill'sresourcesset is never split across pages. ListSkillsResultextendsCacheableResult, sottlMsandcacheScopeare REQUIRED, as they are ontools/listandresources/list, and carry the same semantics. They are a freshness hint and a cache-scope marker for the listing, not an integrity property. Integrity and Verification governs content regardless of how fresh a cached listing is.- The method serves entries for a server's skills regardless of URI scheme.
A skills/list entry is a complete manifest of the skill rather than a summary. After paging through the listing, a host has everything it needs to build its registry, present a skill for approval, bind the approval to content, and verify every file it later reads. A host does not need to call skills/get to complete a listed entry.
Getting a Skill
A server declaring this extension MUST implement the skills/get method, which returns the entry for a single skill named by the URI of its SKILL.md.
Request
interface GetSkillRequest extends Request {
method: "skills/get";
params: {
/** URI of the skill's SKILL.md. */
uri: string;
};
}{
"jsonrpc": "2.0",
"id": 5,
"method": "skills/get",
"params": {
"uri": "skill://pdf-processing/SKILL.md"
}
}Response
interface GetSkillResult extends CacheableResult {
skill: Skill;
}{
"jsonrpc": "2.0",
"id": 5,
"result": {
"resultType": "complete",
"skill": {
"uri": "skill://pdf-processing/SKILL.md",
"frontmatter": {
"name": "pdf-processing",
"description": "Extract, fill, and assemble PDF documents"
},
"resources": [
{
"uri": "skill://pdf-processing/SKILL.md",
"digest": "sha256:99b737495721155ece826d57521e2d66141ebdc1344a400487481ea2642ab19e",
"size": 151
},
{
"uri": "skill://pdf-processing/templates/invoice.md",
"digest": "sha256:61f4ea6d2c75fde1b4977219e7e3107d491c3c26aefb6686e84d6281c088d9ee",
"size": 29
},
{
"uri": "skill://pdf-processing/templates/purchase-order.md",
"digest": "sha256:f2ff774b1737ff3dec81c47946f9976f18a1a9f69dda0a81f22eabd95173c158",
"size": 35
}
]
},
"ttlMs": 300000,
"cacheScope": "public"
}
}The skill object is a Skill entry, identical in shape and meaning to an entry of skills/list, under the same rules.
Semantics:
- The
resultTypefield MUST be set to"complete"onGetSkillResult, as it is the standard result shape for theskills/getrequest. params.uriMUST be the URI of a skill'sSKILL.md.- If the URI does not identify a skill the server serves, the server MUST return error
-32602(Invalid params), the same coderesources/readuses for unknown resources. - A server MUST answer for every skill it serves, whether or not that skill appears in its
skills/listresult. A skill absent from a partial listing is still retrievable by URI. - The result is a point-in-time snapshot, as a listing entry is. A host re-calls the method to refresh one skill's digests without re-enumerating the catalog.
GetSkillResultextendsCacheableResult, sottlMsandcacheScopeare REQUIRED, as they are onresources/read, and carry the same semantics.ttlMsis the server's hint for how long a host may treat the entry as current before re-callingskills/get. Neither field is an integrity property.- A skill whose content is generated dynamically carries
"resources": "dynamic", per Resources, whether it is reached throughskills/listorskills/get. - The result carries no pagination cursor.
skills/get complements direct reading. A URI alone is enough to read a skill via resources/read, and skills/get returns the metadata and digests for that same URI, so a skill that never appeared in a listing can still be verified and content-bound (Security Considerations).
Pointer from Server Instructions
A server MAY direct the agent to specific skill URIs from its instructions. This requires no discovery machinery on the host. The URI is present in the model's context, and the host can confirm it with skills/get and read it with resources/read.
Reading Skill Content
Skill files are read via the standard resources/read method. No skill-specific read semantics are defined.
Reading a SKILL.md via resources/read does not by itself activate the skill. resources/read is transport. It returns bytes to whatever asked for them, whether a generic resource-reading tool, a resource browser, or a user inspecting the server. A skill is activated only by the host's own skill-loading path, which verifies the content against the skill's entry (Integrity and Verification), applies any required user approval (Security Considerations), and opens the window in which the host is acting on the skill.
- Hosts MUST NOT treat a
resources/readof aSKILL.mdthat arrives by any other route as a load. Such a read grants no approval, opens no acting window, and confers no standing on the skill's supporting files. - Content obtained that way is ordinary resource content, and a host that returns it to the model SHOULD do so as it would any other resource read, not as a loaded skill.
- A host that wants such a read to load the skill routes it through the skill-loading path instead.
Relative References
Internal references within a skill (for example, 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, as a filesystem path would resolve. For example, references/GUIDE.md in skill://acme/billing/refunds/SKILL.md resolves to skill://acme/billing/refunds/references/GUIDE.md. The skill's root is the directory containing SKILL.md, not the scheme root. When skills nest, each SKILL.md's references resolve against its own directory, so a relative reference in a nested skill's SKILL.md resolves against the nested skill's root regardless of how the file was reached.
Integrity and Verification
Digests are SHA-256 hashes of a file's raw bytes, formatted as sha256:{hex} where {hex} is 64 lowercase hexadecimal characters. Each SkillResource in a skill's resources carries the digest of the file at its uri.
Verification on Read
- When a host retrieves a file listed in a skill's
resources, it MUST verify the content against that entry'sdigestandsize. - A mismatch means the content is not what the entry described. It may be corrupted, tampered with, or stale because the skill was updated after the entry was fetched. In all cases, hosts MUST NOT use the unverified content.
- To recover from staleness, the host calls
skills/getfor that skill (orskills/listto refresh the catalog) and proceeds from the currentresourcesset. Because that set differs, any content-bound approval is revoked (Security Considerations).
The Acting Window and the Held Entry
A host is acting on a skill from the moment it loads the skill's SKILL.md into the model's context until, at the earliest, that SKILL.md leaves context. Throughout that window the host holds the entry from which it loaded the skill.
- Hosts MAY hold the window open longer but not shorter.
- Because
resourcesis complete, an unlisted file is a change to the skill. While acting on a skill, a host MUST resolve reads of the skill's files only to URIs listed in the held entry'sresources. - A host MUST treat a read of an unlisted file within the skill as a verification failure equivalent to a digest mismatch.
Frontmatter Verification
- After fetching a
SKILL.mdfor which the host holds an entry (digest-verified when the entry'sresourcesis an array, unverifiable when it is"dynamic"), hosts MUST parse its YAML frontmatter and compare it field-by-field against the entry'sfrontmatter. - Any discrepancy MUST be treated as a verification failure equivalent to a digest mismatch, and the skill MUST NOT be loaded.
This enforces the Frontmatter identity requirement on the host side, so that what a user approves from the entry is what the model receives.
Lazy Retrieval
- Hosts MUST NOT retrieve a skill's files ahead of need, whether on connection, on listing, or at approval. A
SKILL.mdis fetched when the skill is loaded, and a supporting file when it is read. - Hosts SHOULD cache what they do retrieve. A cached file whose digest matches the current entry can be served without fetching it again, and one whose digest does not match must be fetched again. The requirements on a disk cache are in Security Considerations.
Lazy retrieval is compatible with content-bound approval, which binds to the entry's resources set rather than to retrieved bytes. A file fetched long after approval is verified against that set when it is read.
Digests Are Not a Trust Anchor
Digests are unsigned and supplied by the same server that supplies the content. A match proves the two are consistent, not that either is trustworthy. Any intermediary on the path, such as a gateway, can rewrite both the entry and the content together.
- Hosts MUST NOT treat a digest match as a security boundary.
Reading Directories
A skill's instructions frequently reference a directory rather than a file, for example "pick the appropriate template from templates/" or "run the matching script in scripts/". To act on this, the agent must learn what the directory contains. resources/list enumerates the server's entire resource space rather than a subtree, and servers with large or generated catalogs may not implement meaningful global listing at all. This extension therefore defines the resources/directory/read method, gated behind the directoryRead capability setting.
Directory Resources
A directory resource is a resource whose mimeType is inode/directory. In a skill namespace served as individual files, every directory level is a directory resource: the skill root (skill://pdf-processing) and each subdirectory (skill://pdf-processing/templates). Directory URIs are written without a trailing slash. Directory resources need not appear in resources/list, and are addressable whether listed or not.
Request
interface ReadResourceDirectoryRequest extends PaginatedRequest {
method: "resources/directory/read";
params: {
/** URI of the directory resource to read. */
uri: string;
cursor?: Cursor;
};
}{
"jsonrpc": "2.0",
"id": 7,
"method": "resources/directory/read",
"params": {
"uri": "skill://pdf-processing/templates"
}
}Response
interface ReadResourceDirectoryResult extends PaginatedResult {
/** Resource metadata of the directory's direct children. */
resources: Resource[];
}{
"jsonrpc": "2.0",
"id": 7,
"result": {
"resultType": "complete",
"resources": [
{
"uri": "skill://pdf-processing/templates/invoice.md",
"name": "invoice.md",
"mimeType": "text/markdown"
},
{
"uri": "skill://pdf-processing/templates/purchase-order.md",
"name": "purchase-order.md",
"mimeType": "text/markdown"
},
{
"uri": "skill://pdf-processing/templates/regional",
"name": "regional",
"mimeType": "inode/directory"
}
]
}
}The resultType field MUST be set to "complete" on ReadResourceDirectoryResult, as it is the standard result shape for the resources/directory/read request.
Semantics:
- The method applies only to directory resources. If the URI does not exist, or exists but is not a directory resource, the server MUST return error
-32602(Invalid params). - The result contains every direct child of the directory. Files carry their ordinary
Resourcemetadata and subdirectories are listed as directory resources (mimeType: "inode/directory"). The listing is not recursive, and clients descend by calling the method again on a child directory. - An empty directory yields an empty
resourcesarray. - Pagination mirrors
resources/list. When the result includesnextCursor, the client passes it back ascursorto retrieve the next page. - A server that declares
directoryReadMUST support the method for every directory within the skill namespaces it serves as individual files. - The method itself is not skill-specific, and a server MAY support it on any directory resource it serves, under any scheme.
Directory Reads and the Held Entry
For a skill whose entry carries a resources array, the host already holds a complete manifest of the skill's files, and a directory read adds nothing about that skill's contents. When a host acting on such a skill wants to know what templates/ contains, it MAY answer from the entry alone. Directory reading is useful for dynamically generated skills (whose resources is "dynamic"), for resource trees that are not skills at all, and for obtaining the server's current view of a directory without first refreshing the entry.
The two views can disagree. If the server adds a file to a skill after the host obtained its entry, a directory read may list that file while the held manifest does not. This is the stale-snapshot case that Integrity and Verification governs:
- While acting on the skill under the held entry, the host MUST NOT read the newly listed child (an unlisted file is a verification failure) and MUST NOT surface it to the model as a file of the skill.
- To reach it, the host refreshes the entry with
skills/get, at which point theresourcesset has changed and any persisted content-bound approval is revoked and must be obtained again. - Hosts SHOULD present this sequence as a skill that has changed and needs re-approval, rather than as a read error.
- Conversely, a child present in the manifest but absent from a directory read is a file the server no longer serves. A read of it will fail, and the same refresh applies.
- Hosts MUST NOT treat the directory result as extending the manifest. This extension defines no shared version or cache token that would let a host determine whether a directory result and an entry describe the same snapshot of the server. The manifest is authoritative for what the host may read under its current approval. A directory read is a live observation that may be ahead of or behind it.
For a dynamically generated skill, a directory read is the only way to discover the skill's files, but it does not provide the content integrity that the entry lacks.
Example Message Flow
Consider a host connected to a server it labels docs-server, which declares the extension with directoryRead: true. The host builds its skill registry by listing:
{
"jsonrpc": "2.0",
"id": 2,
"method": "skills/list",
"params": {}
}{
"jsonrpc": "2.0",
"id": 2,
"result": {
"resultType": "complete",
"skills": [
{
"uri": "skill://pdf-processing/SKILL.md",
"frontmatter": {
"name": "pdf-processing",
"description": "Extract, fill, and assemble PDF documents"
},
"resources": [
{
"uri": "skill://pdf-processing/SKILL.md",
"digest": "sha256:99b737495721155ece826d57521e2d66141ebdc1344a400487481ea2642ab19e",
"size": 151
},
{
"uri": "skill://pdf-processing/templates/invoice.md",
"digest": "sha256:61f4ea6d2c75fde1b4977219e7e3107d491c3c26aefb6686e84d6281c088d9ee",
"size": 29
},
{
"uri": "skill://pdf-processing/templates/purchase-order.md",
"digest": "sha256:f2ff774b1737ff3dec81c47946f9976f18a1a9f69dda0a81f22eabd95173c158",
"size": 35
}
]
}
],
"ttlMs": 300000,
"cacheScope": "public"
}
}The supporting files in this example contain the following UTF-8 text, each ending with a newline. Their sizes and SHA-256 digests match the manifest above.
invoice.md:
# Invoice
Customer:
Amount:purchase-order.md:
# Purchase order
Supplier:
Items:The host records the entry under the identity (docs-server, skill://pdf-processing/SKILL.md), surfaces the skill's name, description, and origin to the model and the user, and fetches nothing further.
Later the model asks to load the skill. The host obtains user approval, binding it to the three {uri, digest} pairs above, then reads SKILL.md from docs-server:
{
"jsonrpc": "2.0",
"id": 3,
"method": "resources/read",
"params": {
"uri": "skill://pdf-processing/SKILL.md"
}
}{
"jsonrpc": "2.0",
"id": 3,
"result": {
"resultType": "complete",
"contents": [
{
"uri": "skill://pdf-processing/SKILL.md",
"mimeType": "text/markdown",
"text": "---\nname: pdf-processing\ndescription: Extract, fill, and assemble PDF documents\n---\n\n# PDF processing\n\nChoose the matching template from `templates/`.\n"
}
],
"ttlMs": 300000,
"cacheScope": "public"
}
}The host checks that the content is 151 bytes and matches the manifest's SHA-256 digest, parses the frontmatter and confirms it equals the entry's frontmatter, then places the content in the model's context tagged as originating from docs-server. The host is now acting on the skill and holds this entry.
The instructions reference templates/. The model lists the directory, and the host routes this to docs-server:
{
"jsonrpc": "2.0",
"id": 4,
"method": "resources/directory/read",
"params": {
"uri": "skill://pdf-processing/templates"
}
}{
"jsonrpc": "2.0",
"id": 4,
"result": {
"resultType": "complete",
"resources": [
{
"uri": "skill://pdf-processing/templates/invoice.md",
"name": "invoice.md",
"mimeType": "text/markdown"
},
{
"uri": "skill://pdf-processing/templates/purchase-order.md",
"name": "purchase-order.md",
"mimeType": "text/markdown"
},
{
"uri": "skill://pdf-processing/templates/credit-note.md",
"name": "credit-note.md",
"mimeType": "text/markdown"
}
]
}
}credit-note.md is not in the held entry's resources, because the server added it after the listing. The host does not surface it as a file of the skill and would treat a read of it as a verification failure. The model reads invoice.md, which is listed. The host issues resources/read, verifies size and digest against the held entry, and returns the content.
The newly added credit-note.md contains this UTF-8 text, ending with a newline:
# Credit note
Invoice:
Credit amount:To make credit-note.md available, the host refreshes the entry:
{
"jsonrpc": "2.0",
"id": 6,
"method": "skills/get",
"params": {
"uri": "skill://pdf-processing/SKILL.md"
}
}{
"jsonrpc": "2.0",
"id": 6,
"result": {
"resultType": "complete",
"skill": {
"uri": "skill://pdf-processing/SKILL.md",
"frontmatter": {
"name": "pdf-processing",
"description": "Extract, fill, and assemble PDF documents"
},
"resources": [
{
"uri": "skill://pdf-processing/SKILL.md",
"digest": "sha256:99b737495721155ece826d57521e2d66141ebdc1344a400487481ea2642ab19e",
"size": 151
},
{
"uri": "skill://pdf-processing/templates/invoice.md",
"digest": "sha256:61f4ea6d2c75fde1b4977219e7e3107d491c3c26aefb6686e84d6281c088d9ee",
"size": 29
},
{
"uri": "skill://pdf-processing/templates/purchase-order.md",
"digest": "sha256:f2ff774b1737ff3dec81c47946f9976f18a1a9f69dda0a81f22eabd95173c158",
"size": 35
},
{
"uri": "skill://pdf-processing/templates/credit-note.md",
"digest": "sha256:766bffa8d4908ce897e1727ca22e4bf0fa796620b35218ce2132a124545626f1",
"size": 39
}
]
},
"ttlMs": 300000,
"cacheScope": "public"
}
}The resources set differs from the one the user approved, so the prior approval is revoked. The host presents the skill as changed, obtains fresh approval bound to the new set, and only then reads credit-note.md under the refreshed entry.
Error Handling
Servers MUST return standard JSON-RPC errors for the following protocol error cases:
skills/getwith aurithat does not identify a skill the server serves:-32602(Invalid params).resources/directory/readwith aurithat does not exist or is not a directory resource:-32602(Invalid params).resources/readof a skill file the server does not serve:-32602(Invalid params), per the base Resources specification.- Internal errors:
-32603(Internal error).
A server that has not declared directoryRead: true is not required to recognize resources/directory/read and responds as the base protocol specifies for an unknown method.
Servers SHOULD provide informative error messages to describe the cause of errors.
Example: unknown skill
{
"jsonrpc": "2.0",
"id": 5,
"error": {
"code": -32602,
"message": "No skill is served at skill://acme/billing/chargebacks/SKILL.md"
}
}Example: not a directory
{
"jsonrpc": "2.0",
"id": 7,
"error": {
"code": -32602,
"message": "skill://pdf-processing/SKILL.md is not a directory resource"
}
}Verification failures (a digest or size mismatch, a frontmatter discrepancy, or a read of an unlisted file while acting on a skill) are host-side conditions rather than protocol errors. They are governed by Integrity and Verification. The only resulting wire traffic is the skills/get or skills/list call a host makes to refresh the entry.
Reservations
- The
skills/method prefix is reserved for this extension. - The method name
resources/directory/readis defined by this extension. - The label
io.modelcontextprotocol/skillsis reserved for this extension. - The
_metakey prefixio.modelcontextprotocol.skills/is reserved for this extension on skill resources. - Within
SKILL.mdfrontmattermetadata, keys prefixedio.modelcontextprotocol/are reserved for metadata defined by MCP extensions.
Security Considerations
Skill content is instructional text delivered to a model, which makes it a prompt-injection surface. Unlike a remote tool call, an MCP-served skill can place server-authored bytes on the host and direct the model to execute them with host-side tools. This extension imposes the following requirements.
- 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.
- Hosts MUST treat MCP-served skills as a higher-risk surface than remote tool invocation.
- Origin is visible to the model.
- Hosts MUST tag MCP-served skill content with its originating server identity at the point it enters model context.
- Hosts MUST NOT present an MCP-served skill to the model as indistinguishable from a local filesystem skill.
- No implicit local execution. Hosts MUST NOT allow MCP-served skill content to cause host-side code execution without explicit per-skill user approval. This covers (a) declarative fields the host parses (hooks, frontmatter scripts) and (b) instructions in the skill body that direct the model to invoke any host code-execution tool, whether to run a script bundled in the skill or to run an arbitrary command the skill specifies.
- Hosts MUST ignore or approval-gate (a).
- Hosts MUST apply the same approval gate to code-execution tool calls issued while the model is acting on an MCP-served skill.
- Origin-scoped resource reads. A model-callable resource-read surface is a cross-server confused-deputy vector when driven by untrusted skill content.
- Hosts MUST bind such reads to the skill's originating server. A skill served by server A MUST NOT cause a
resources/readagainst server B. - Hosts MUST identify servers by a host-assigned label, not the server's self-reported
serverInfo.name. - Any cross-origin read MUST be gated behind explicit per-call user approval naming both servers.
- Hosts MUST bind such reads to the skill's originating server. A skill served by server A MUST NOT cause a
- Name collisions are an impersonation surface. Skill names are not unique across origins, and a malicious server can publish a skill under the name of a popular one. A name binds to whatever bytes its origin currently serves and carries no authorship or endorsement.
- Hosts MUST resolve skill names within a per-origin namespace, identifying servers by a host-assigned label.
- Hosts MUST NOT let an MCP-served skill silently shadow, replace, or intercept invocations of a same-named skill from any other origin, including the host's filesystem skills.
- Hosts SHOULD surface collisions to the user.
- Intermediaries MAY attach provenance or verification annotations via
_metaunder their own reverse-domain prefix, not theio.modelcontextprotocol.skills/prefix reserved for this extension. This extension assigns such annotations no semantics.
- No implicit permission grants. A remote server populating
allowed-toolsis requesting elevated access on the host, not declaring a property of its own environment.- Hosts MUST NOT honor frontmatter fields that widen the model's tool or filesystem permissions when the skill arrives over MCP.
- In particular, the Agent Skills
allowed-toolsfield MUST be ignored for MCP-origin skills unless the user has explicitly approved that grant for that skill. - Approval of a skill never extends to the frontmatter of any other
SKILL.mdwithin its file space. A nested skill'sallowed-toolshas no effect unless that nested skill is itself activated under its own approval (Nested Skills).
- 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.
- Nested skill consent. Approval is per skill. Approving a skill does not approve skills nested within it. Activating a nested
SKILL.mdrequires fresh, explicit user consent, per Nested Skills. - Provenance and inspection.
- Hosts SHOULD indicate which server a skill originates from when presenting it.
- Hosts SHOULD let users inspect a skill's content before it is loaded into model context.
- Hosts MAY gate loading behind per-skill or per-server user approval.
- Digests are not a security boundary. Entry digests are unsigned and come from the same server as the content. They confirm consistency between the entry and what was fetched, as described in Integrity and Verification, but they cannot establish trust in the content, defend against the server itself, or detect an intermediary that rewrites both together.
- Content-bound approval.
- When a host persists any per-skill user approval, it MUST be bound to the entry's
resourcesset (everyurianddigest) observed at the moment of approval. - If a subsequent entry for that skill, from
skills/listorskills/get, advertises a different set, whether a file was rotated, added, or removed, the host MUST treat the prior approval as revoked and re-prompt before loading or executing. - A host need not poll for changes. While it is acting on the skill, content that has changed fails verification when read, and if it fetches a fresh entry, the rule above revokes the approval.
- A skill whose
resourcesis"dynamic"cannot be content-bound. Hosts MAY decline to load it, and MUST NOT treat a persisted approval as covering whatever content the server currently serves.
- When a host persists any per-skill user approval, it MUST be bound to the entry's
- Cache integrity, cache isolation, and durable origin. A cache is a second copy of content that was verified once, and the verification does not carry over to bytes that may have changed since. Cached bytes do not acquire filesystem-skill trust by being stored locally.
- Hosts SHOULD cache verified skill content locally, populated on demand as files are read rather than in bulk.
- Hosts that cache skill content on disk MUST do one of the following for every file served from the cache. Comparing a stored digest label or a modification time is not verification.
- Keep the cache where only the host can write to it (not the model, scripts or tools the model runs, or other users of the machine) and never modify a cached file in place.
- Recompute the file's SHA-256 digest from the cached bytes on each access and compare it against the entry's digest, treating a mismatch as a mismatch on a fresh read.
- Hosts that cache MCP-served skill content on disk MUST do so in a location excluded from every filesystem-skill discovery path.
- Hosts MUST treat content loaded from that location as having arrived over MCP for all purposes of the no-implicit-local-execution rule above, including after host restart and after the originating server is disconnected.
- Hosts SHOULD remove a server's cached skill content when the user removes that server.