Model Context Protocol (MCP) standards
Criteria verified as of August 2026. Re-verify on the web before committing to anything (§8).
1. Scope and triggers
Applies when designing, implementing, auditing or operating MCP servers and clients, and when
deciding whether MCP is even the right integration. Covers: the host/client/server model; the
primitives (tools, resources, prompts) and their status in the current revision; transports
(stdio and Streamable HTTP); the design of a server's tool surface;
authorisation (OAuth 2.1 as a resource server, RFC 9728, RFC 8707, CIMD); the class of risk
introduced by a third-party server running with your permissions; and operational governance
(inventory, versioning, updating, observability).
Triggers by artifact: mcp.json, .mcp.json, claude_desktop_config.json, server.json,
@modelcontextprotocol/sdk, mcp (PyPI), FastMCP, go-sdk/csharp-sdk,
tools/list, tools/call, resources/read, prompts/get, server/discover,
subscriptions/listen, inputRequests/resultType, Mcp-Method/Mcp-Name headers,
WWW-Authenticate with resource_metadata, /.well-known/oauth-protected-resource,
mcp-scan, "MCP server", "tool poisoning", "rug pull".
Governing principle: an MCP server is not an API. An API is consumed by a program that
validates the contract; an MCP server is consumed by a model that reads text and decides. The
tool's description is attack surface and is the functional specification.
Designing an MCP server as if it were a REST wrapper produces servers that are useless
(too many tools, gigantic outputs, opaque errors) and insecure.
Not applicable: see
claude-api (the concrete implementation on the Anthropic side: the Messages API's MCP
connector, mcp_servers + mcp_toolset, MCP in Managed Agents with vaults and mcp_oauth
credentials, the anthropic.lib.tools.mcp helpers, model IDs, effort, caching — all of that
is theirs; here we have the protocol and the design criteria, provider-agnostic);
ai-agents-standards (the autonomous loop, the iteration budget,
context management, multi-agent, the lethal trifecta — MCP is a mechanism for giving tools
to an agent, not the only one, and an MCP server is consumed from many hosts that are not your own
agents; the boundary is on the client side: if you are deciding what the server exposes
and how it is authorised, it is this skill; if you are deciding how the agent chooses, iterates and
stops, it is theirs);
claude-code-skills-standards (the context format for agents: SKILL.md, frontmatter,
activation — a relevant boundary, because skills and MCP are two different ways of giving
capability to an agent: a skill injects instructions, an MCP server exposes execution;
a skill does not execute anything by itself);
api-design-standards (a boundary that gets confused daily: OpenAPI/GraphQL/gRPC, HTTP
codes, pagination, versioning of the contract of an API consumed by a program; if the consumer
is deterministic, it is theirs);
identity-access-management-standards (IdP design: OAuth 2.1/OIDC flows, PKCE,
token issuance and validation, authorisation engines — the use of those flows in the
MCP protocol belongs to this skill);
secrets-management-standards (custody and rotation of the credentials MCP servers
consume), cryptography-pki-standards (TLS, artifact signing);
appsec-standards (classic vulnerability classes: SSRF, path traversal, command
injection — which is exactly what turns up in MCP server CVEs; the triage is theirs),
vulnerability-management-standards (the CVE/EPSS/KEV lifecycle of the installed servers),
container-runtime-security-standards (sandboxing the local server: seccomp, capabilities,
rootless), firewall-policy-standards (egress of the server and of the host),
observability-standards (OpenTelemetry: MCP documents traceparent propagation in
_meta, but the telemetry design is theirs),
detection-engineering-standards (detection rules over that telemetry),
incident-response-forensics-standards (responding to a compromised server),
offensive-security-standards (authorised offensive assessment of a server),
python-standards/typescript-standards (the idiom of the SDK's language),
cicd-standards (the pipeline that publishes and signs the server),
privacy-engineering-standards / grc-compliance-standards (personal data and governance).
Also: llm-app-engineering-standards (the single-turn LLM app or deterministic
pipeline — prompting, structured output, context window, cost per request).
Plus: rag-standards, llm-evaluation-standards, mlsecops-standards,
ai-governance-standards.
2. Default decisions
Verify the current revision on the web before committing to anything (§8). This protocol changes
by dated revision and the 2026-07-28 one broke big things: the data below expire.
| Decision |
Default |
Reason / alternative |
| Protocol revision |
2026-07-28 (final, published 28-Jul-2026; supersedes 2025-11-25) |
The versions are YYYY-MM-DD dates marking the last breaking change. Pin the revision explicitly; not "the latest" |
| Local transport |
stdio |
A child process of the host; no open port, no network surface. The default for every server running on the user's machine |
| Remote transport |
Streamable HTTP |
The original HTTP+SSE has been deprecated since 2025-03-26 and reclassified as Deprecated under the lifecycle policy in 2026-07-28. It is not implemented in new code |
| Server state |
Stateless |
2026-07-28 removes protocol sessions and the Mcp-Session-Id header; state between calls is carried in explicit handles minted by the server and passed as a tool argument |
| MCP server or a normal function? |
A normal function if it is one in-house integration consumed by one in-house host |
MCP solves M×N → M+N. With M=1 and N=1 it only adds a process, a transport, attack surface and a translation layer |
| Remote authorisation |
OAuth 2.1 with PKCE (S256); the MCP server is only a resource server |
Never issue tokens from the MCP server. RFC 9728 (protected resource metadata) + RFC 8707 (resource) mandatory |
| OAuth client registration |
Client ID Metadata Documents (CIMD) |
Dynamic Client Registration (RFC 7591) is deprecated in 2026-07-28; it dropped from SHOULD to MAY in 2025-11-25. DCR only for compatibility with ASes that do not support CIMD |
| Number of tools per server |
Few and task-oriented (single digits, not dozens) |
Every definition takes up context on every turn and competes for the model's attention. Exposing a whole API is the most common antipattern |
| Schemas |
A strict inputSchema with additionalProperties: false, explicit required and enum where applicable |
The model fills in whatever the schema allows. A lax schema is an invitation to malformed calls |
| Tool output |
Bounded and paginated; a hard size limit on the server |
A tool that returns 200 KB poisons the host's context and ruins the prompt cache |
| SDK |
Tier 1: TypeScript, Python, C#, Go |
Tier 2: Java, Rust, Ruby. Tier 3: Swift, PHP, Kotlin. Verify the tier table before committing to a language |
| Server registry |
The official registry in preview, not GA |
registry.modelcontextprotocol.io still warns of possible breaking changes and data resets. It is not a chain of trust: it does not validate security. Use an internal/curated registry for production |
| Installing third-party servers |
Audit + pin the version by digest |
An MCP server is arbitrary execution with your permissions (§5) |
Primitives and their status (revision 2026-07-28)
Who controls what is half of the design:
| Primitive |
Who controls it |
Status |
Tools (tools/list, tools/call) |
The model decides to invoke it |
Active. It is 90% of what gets built |
Resources (resources/list, resources/read) |
The application contributes them to the context |
Active. resources/subscribe/unsubscribe replaced by subscriptions/listen |
Prompts (prompts/list, prompts/get) |
The user chooses them (menu, slash command) |
Active. Little adopted by clients: verify host support before relying on them |
Sampling (sampling/createMessage) |
Server → client |
DEPRECATED in 2026-07-28. Suggested migration: integrate directly with the LLM provider's API |
Roots (roots/list) |
Server → client |
DEPRECATED. Migration: pass directories/files as tool parameters, resource URIs or server configuration |
Logging (logging/setLevel) |
Server → client |
DEPRECATED. Migration: stderr on stdio, or OpenTelemetry |
| Elicitation |
Server → client |
Replaced by the MRTR pattern (Multi Round-Trip Requests): the server returns resultType: "input_required" with inputRequests, and the client retries the original request with inputResponses |
Design consequence: do not build anything new on sampling, roots or logging —
they keep working during the deprecation window (a minimum of 12 months under the lifecycle
policy), but they are debt from day one. If a design "needs" sampling, almost
always what it needs is for the host to make the call to the model.
3. Structure and conventions
Designing the tool surface
- One tool = one user task, not one endpoint.
create_issue_with_labels is
better than POST /issues + POST /issues/{id}/labels exposed separately: fewer turns,
fewer intermediate states, fewer opportunities for error.
- The description says when to call it, not just what it does. "Query the status of a
deployment. Use it when the user asks whether a change is already in production or why
a release failed; do not use it to list historical deployments — for that,
list_deploys."
Purely declarative descriptions produce under-invocation in some models and
over-invocation in others.
- Stable names with a namespace of their own (
acme_deploy_status). Name collisions
between servers are the way in for shadowing (§5).
- A deterministic order in
tools/list: the current revision recommends returning the
tools in a stable order so the client can cache and improve the hit rate of the model's
prompt cache. A random order (iterating a set, an unordered dict) invalidates
the cache on every turn.
- Errors the model can recover from: actionable text, not a stack trace or a
500 Internal Server Error. "The repository x/y does not exist or you do not have access. Check
the name or use list_repos." The model retries well with a message like that and loops
with an opaque one.
- Outputs bounded by design: cursor pagination, explicit and announced truncation
("showing 20 of 431; use
cursor to continue"), and field projection. Never
return the source system's complete object "just in case".
- Idempotency and effects: mark in the description which tools mutate state and which do
not; the host uses that distinction to parallelise the read ones and to ask for approval on the
write ones.
Configuration file and publishing
- Server entries in
mcp.json / .mcp.json / the host's configuration: a pinned version
(image digest or exact package version), never latest and never a branch.
server.json for publishing to the registry: metadata and installation instructions; the
artifacts still live in npm/PyPI/OCI, with the supply chain of those registries
(and their risks — §5).
- Version the server with SemVer and declare the supported protocol revision. Changing
the schema or the semantics of an existing tool is a breaking change for the
model even if the JSON still validates.
What is new in 2026-07-28 that affects the code
- There is no
initialize/notifications/initialized handshake: every request carries the protocol
version and the client's capabilities in _meta.
server/discover is mandatory on the server, to announce supported versions,
capabilities and identity.
- The
Mcp-Method and Mcp-Name headers are mandatory on POST over Streamable HTTP — they let
gateways, rate limiters and WAFs route and measure without parsing the body. The server rejects
requests where the header and the body disagree.
ttlMs and cacheScope (public/private) are mandatory in the results of tools/list,
prompts/list, resources/list, resources/read and resources/templates/list.
- SSE stream resumption (
Last-Event-ID) is removed: a broken stream loses the in-flight
request and the client must reissue it with a new ID — which demands real idempotency
in the write tools.
resultType is mandatory in every result ("complete" or "input_required").
- Tasks moves from experimental core to an official extension (
io.modelcontextprotocol/tasks).
4. Quality and gates
Gates in increasing order of cost. The ones marked [BLOCKS] break the build or the deployment.
- [BLOCKS] Schema validation: every
inputSchema with additionalProperties: false
and explicit required. A test that walks tools/list and verifies it.
- [BLOCKS] Output budget: a test that exercises each tool with the most
voluminous reasonable input and fails if the response exceeds the set limit (choose one and
document it; the useful order of magnitude is a few thousand tokens, not hundreds of thousands).
- [BLOCKS] No token passthrough: a test that sends the server a token whose
aud is not
the server and checks that it is rejected. The specification forbids it with an explicit
MUST NOT: "MCP servers MUST NOT accept any tokens that were not explicitly issued for
the MCP server."
- [BLOCKS] Remote authorisation:
/.well-known/oauth-protected-resource (RFC 9728)
served and correct; audience validation; PKCE S256; validation of the iss parameter in
the authorisation response (RFC 9207) before exchanging the code.
- [BLOCKS] SCA + artifact scanning of the server and of its transitive dependencies.
- Protocol conformance:
server/discover responds; the Mcp-Method/Mcp-Name headers
verified against the body; resultType present; ttlMs/cacheScope present.
tools/list determinism: a test that calls twice and compares the order byte by byte.
- Edge and error testing: invalid input, non-existent resource, permission denied,
source system timeout — each returns an actionable error, not a dump.
- Testing with a real model: a server can be correct and still be useless. Run
a set of end-to-end tasks and measure the task success rate, not
API coverage. If the model picks the wrong tool, the defect is in the
description, not in the model.
- Description auditing (
mcp-scan or equivalent) over the servers you
install: detection of embedded instructions and of overlap between servers.
- Pinning definitions: hash each tool definition on approving it and alert
when it changes (a direct mitigation of the rug pull, §5).
5. Security — the critical section
Premise: an MCP server is third-party code running with your permissions. A local
server is a binary you execute; a remote one is a service you hand context and
credentials to. The specification is explicit: without sandboxing and consent, one-click
installation allows arbitrary code execution with the client's privileges, and it warns
that "Users have no insight into what commands are being executed."
Everything that follows is a risk class, an indicator and a mitigation. Nothing here is an
exploitation procedure.
Risk classes specific to MCP
| Class |
What it is |
Indicator |
Mitigation |
| Tool poisoning |
Instructions for the model hidden in the description, the schema or the result of a tool. The user sees a short name; the model reads the full text and obeys it. The tool does not need to be invoked: it is enough for it to be loaded in context |
Disproportionately long descriptions, imperative text addressed to the assistant, invisible or control characters, references to other tools or to the user's files |
Human review of every description before approval; automated scanning; render the full description in the approval UI, untruncated |
| Rug pull |
The server changes the description after you trusted it. Most clients do not warn about the change |
A definition hash different from the approved one |
Pin the version by digest; hash definitions and fail closed on a change; explicit re-approval |
| Cross-server shadowing |
A malicious server's description alters the agent's behaviour with tools from another, trusted server. Combined with a rug pull, it hijacks without appearing in the visible log |
Colliding tool names; a description that mentions other servers' tools |
Per-server namespaces; isolate servers by trust level; do not mix third-party servers with tools over sensitive data in the same session |
| Confused deputy |
An MCP proxy with a static client_id before the third-party AS, dynamic client registration and a consent cookie allows obtaining authorisation codes bypassing the user's consent |
An MCP proxy that does not store consent per client_id |
The specification requires it: "MCP proxy servers MUST implement per-client consent" — a register of user-approved client_ids, checked before forwarding to the third-party AS; a redirect_uri validated by exact match; a single-use state created only after consent is approved |
| Token passthrough |
The server accepts and forwards tokens not issued for it |
Absence of aud validation |
The MUST NOT of §4.3; RFC 8707 resource in the authorisation and token requests |
| State handle hijacking |
With the stateless protocol, whoever guesses or obtains a handle accesses another user's state |
Sequential or predictable handles |
"MCP servers MUST NOT treat possession of a state handle as authentication." Securely random handles, bound to the authenticated user on the server side (<user_id>:<handle>), with expiry |
| SSRF in the client |
The malicious server publishes OAuth discovery URLs pointing at 169.254.169.254, localhost or private ranges |
Client requests to internal IPs |
Require HTTPS, block private/reserved/link-local ranges, validate redirect destinations, an egress proxy. Do not implement the IP validation by hand — the encoding tricks (octal, hex, IPv4-mapped IPv6) get through |
| Dangerous URL scheme |
A javascript:, data:, file: authorisation URL from the server → XSS/RCE in the client |
— |
Allowlist http(loopback)/https; never open URLs via a shell |
| Supply chain compromise |
A trojanised server published in a registry with accounts and personas created to give an appearance of legitimacy; the official registry is not a chain of trust and is still in preview |
A new package, a maintainer with no history, no verifiable repository |
An internal curated registry; code review; digest pinning; SBOM and signing; an inventory of what is installed |
Hard rules
- FORBIDDEN to install a third-party MCP server without auditing it: code, dependencies,
maintainer and the permissions it asks for. It is the same decision as installing a binary.
- stdio by default for local servers; if there is a local HTTP transport, require an
authorisation token or a unix socket with restricted permissions. A local server listening on
localhost with no auth is reachable by DNS rebinding from the browser.
- Sandboxing the local server: a container or a platform sandbox, a filesystem
restricted to the necessary directories, no network beyond the indispensable, non-root. The
specification lists it as a client SHOULD; treat it as a requirement of your own.
- Least privilege in the server's credentials: a token with the task's scope, not
the administrator's. The specification explicitly discourages omnibus scopes
(
*, all, full-access) and publishing the full catalogue in scopes_supported.
- Informed consent, per sensitive action, not an "allow everything" at install time: the
user must see the exact command untruncated, what is executed and with what privileges. A
dialogue that truncates the tool's description turns consent into theatre.
- Never put secrets in descriptions, prompts, resources or results: they end up in the
model's context, in the history and potentially in logs and summaries.
- The server cannot trust that the client applies any mitigation: it validates at its
own edge.
The reality of adoption (context, not an excuse)
Authorisation adoption in public MCP servers is low —in the order of single-digit
percentages according to ecosystem analyses in 2026, and a significant fraction of the
registered servers offer no effective authentication. Operational translation: assume any
public server is unauthenticated and badly maintained until proven otherwise.
The volume of CVEs against MCP implementations during 2026 is high, and the dominant classes
are classic ones —path traversal, command injection, missing authentication on a sibling
endpoint— not exotic ones: see appsec-standards for the triage.
6. Performance and operability
- A mandatory inventory of MCP servers installed per host and per user: origin,
pinned version, credentials it consumes, permissions it holds, who approved it and when.
Without an inventory there is no incident response and no vulnerability management. Shadow MCP
—servers installed outside change control— is the most common governance failure.
- Observability of invocations: which tool, from which server, with which arguments
(with the sensitive ones redacted), what result, what latency, what token cost. The
current revision documents W3C/OpenTelemetry trace context propagation in
_meta
(traceparent, tracestate, baggage): use it to correlate the model's call with
the execution on the server and with the request to the source system.
- Caching: honour
ttlMs and cacheScope; cacheScope: "private" is never cached in a
shared intermediary. A tools/list with an unstable order breaks the host's prompt cache
and makes every turn more expensive.
- Context budget: a server's cost is not just its latency; it is the tokens
its definitions occupy on every turn. Measure that cost and prune tools that are not
used.
- Stateless by design (
2026-07-28): a remote server must be able to run behind a
round-robin load balancer with no sticky sessions. If yours needs affinity, the state is
badly modelled.
- Timeouts and limits on every call to the source system; degradation with an actionable error
instead of hanging the model's turn.
- Updating: a defined cadence, the changelog read (not applied blindly — an update is a
rug pull vector), and re-approval when tool definitions change.
7. Sustainability and prohibitions
- Review cadence: this ecosystem moves by dated revision with a minimum deprecation
window of 12 months. Review the protocol revision and the deprecations every
quarter, not every year.
- The server's own deprecation policy: do not break the semantics of an existing tool;
add a new one and mark the old one. The "consumer" is a model with prompts and
evaluations built on top.
FORBIDDEN
- ❌ Standing up an MCP server for one in-house integration consumed by one in-house host: it is a function.
- ❌ Exposing a whole API as MCP tools, endpoint by endpoint.
- ❌ Tool descriptions that only say what the tool does and not when to use it.
- ❌ Lax schemas: no
additionalProperties: false, no required, free string where an enum fits.
- ❌ Tools with unbounded output.
- ❌ Opaque errors (
500, a stack trace) returned to the model.
- ❌ Implementing HTTP+SSE in new code (deprecated since
2025-03-26).
- ❌ Building on sampling, roots or logging: deprecated in
2026-07-28.
- ❌ Letting the MCP server act as an authorization server or issue tokens.
- ❌ Accepting or forwarding tokens not issued for the server (the specification's MUST NOT).
- ❌ Treating possession of a state handle as authentication.
- ❌ Dynamic Client Registration in new code: use CIMD.
- ❌ Installing third-party servers without auditing them, or from unverified registries.
- ❌
latest / a branch / an unpinned package in a server's configuration.
- ❌ A local server with an HTTP transport and no authentication.
- ❌ Running a local server without a sandbox and with broad filesystem access.
- ❌ A consent dialogue that truncates the description or the command: it is security theatre.
- ❌ Secrets in descriptions, prompts, resources or results.
- ❌ Treating the official registry as a chain of trust or as GA.
- ❌ Accepting a server update without reviewing changes to the tool definitions.
- ❌ Trusting that the client applies the mitigations: the server validates at its edge.
8. Mandatory web verification
Before committing to any version, field name, primitive or normative requirement:
- The specification's current revision (
modelcontextprotocol.io/specification/...) and its
changelog: the versions are dates and the 2026-07-28 one removed sessions, the handshake,
ping, logging/setLevel and stream resumption. Check whether there is a later one.
- The register of deprecated features (
/specification/<rev>/deprecated) and the lifecycle
policy: sampling, roots and logging are in the deprecation window — confirm whether they have
already been removed.
- The authorisation specification: it has been revised several times. Confirm the status of
RFC 9728, RFC 8707, PKCE S256,
iss validation (RFC 9207) and the exact status of CIMD
versus DCR.
- The Security Best Practices page of the current revision: it is the normative source of the
MUSTs/MUST NOTs cited in §5. Quote verbatim any requirement that decides something.
- The SDK tier table (
/docs/sdk and /community/sdk-tiers): the tiers change.
- The status of the official registry: still in preview as of August 2026 — verify whether it has
reached GA and what guarantees it gives.
- CVEs and incidents in the specific servers you are going to install (not in "MCP" in the
abstract): NVD/GHSA per package, plus the maintainer's history.
- The status of the extensions (
tasks, MCP Apps) and of neighbouring projects (A2A under the
Linux Foundation) if the design depends on them.
Declared gaps (not verified in this drafting)
- Exact CVE figures and specific vulnerability IDs for MCP servers in 2026: they are
described as a class and an aggregate volume from secondary sources; no IDs or CVSS scores are
fixed here. Verify in NVD/GHSA before citing any.
- The exact percentage of public servers with OAuth implemented and the size of the registry:
a secondary-source datum, order of magnitude only.
- The detail of the
io.modelcontextprotocol/tasks extension and of MCP Apps: not verified in
depth; consult the extensions documentation before designing on them.
- The status of
mcp-scan and other description-auditing tools: it is cited as a
category; its current maintenance has not been verified.
- OWASP's "MCP Top 10": mentioned by secondary sources as a separate project; not
verified against OWASP's primary source.
If the web contradicts this document, the web wins — flag the discrepancy.
1---2name: mcp-standards3description: Model Context Protocol server and client engineering. Use when building or auditing an MCP server or client with the official SDKs (modelcontextprotocol typescript-sdk, python-sdk, go-sdk, csharp-sdk, FastMCP), declaring tools/resources/prompts primitives, choosing stdio versus Streamable HTTP transport, protocol-revision fields (server/discover, _meta, Mcp-Method/Mcp-Name headers, resultType, MRTR inputRequests, ttlMs/cacheScope), mcp.json / .mcp.json / claude_desktop_config.json server entries, server.json and the MCP registry, MCP authorization (RFC 9728 protected resource metadata, RFC 8707 resource indicators, Client ID Metadata Documents, PKCE S256), or triaging tool poisoning, rug pull, server shadowing, token passthrough and confused-deputy exposure in installed servers.4---56# Model Context Protocol (MCP) standards78Criteria verified as of **August 2026**. Re-verify on the web before committing to anything (§8).910## 1. Scope and triggers1112Applies when **designing, implementing, auditing or operating MCP servers and clients**, and when13deciding whether MCP is even the right integration. Covers: the host/client/server model; the14primitives (`tools`, `resources`, `prompts`) and their status in the current revision; transports15(stdio and Streamable HTTP); the design of a server's tool surface;16authorisation (OAuth 2.1 as a *resource server*, RFC 9728, RFC 8707, CIMD); the class of risk17introduced by a third-party server running with your permissions; and operational governance18(inventory, versioning, updating, observability).1920Triggers by artifact: `mcp.json`, `.mcp.json`, `claude_desktop_config.json`, `server.json`,21`@modelcontextprotocol/sdk`, `mcp` (PyPI), `FastMCP`, `go-sdk`/`csharp-sdk`,22`tools/list`, `tools/call`, `resources/read`, `prompts/get`, `server/discover`,23`subscriptions/listen`, `inputRequests`/`resultType`, `Mcp-Method`/`Mcp-Name` headers,24`WWW-Authenticate` with `resource_metadata`, `/.well-known/oauth-protected-resource`,25`mcp-scan`, "MCP server", "tool poisoning", "rug pull".2627**Governing principle**: **an MCP server is not an API**. An API is consumed by a program that28validates the contract; an MCP server is consumed by a model that reads text and decides. The29tool's description **is** attack surface and **is** the functional specification.30Designing an MCP server as if it were a REST wrapper produces servers that are useless31(too many tools, gigantic outputs, opaque errors) and insecure.3233**Not applicable**: see34`claude-api` (**the concrete implementation on the Anthropic side**: the Messages API's MCP35connector, `mcp_servers` + `mcp_toolset`, MCP in Managed Agents with vaults and `mcp_oauth`36credentials, the `anthropic.lib.tools.mcp` helpers, model IDs, `effort`, caching — all of that37is **theirs**; here we have the protocol and the design criteria, provider-agnostic);38`ai-agents-standards` (the autonomous loop, the iteration budget,39context management, multi-agent, the lethal trifecta — MCP is *a* mechanism for giving tools40to an agent, not the only one, and an MCP server is consumed from many hosts that are not your own41agents; the boundary is on the client side: **if you are deciding what the server exposes42and how it is authorised, it is this skill; if you are deciding how the agent chooses, iterates and43stops, it is theirs**);44`claude-code-skills-standards` (the context format for agents: `SKILL.md`, frontmatter,45activation — **a relevant boundary**, because skills and MCP are two different ways of giving46capability to an agent: a skill injects *instructions*, an MCP server exposes *execution*;47a skill does not execute anything by itself);48`api-design-standards` (**a boundary that gets confused daily**: OpenAPI/GraphQL/gRPC, HTTP49codes, pagination, versioning of the contract of an API consumed by a program; if the consumer50is deterministic, it is theirs);51`identity-access-management-standards` (**IdP design**: OAuth 2.1/OIDC flows, PKCE,52token issuance and validation, authorisation engines — the *use* of those flows in the53MCP protocol belongs to this skill);54`secrets-management-standards` (custody and rotation of the credentials MCP servers55consume), `cryptography-pki-standards` (TLS, artifact signing);56`appsec-standards` (classic vulnerability classes: SSRF, path traversal, command57injection — which is exactly what turns up in MCP server CVEs; the triage is theirs),58`vulnerability-management-standards` (the CVE/EPSS/KEV lifecycle of the installed servers),59`container-runtime-security-standards` (sandboxing the local server: seccomp, capabilities,60rootless), `firewall-policy-standards` (egress of the server and of the host),61`observability-standards` (OpenTelemetry: MCP documents `traceparent` propagation in62`_meta`, but the telemetry design is theirs),63`detection-engineering-standards` (detection rules over that telemetry),64`incident-response-forensics-standards` (responding to a compromised server),65`offensive-security-standards` (**authorised** offensive assessment of a server),66`python-standards`/`typescript-standards` (the idiom of the SDK's language),67`cicd-standards` (the pipeline that publishes and signs the server),68`privacy-engineering-standards` / `grc-compliance-standards` (personal data and governance).69Also: `llm-app-engineering-standards` (the single-turn LLM app or deterministic70pipeline — prompting, structured output, context window, cost per request).71Plus: `rag-standards`, `llm-evaluation-standards`, `mlsecops-standards`,72`ai-governance-standards`.7374## 2. Default decisions7576> Verify the current revision on the web before committing to anything (§8). **This protocol changes77> by dated revision and the 2026-07-28 one broke big things**: the data below expire.7879| Decision | Default | Reason / alternative |80|---|---|---|81| Protocol revision | **`2026-07-28`** (final, published 28-Jul-2026; supersedes `2025-11-25`) | The versions are `YYYY-MM-DD` dates marking the last breaking change. Pin the revision explicitly; not "the latest" |82| Local transport | **stdio** | A child process of the host; no open port, no network surface. The default for every server running on the user's machine |83| Remote transport | **Streamable HTTP** | The original HTTP+SSE has been **deprecated since `2025-03-26`** and reclassified as *Deprecated* under the lifecycle policy in `2026-07-28`. It is not implemented in new code |84| Server state | **Stateless** | `2026-07-28` removes protocol sessions and the `Mcp-Session-Id` header; state between calls is carried in explicit *handles* minted by the server and passed as a tool argument |85| MCP server or a normal function? | **A normal function** if it is **one** in-house integration consumed by **one** in-house host | MCP solves M×N → M+N. With M=1 and N=1 it only adds a process, a transport, attack surface and a translation layer |86| Remote authorisation | **OAuth 2.1 with PKCE (S256)**; the MCP server is **only a *resource server*** | Never issue tokens from the MCP server. RFC 9728 (protected resource metadata) + RFC 8707 (`resource`) mandatory |87| OAuth client registration | **Client ID Metadata Documents (CIMD)** | Dynamic Client Registration (RFC 7591) is **deprecated** in `2026-07-28`; it dropped from SHOULD to MAY in `2025-11-25`. DCR only for compatibility with ASes that do not support CIMD |88| Number of tools per server | **Few and task-oriented** (single digits, not dozens) | Every definition takes up context on every turn and competes for the model's attention. Exposing a whole API is the most common antipattern |89| Schemas | A strict `inputSchema` with `additionalProperties: false`, explicit `required` and `enum` where applicable | The model fills in whatever the schema allows. A lax schema is an invitation to malformed calls |90| Tool output | **Bounded and paginated**; a hard size limit on the server | A tool that returns 200 KB poisons the host's context and ruins the prompt cache |91| SDK | **Tier 1**: TypeScript, Python, C#, Go | Tier 2: Java, Rust, Ruby. Tier 3: Swift, PHP, Kotlin. Verify the tier table before committing to a language |92| Server registry | The official registry **in preview**, not GA | `registry.modelcontextprotocol.io` still warns of possible *breaking changes* and data resets. It is not a chain of trust: **it does not validate security**. Use an internal/curated registry for production |93| Installing third-party servers | **Audit + pin the version by digest** | An MCP server is arbitrary execution with your permissions (§5) |9495### Primitives and their status (revision `2026-07-28`)9697Who controls what is half of the design:9899| Primitive | Who controls it | Status |100|---|---|---|101| **Tools** (`tools/list`, `tools/call`) | **The model** decides to invoke it | Active. It is 90% of what gets built |102| **Resources** (`resources/list`, `resources/read`) | **The application** contributes them to the context | Active. `resources/subscribe`/`unsubscribe` replaced by `subscriptions/listen` |103| **Prompts** (`prompts/list`, `prompts/get`) | **The user** chooses them (menu, slash command) | Active. Little adopted by clients: verify host support before relying on them |104| **Sampling** (`sampling/createMessage`) | Server → client | **DEPRECATED** in `2026-07-28`. Suggested migration: integrate directly with the LLM provider's API |105| **Roots** (`roots/list`) | Server → client | **DEPRECATED**. Migration: pass directories/files as tool parameters, resource URIs or server configuration |106| **Logging** (`logging/setLevel`) | Server → client | **DEPRECATED**. Migration: `stderr` on stdio, or OpenTelemetry |107| **Elicitation** | Server → client | Replaced by the **MRTR** pattern (Multi Round-Trip Requests): the server returns `resultType: "input_required"` with `inputRequests`, and the client retries the original request with `inputResponses` |108109**Design consequence**: do not build anything new on sampling, roots or logging —110they keep working during the deprecation window (a minimum of 12 months under the lifecycle111policy), but they are debt from day one. If a design "needs" sampling, almost112always what it needs is for the **host** to make the call to the model.113114## 3. Structure and conventions115116### Designing the tool surface117118- **One tool = one user task**, not one endpoint. `create_issue_with_labels` is119 better than `POST /issues` + `POST /issues/{id}/labels` exposed separately: fewer turns,120 fewer intermediate states, fewer opportunities for error.121- **The description says *when* to call it, not just what it does.** "Query the status of a122 deployment. Use it when the user asks whether a change is already in production or why123 a release failed; **do not** use it to list historical deployments — for that, `list_deploys`."124 Purely declarative descriptions produce under-invocation in some models and125 over-invocation in others.126- **Stable names with a namespace of their own** (`acme_deploy_status`). Name collisions127 between servers are the way in for *shadowing* (§5).128- **A deterministic order** in `tools/list`: the current revision recommends returning the129 tools in a stable order so the client can cache and improve the *hit rate* of the model's130 prompt cache. A random order (iterating a `set`, an unordered `dict`) invalidates131 the cache on every turn.132- **Errors the model can recover from**: actionable text, not a stack trace or a133 `500 Internal Server Error`. "The repository `x/y` does not exist or you do not have access. Check134 the name or use `list_repos`." The model retries well with a message like that and loops135 with an opaque one.136- **Outputs bounded by design**: cursor pagination, explicit and announced truncation137 ("showing 20 of 431; use `cursor` to continue"), and field projection. Never138 return the source system's complete object "just in case".139- **Idempotency and effects**: mark in the description which tools mutate state and which do140 not; the host uses that distinction to parallelise the read ones and to ask for approval on the141 write ones.142143### Configuration file and publishing144145- Server entries in `mcp.json` / `.mcp.json` / the host's configuration: **a pinned version**146 (image digest or exact package version), never `latest` and never a branch.147- `server.json` for publishing to the registry: metadata and installation instructions; the148 artifacts still live in npm/PyPI/OCI, with the supply chain of those registries149 (and their risks — §5).150- **Version the server** with SemVer and declare the supported protocol revision. Changing151 the schema or the semantics of an existing tool is a breaking change **for the152 model** even if the JSON still validates.153154### What is new in `2026-07-28` that affects the code155156- There is no `initialize`/`notifications/initialized` handshake: every request carries the protocol157 version and the client's capabilities in `_meta`.158- `server/discover` is **mandatory** on the server, to announce supported versions,159 capabilities and identity.160- The `Mcp-Method` and `Mcp-Name` headers are mandatory on POST over Streamable HTTP — they let161 gateways, rate limiters and WAFs route and measure without parsing the body. The server rejects162 requests where the header and the body disagree.163- `ttlMs` and `cacheScope` (`public`/`private`) are mandatory in the results of `tools/list`,164 `prompts/list`, `resources/list`, `resources/read` and `resources/templates/list`.165- SSE stream resumption (`Last-Event-ID`) is removed: a broken stream loses the in-flight166 request and **the client must reissue it with a new ID** — which demands real idempotency167 in the write tools.168- `resultType` is mandatory in every result (`"complete"` or `"input_required"`).169- Tasks moves from experimental core to an **official extension** (`io.modelcontextprotocol/tasks`).170171## 4. Quality and gates172173Gates in increasing order of cost. The ones marked **[BLOCKS]** break the build or the deployment.1741751. **[BLOCKS] Schema validation**: every `inputSchema` with `additionalProperties: false`176 and explicit `required`. A test that walks `tools/list` and verifies it.1772. **[BLOCKS] Output budget**: a test that exercises each tool with the most178 voluminous reasonable input and fails if the response exceeds the set limit (choose one and179 document it; the useful order of magnitude is a few thousand tokens, not hundreds of thousands).1803. **[BLOCKS] No *token passthrough***: a test that sends the server a token whose `aud` is not181 the server and checks that it is **rejected**. The specification forbids it with an explicit182 MUST NOT: *"MCP servers **MUST NOT** accept any tokens that were not explicitly issued for183 the MCP server."*1844. **[BLOCKS] Remote authorisation**: `/.well-known/oauth-protected-resource` (RFC 9728)185 served and correct; audience validation; PKCE S256; validation of the `iss` parameter in186 the authorisation response (RFC 9207) before exchanging the code.1875. **[BLOCKS] SCA + artifact scanning** of the server and of its transitive dependencies.1886. **Protocol conformance**: `server/discover` responds; the `Mcp-Method`/`Mcp-Name` headers189 verified against the body; `resultType` present; `ttlMs`/`cacheScope` present.1907. **`tools/list` determinism**: a test that calls twice and compares the order byte by byte.1918. **Edge and error testing**: invalid input, non-existent resource, permission denied,192 source system timeout — each returns an actionable error, not a dump.1939. **Testing with a real model**: a server can be correct and still be useless. Run194 a set of end-to-end tasks and measure the **task success rate**, not195 API coverage. If the model picks the wrong tool, the defect is in the196 description, not in the model.19710. **Description auditing** (`mcp-scan` or equivalent) over the servers you198 install: detection of embedded instructions and of overlap between servers.19911. **Pinning definitions**: hash each tool definition on approving it and alert200 when it changes (a direct mitigation of the *rug pull*, §5).201202## 5. Security — the critical section203204**Premise**: **an MCP server is third-party code running with your permissions.** A local205server is a binary you execute; a remote one is a service you hand context and206credentials to. The specification is explicit: without sandboxing and consent, one-click207installation allows *arbitrary code execution* with the client's privileges, and it warns208that *"Users have no insight into what commands are being executed."*209210Everything that follows is **a risk class, an indicator and a mitigation**. Nothing here is an211exploitation procedure.212213### Risk classes specific to MCP214215| Class | What it is | Indicator | Mitigation |216|---|---|---|---|217| **Tool poisoning** | Instructions for the model hidden in the description, the schema or the result of a tool. The user sees a short name; the model reads the full text and obeys it. **The tool does not need to be invoked**: it is enough for it to be loaded in context | Disproportionately long descriptions, imperative text addressed to the assistant, invisible or control characters, references to other tools or to the user's files | Human review of every description before approval; automated scanning; render the **full** description in the approval UI, untruncated |218| **Rug pull** | The server changes the description **after** you trusted it. Most clients do not warn about the change | A definition hash different from the approved one | Pin the version by digest; hash definitions and **fail closed** on a change; explicit re-approval |219| **Cross-server shadowing** | A malicious server's description alters the agent's behaviour with tools from **another**, trusted server. Combined with a rug pull, it hijacks without appearing in the visible log | Colliding tool names; a description that mentions other servers' tools | Per-server namespaces; isolate servers by trust level; do not mix third-party servers with tools over sensitive data in the same session |220| **Confused deputy** | An MCP proxy with a static `client_id` before the third-party AS, dynamic client registration and a consent cookie allows obtaining authorisation codes **bypassing the user's consent** | An MCP proxy that does not store consent per `client_id` | The specification requires it: *"MCP proxy servers **MUST** implement per-client consent"* — a register of user-approved `client_id`s, checked **before** forwarding to the third-party AS; a `redirect_uri` validated by exact match; a single-use `state` created **only after** consent is approved |221| **Token passthrough** | The server accepts and forwards tokens not issued for it | Absence of `aud` validation | The MUST NOT of §4.3; RFC 8707 `resource` in the authorisation **and** token requests |222| **State handle hijacking** | With the stateless protocol, whoever guesses or obtains a *handle* accesses another user's state | Sequential or predictable handles | *"MCP servers **MUST NOT** treat possession of a state handle as authentication."* Securely random handles, bound to the authenticated user on the server side (`<user_id>:<handle>`), with expiry |223| **SSRF in the client** | The malicious server publishes OAuth discovery URLs pointing at `169.254.169.254`, `localhost` or private ranges | Client requests to internal IPs | Require HTTPS, block private/reserved/link-local ranges, validate redirect destinations, an egress proxy. **Do not implement the IP validation by hand** — the encoding tricks (octal, hex, IPv4-mapped IPv6) get through |224| **Dangerous URL scheme** | A `javascript:`, `data:`, `file:` authorisation URL from the server → XSS/RCE in the client | — | Allowlist `http`(loopback)/`https`; **never** open URLs via a shell |225| **Supply chain compromise** | A trojanised server published in a registry with accounts and personas created to give an appearance of legitimacy; the official registry **is not a chain of trust** and is still in preview | A new package, a maintainer with no history, no verifiable repository | An internal curated registry; code review; digest pinning; SBOM and signing; an inventory of what is installed |226227### Hard rules228229- **FORBIDDEN to install a third-party MCP server without auditing it**: code, dependencies,230 maintainer and the permissions it asks for. It is the same decision as installing a binary.231- **stdio by default for local servers**; if there is a local HTTP transport, require an232 authorisation token or a unix socket with restricted permissions. A local server listening on233 localhost with no auth is reachable by DNS rebinding from the browser.234- **Sandboxing the local server**: a container or a platform sandbox, a filesystem235 restricted to the necessary directories, no network beyond the indispensable, non-root. The236 specification lists it as a client SHOULD; treat it as a requirement of your own.237- **Least privilege in the server's credentials**: a token with the task's scope, not238 the administrator's. The specification explicitly discourages omnibus *scopes*239 (`*`, `all`, `full-access`) and publishing the full catalogue in `scopes_supported`.240- **Informed consent, per sensitive action**, not an "allow everything" at install time: the241 user must see the exact command untruncated, what is executed and with what privileges. A242 dialogue that truncates the tool's description turns consent into theatre.243- **Never** put secrets in descriptions, prompts, resources or results: they end up in the244 model's context, in the history and potentially in logs and summaries.245- The server **cannot trust** that the client applies any mitigation: it validates at its246 own edge.247248### The reality of adoption (context, not an excuse)249250Authorisation adoption in public MCP servers is **low** —in the order of single-digit251percentages according to ecosystem analyses in 2026, and a significant fraction of the252registered servers offer no effective authentication. Operational translation: **assume any253public server is unauthenticated and badly maintained until proven otherwise.**254The volume of CVEs against MCP implementations during 2026 is high, and the dominant classes255are classic ones —path traversal, command injection, missing authentication on a sibling256endpoint— not exotic ones: see `appsec-standards` for the triage.257258## 6. Performance and operability259260- **A mandatory inventory** of MCP servers installed per host and per user: origin,261 pinned version, credentials it consumes, permissions it holds, who approved it and when.262 Without an inventory there is no incident response and no vulnerability management. *Shadow MCP*263 —servers installed outside change control— is the most common governance failure.264- **Observability of invocations**: which tool, from which server, with which arguments265 (with the sensitive ones redacted), what result, what latency, what token cost. The266 current revision documents W3C/OpenTelemetry trace context propagation in `_meta`267 (`traceparent`, `tracestate`, `baggage`): use it to correlate the model's call with268 the execution on the server and with the request to the source system.269- **Caching**: honour `ttlMs` and `cacheScope`; `cacheScope: "private"` is **never** cached in a270 shared intermediary. A `tools/list` with an unstable order breaks the host's prompt cache271 and makes every turn more expensive.272- **Context budget**: a server's cost is not just its latency; it is the tokens273 its definitions occupy on **every** turn. Measure that cost and prune tools that are not274 used.275- **Stateless by design** (`2026-07-28`): a remote server must be able to run behind a276 round-robin load balancer with no sticky sessions. If yours needs affinity, the state is277 badly modelled.278- **Timeouts and limits** on every call to the source system; degradation with an actionable error279 instead of hanging the model's turn.280- **Updating**: a defined cadence, the changelog read (not applied blindly — an update is a281 rug pull vector), and re-approval when tool definitions change.282283## 7. Sustainability and prohibitions284285- **Review cadence**: this ecosystem moves by dated revision with a minimum deprecation286 window of 12 months. Review the protocol revision and the deprecations **every287 quarter**, not every year.288- **The server's own deprecation policy**: do not break the semantics of an existing tool;289 add a new one and mark the old one. The "consumer" is a model with prompts and290 evaluations built on top.291292**FORBIDDEN**293- ❌ Standing up an MCP server for **one** in-house integration consumed by **one** in-house host: it is a function.294- ❌ Exposing a whole API as MCP tools, endpoint by endpoint.295- ❌ Tool descriptions that only say what the tool does and not **when** to use it.296- ❌ Lax schemas: no `additionalProperties: false`, no `required`, free `string` where an `enum` fits.297- ❌ Tools with unbounded output.298- ❌ Opaque errors (`500`, a stack trace) returned to the model.299- ❌ Implementing HTTP+SSE in new code (deprecated since `2025-03-26`).300- ❌ Building on **sampling**, **roots** or **logging**: deprecated in `2026-07-28`.301- ❌ Letting the MCP server act as an *authorization server* or issue tokens.302- ❌ Accepting or forwarding tokens not issued for the server (the specification's **MUST NOT**).303- ❌ Treating possession of a *state handle* as authentication.304- ❌ Dynamic Client Registration in new code: use CIMD.305- ❌ Installing third-party servers without auditing them, or from unverified registries.306- ❌ `latest` / a branch / an unpinned package in a server's configuration.307- ❌ A local server with an HTTP transport and no authentication.308- ❌ Running a local server without a sandbox and with broad filesystem access.309- ❌ A consent dialogue that truncates the description or the command: it is security theatre.310- ❌ Secrets in descriptions, prompts, resources or results.311- ❌ Treating the official registry as a chain of trust or as GA.312- ❌ Accepting a server update without reviewing changes to the tool definitions.313- ❌ Trusting that the client applies the mitigations: the server validates at its edge.314315## 8. Mandatory web verification316317Before committing to any version, field name, primitive or normative requirement:3183191. **The specification's current revision** (`modelcontextprotocol.io/specification/...`) and its320 *changelog*: the versions are dates and the `2026-07-28` one removed sessions, the handshake,321 `ping`, `logging/setLevel` and stream resumption. Check whether there is a later one.3222. **The register of deprecated features** (`/specification/<rev>/deprecated`) and the lifecycle323 policy: sampling, roots and logging are in the deprecation window — confirm whether they have324 already been **removed**.3253. **The authorisation specification**: it has been revised several times. Confirm the status of326 RFC 9728, RFC 8707, PKCE S256, `iss` validation (RFC 9207) and the exact status of CIMD327 versus DCR.3284. **The Security Best Practices page** of the current revision: it is the normative source of the329 MUSTs/MUST NOTs cited in §5. Quote **verbatim** any requirement that decides something.3305. **The SDK tier table** (`/docs/sdk` and `/community/sdk-tiers`): the tiers change.3316. **The status of the official registry**: still in preview as of August 2026 — verify whether it has332 reached GA and what guarantees it gives.3337. **CVEs and incidents** in the specific servers you are going to install (not in "MCP" in the334 abstract): NVD/GHSA per package, plus the maintainer's history.3358. **The status of the extensions** (`tasks`, MCP Apps) and of neighbouring projects (A2A under the336 Linux Foundation) if the design depends on them.337338### Declared gaps (not verified in this drafting)339340- **Exact CVE figures and specific vulnerability IDs for MCP servers in 2026**: they are341 described as a class and an aggregate volume from secondary sources; **no IDs or CVSS scores are342 fixed here**. Verify in NVD/GHSA before citing any.343- **The exact percentage of public servers with OAuth implemented** and the size of the registry:344 a secondary-source datum, order of magnitude only.345- **The detail of the `io.modelcontextprotocol/tasks` extension and of MCP Apps**: not verified in346 depth; consult the extensions documentation before designing on them.347- **The status of `mcp-scan` and other description-auditing tools**: it is cited as a348 category; its current maintenance has not been verified.349- **OWASP's "MCP Top 10"**: mentioned by secondary sources as a separate project; not350 verified against OWASP's primary source.351352If the web contradicts this document, **the web wins** — flag the discrepancy.