DeepThinking AI

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

Loading a skill, with the verification steps the spec requiresSequence diagram between Host and Server. 1. Host to Server: skills/list. 2. Server to Host: entries with resultType complete, ttlMs, cacheScope. 3. Host to Host: Approve against the manifest, fetching nothing. 4. Host to Server: resources/read (SKILL.md). 5. Server to Host: file content. 6. Host to Host: Verify size, digest and frontmatter, or refuse.HostServerskills/listReturns frontmatter plus a manifest of URIs, digests and sizes.entries with resultType complete, ttlMs, cacheScopeApprove against the manifest, fetching nothingHosts MUST NOT retrieve files ahead of need.resources/read (SKILL.md)file contentVerify size, digest and frontmatter, or refuseContent that fails verification MUST NOT be used.
Show as text
Loading a skill, with the verification steps the spec requires. Sequence diagram between Host and Server. 1. Host to Server: skills/list. 2. Server to Host: entries with resultType complete, ttlMs, cacheScope. 3. Host to Host: Approve against the manifest, fetching nothing. 4. Host to Server: resources/read (SKILL.md). 5. Server to Host: file content. 6. Host to Host: Verify size, digest and frontmatter, or refuse.
#FromToMessage
1HostServerskills/list. Returns frontmatter plus a manifest of URIs, digests and sizes.
2ServerHostentries with resultType complete, ttlMs, cacheScope
3HostHostApprove against the manifest, fetching nothing. Hosts MUST NOT retrieve files ahead of need.
4HostServerresources/read (SKILL.md)
5ServerHostfile content
6HostHostVerify size, digest and frontmatter, or refuse. Content that fails verification MUST NOT be used.
The approval step happens before any file is fetched, which is what makes the manifest the unit of consent rather than the content.

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

What MCP specifies for each content surfaceDiagram: 9 ordered layers. SHA-256 digest per file, verified before use, then Raw byte size per file, verified before use, then Frontmatter compared field by field, then Approval bound to file URIs and digests, then Reads restricted to the retained manifest, then skills only above this line (breakpoint), then Deterministic ordering for cache hits, then ttlMs and cacheScope on list results, then Notification that the list changed.1SHA-256 digest per file, verified before useSkills only. Hosts MUST verify.2Raw byte size per file, verified before useSkills only. Hosts MUST verify.3Frontmatter compared field by fieldSkills only.4Approval bound to file URIs and digestsSkills only. One change revokes it.5Reads restricted to the retained manifestSkills only.skills only above this line6Deterministic ordering for cache hitsBoth, as a SHOULD.7ttlMs and cacheScope on list resultsBoth, since revision 2026-07-28.8Notification that the list changedTools only, and it carries no content.
Show as text
What MCP specifies for each content surface. Diagram: 9 ordered layers. SHA-256 digest per file, verified before use, then Raw byte size per file, verified before use, then Frontmatter compared field by field, then Approval bound to file URIs and digests, then Reads restricted to the retained manifest, then skills only above this line (breakpoint), then Deterministic ordering for cache hits, then ttlMs and cacheScope on list results, then Notification that the list changed.
#LayerNote
1SHA-256 digest per file, verified before useSkills only. Hosts MUST verify.
2Raw byte size per file, verified before useSkills only. Hosts MUST verify.
3Frontmatter compared field by fieldSkills only.
4Approval bound to file URIs and digestsSkills only. One change revokes it.
5Reads restricted to the retained manifestSkills only.
·skills only above this line (breakpoint)
6Deterministic ordering for cache hitsBoth, as a SHOULD.
7ttlMs and cacheScope on list resultsBoth, since revision 2026-07-28.
8Notification that the list changedTools only, and it carries no content.
Everything above the line is required of a host loading a skill. None of it applies to a tool definition, which is the surface almost every MCP deployment already exposes.

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.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

Sources

  1. SEP-2640: Skills Extension (Final)Model Context Protocol · 2026-04-23
  2. Skills: discover and read Agent Skills from MCP serversModel Context Protocol
  3. Tools specificationModel Context Protocol
  4. modelcontextprotocol/ext-skillsModel Context Protocol

mcpagentssecurityprotocols