Does MCP verify tool definitions the way it verifies skills?
AI Architect
Key takeaways
- SEP-2640 requires hosts to verify each skill file's SHA-256 digest and raw byte size before using it.
- Persisted approval binds to the complete set of file URIs and digests, so a changed, added or removed file revokes it.
- The tools specification defines no digest, no manifest and no content binding, only a listChanged notification.
- Skills are a binding over the Resources primitive rather than a fourth primitive, so content still moves over resources/read.
- The strictest integrity rules in MCP now cover its newest surface, while its most deployed surface has none.
SEP-2640 reached Final status and landed in the Model Context Protocol docs on 13 September 2026, letting a server serve Agent Skills over MCP. Most of the attention has gone to the obvious part, which is that servers can now ship workflows next to the tools those workflows drive.
The more interesting part is in the verification rules, and it says something uncomfortable about the rest of the protocol.
What does the spec actually require of a host?
More than any other MCP surface. A host loading a skill has to verify the bytes it receives, and the requirements are written as MUST rather than SHOULD.
A skills/list entry carries a manifest: every file’s URI, its SHA-256 digest
and its raw byte size. The
full specification lives
in its own repository, written by the Skills Over MCP Working Group. Before using any file, a host must restrict reads to
URIs in that retained manifest, verify each file’s size and digest, and parse
SKILL.md frontmatter to compare it field by field against the entry. Content
that fails any of those checks must not be used.
Consent is bound to the same manifest. Persisted approval must cover the complete set of file URIs and digests, and a changed, added or removed file revokes it, with fresh approval required before loading or executing.
Loading a skill, with the verification steps the spec requires
Show as text
| # | From | To | Message |
|---|---|---|---|
| 1 | Host | Server | skills/list. Returns frontmatter plus a manifest of URIs, digests and sizes. |
| 2 | Server | Host | entries with resultType complete, ttlMs, cacheScope |
| 3 | Host | Host | Approve against the manifest, fetching nothing. Hosts MUST NOT retrieve files ahead of need. |
| 4 | Host | Server | resources/read (SKILL.md) |
| 5 | Server | Host | file content |
| 6 | Host | Host | Verify size, digest and frontmatter, or refuse. Content that fails verification MUST NOT be used. |
Why approve before fetching anything?
Because it makes the manifest the unit of consent. Hosts must not retrieve files ahead of need, including on connection, on listing, and on approval, and the spec states that approval binds to the manifest without requiring file retrieval.
The practical effect is that a user can be shown the complete inventory of a skill, every file and its size, before a single byte reaches the model. The familiar alternative is approving a capability and finding out afterwards what it pulled in.
It also removes the quiet trick of shipping an innocuous SKILL.md and swapping
a supporting file later. The digest was recorded at approval, so the swap fails
verification rather than succeeding silently.
How does this compare with tools?
There is nothing to compare. The tools specification defines no digest, no manifest, no byte-size check and no binding between an approval and the content that was approved.
What MCP specifies for each content surface
Show as text
| # | Layer | Note |
|---|---|---|
| 1 | SHA-256 digest per file, verified before use | Skills only. Hosts MUST verify. |
| 2 | Raw byte size per file, verified before use | Skills only. Hosts MUST verify. |
| 3 | Frontmatter compared field by field | Skills only. |
| 4 | Approval bound to file URIs and digests | Skills only. One change revokes it. |
| 5 | Reads restricted to the retained manifest | Skills only. |
| · | skills only above this line (breakpoint) | |
| 6 | Deterministic ordering for cache hits | Both, as a SHOULD. |
| 7 | ttlMs and cacheScope on list results | Both, since revision 2026-07-28. |
| 8 | Notification that the list changed | Tools only, and it carries no content. |
A tool set may change over time. The only signal is an optional
notifications/tools/list_changed, which tells a client that something moved
without saying what, and carries no way to detect a change the server chose not
to announce. On trust, the spec asks clients to treat tool annotations as
untrusted unless they come from a trusted server, which puts the judgement at
the level of the whole server rather than the individual definition.
Both surfaces share the caching attributes added in revision 2026-07-28,
ttlMs and cacheScope, which this site has
written about before. Those describe freshness and
sharing. The skills spec is explicit that they do not provide content integrity.
Should you verify MCP tool definitions yourself?
The protocol has built a careful supply-chain control for its newest and least deployed surface, while the surface sitting in nearly every production MCP client has none. A tool description is text that goes into the model’s context and shapes what it does next, which is the same threat shape the skills rules exist to address.
I do not read this as an oversight. Skills are files from a directory, so a file-integrity model was the natural fit, and retrofitting digests onto tool definitions would break every server that generates them dynamically. The result is still a protocol where the strongest guarantee covers the weakest exposure.
If you run an MCP host, the useful move is to stop treating the skills rules as skills-specific. Recording a hash of each tool definition at approval and re-prompting when it changes is something you can implement yourself today, and it is verification rather than declaration, which is the distinction that actually holds when a server stops behaving.
Do this
Decide whether a capability is a tool, a resource or a skill
The split is not stylistic, because the three surfaces carry different integrity guarantees. Pick on what the agent needs to do, then accept the obligations that come with the choice.
Expose it as a tool when the agent needs an action performed
A tool runs code on the server and returns a result. If the value is in the doing rather than the reading, it is a tool. Accept that the definition carries no integrity guarantee, and that a client can only tell it changed if you send a listChanged notification.
Expose it as a resource when the agent needs to read one thing
A file, a record, a document. No workflow attached, no instructions about how to combine it with anything else. Resources are the substrate the skills extension is built on, so this is also the fallback when a skill is more structure than you need.
Expose it as a skill when the agent needs a procedure
A skill is a directory with a SKILL.md and optional supporting files, useful when a workflow spans several tools or needs reference material. Serving it from the same server keeps the instructions next to the thing they describe.
Declare both capabilities, or clients will not ask
A server supporting skills must declare the resources capability and the io.modelcontextprotocol/skills extension, then implement skills/list and skills/get. Clients issue those calls only after seeing the declaration, so a missing declaration makes your skills invisible rather than broken.
Publish manifests computed from the bytes you actually serve
Every file needs a URI, a SHA-256 digest and a byte size, and the manifest must not be split across pages. A digest computed from a different build than the one you serve fails host verification and the skill refuses to load, which is the correct behaviour and an unpleasant way to discover a packaging bug.
Treat a skill edit as a re-consent event, and keep skills small
Changing one file revokes persisted approval and forces the user to approve again, so churn has a direct human cost. Stay under the 512 file and 16 MiB guidance, and use resources dynamic only when content genuinely has no stable digest.
Frequently asked questions
- Does this make skills safer than tools?
- For content integrity, yes, and only for that. A digest proves the bytes match what the server listed at approval time. It says nothing about whether those bytes are safe. The spec is explicit that digests establish consistency with the manifest rather than trust in the content, and that hosts must treat skill content as untrusted input.
- Is a skill a fourth MCP primitive?
- No. SEP-2640 defines a transport binding over the existing Resources primitive. Servers declare both the resources capability and the io.modelcontextprotocol/skills extension, implement skills/list and skills/get for discovery, and serve every file through ordinary resources/read.
- What happens when a server changes a skill file?
- Approval is revoked. The spec requires persisted approval to bind to the complete set of file URIs and digests, and states that a changed, added or removed file revokes it, with fresh approval required before loading or executing. The host recovers by refreshing the entry with skills/get.
- Can a host preload skill files to reduce latency?
- No. Hosts must not retrieve files ahead of need, including on connection, listing or approval. Approval binds to the manifest without requiring file retrieval, which is what lets a host show a user the full file list before a single byte is fetched.
- Why can a host not treat any skill:// URI as a skill?
- Because identity is the originating server plus the URI, and the scheme is a convention rather than a guarantee. Servers should use skill:// but may use another scheme, and hosts must not identify a resource as a skill solely by its URI scheme. Names are labels and are not unique.