MCP integration
Verified 2026-07-29 against the 2026-07-28 specification release announcement. This revision
landed one day before this file was written — read the specification itself before migrating, and
treat the detail below as a map of what to look for, not a substitute for it.
1. The 2026-07-28 revision is a breaking change
The protocol core became stateless. This is the largest change since MCP was published, and it
invalidates a good deal of existing integration code and most tutorials.
| Removed / deprecated |
Replaced by |
initialize / initialized handshake |
Protocol version, client identity and capabilities travel in _meta on every request |
Mcp-Session-Id header |
Nothing — there is no protocol-level session |
| Server-initiated elicitation, sampling, roots-list |
Multi Round-Trip Requests: the server returns resultType: "input_required", the client retries with inputResponses |
| Legacy HTTP+SSE transport |
Streamable HTTP |
| Dynamic Client Registration |
Client ID Metadata Documents (CIMD) |
| Roots, Sampling, Logging features |
Deprecated, with a minimum 12-month sunset |
Added:
- Header-based routing — streamable HTTP requests carry
Mcp-Method and Mcp-Name, so gateways,
rate limiters and authorizers can route and authorise without parsing the JSON body.
- Cacheable list results —
tools/list, prompts/list, resources/list and resources/read
responses carry ttlMs and cacheScope.
- Authorization hardening — RFC 9207 issuer (
iss) validation is now mandatory, an
application_type parameter is supported, and client credentials are bound to the issuing
authorization server.
- A formal extensions framework, with Tasks graduating to
io.modelcontextprotocol/tasks
(poll-based tasks/get, plus tasks/update) and notifications moving to subscriptions/listen.
- A 12-month minimum deprecation policy, which is what makes planned migration possible.
Compatibility is the thing that will bite
A server on the new revision may not work with an older client, and vice versa. Both sides must
share a supported protocol era, or one side must implement deliberate fallback or translation.
Before upgrading either side, enumerate what talks to it. The stateless change is genuinely good
— it lets any instance answer any request behind ordinary round-robin HTTP, with no shared session
store — but it is not backward compatible, and a client you do not control is a hard constraint.
2. Do you need MCP here at all?
MCP earns its cost when the tool surface is consumed by clients you do not own — a desktop
assistant, an IDE, someone else's agent — or when several applications share one integration.
It does not earn it for a private tool used by one application you control. Native function
calling against your own code is simpler, faster, has no transport, no auth layer and no protocol
version to track. Wrapping your own function in a protocol so your own agent can call it is
infrastructure for its own sake.
The honest test: name the second consumer. If there isn't one and isn't likely to be, call the
function.
3. Transport
| Transport |
Use for |
| stdio |
Local, client-launched servers. Simplest and most reliable — no ports, no CORS, no auth layer |
| Streamable HTTP |
Remote and shared servers |
HTTP+SSE |
Deprecated. Do not build new integrations on it |
Default to stdio for anything local. Reaching for HTTP because it feels more production-grade
adds an authentication surface and an availability dependency to something that was a subprocess.
4. Authorization
- Validate the issuer. RFC 9207
iss validation is mandatory in the current revision — it is the
defence against a token minted by one authorization server being replayed at another.
- Prefer CIMD over Dynamic Client Registration, which is now formally deprecated.
- Bind tokens to an audience, and never forward a user's token to a downstream API unchanged. A
server that accepts a user token and reuses it against a third party is a confused deputy: the
downstream sees your service's authority, not the user's.
- The permission the server holds is the permission the model effectively has. Scope credentials
to what the tools genuinely need, per server, not per organisation.
5. Tool lists cost tokens on every call
Every connected server's tool definitions are input tokens on every request, and a large
undifferentiated toolset also degrades tool selection — the same failure as overlapping skills.
- Connect the servers a given surface actually needs, not every server the organisation runs.
- Use
ttlMs / cacheScope to avoid re-fetching lists that have not changed.
- Place tool definitions in the cached prefix of your prompt — they are static, so they belong at
the top where prompt caching can reuse them (
llm-api-optimization §2).
- Watch for name collisions across servers. Two servers exposing
search is an ambiguity you pay
for on every call.
6. Third-party servers are untrusted code
A community MCP server is a dependency that runs on your machine or holds your credentials, and
supplies text directly into the model's context.
- Tool descriptions are an injection surface. They enter the prompt, so a malicious description
can instruct the model. Read them before installing.
- Pin versions. An auto-updating server is remote code execution with a changelog.
- Least privilege per server — separate credentials, minimum scopes, no shared admin token.
- Gate destructive tools behind human approval, at the client (
agentic-architecture §6).
- Treat every tool result as untrusted input, not as trusted context —
llm-security covers the
defences, and this is exactly the boundary it is about.
7. Operating remote servers
- Statelessness is what makes horizontal scaling ordinary — no sticky sessions, no shared session
store, any instance answers any request.
- Exploit header-based routing at the edge:
Mcp-Method and Mcp-Name let a gateway authorise
and rate-limit per tool without deserialising bodies. Per-tool rate limits are the practical
defence against a runaway agent loop.
- Handle tool errors as data, never as a crashed process — one failed call must not take down
every connected client.
- Set timeouts and size caps on tool results at the client. A server you do not control can
return more than your context can hold.
- Version-negotiate explicitly and log the negotiated era, so a client-side incompatibility is a
clear log line rather than a mystery.
8. Anti-patterns
- Migrating to the stateless revision without enumerating every client and server that talks to
the thing being upgraded.
- Building new integrations on HTTP+SSE, which is deprecated.
- Assuming a session exists. There is no protocol session; state you need is yours to carry.
- Wrapping your own function in MCP so your own agent can call it.
- HTTP transport for a local subprocess.
- Forwarding a user's token downstream unchanged.
- Connecting every available server to every surface, then paying for the tool list on every call.
- Installing a community server without reading its tool descriptions.
- Auto-updating third-party servers.
- Treating tool output as trusted context.
- No per-tool rate limit, so an agent loop becomes a third-party bill.
1---2name: mcp-integration3description: Use when wiring MCP servers into an application or agent as a consumer — deciding whether MCP is the right interface at all, the 2026-07-28 stateless protocol revision and what it breaks, transport and version negotiation, OAuth authorization and Client ID Metadata Documents, the context cost of tool lists and how cacheable list results reduce it, treating third-party servers as untrusted code, and operating remote servers behind ordinary HTTP infrastructure.4---56# MCP integration78<!-- REVIEW-BY: 2027-01-31 -->9**Verified 2026-07-29 against the 2026-07-28 specification release announcement.** This revision10landed one day before this file was written — **read the specification itself before migrating**, and11treat the detail below as a map of what to look for, not a substitute for it.1213## 1. The 2026-07-28 revision is a breaking change1415**The protocol core became stateless.** This is the largest change since MCP was published, and it16invalidates a good deal of existing integration code and most tutorials.1718| Removed / deprecated | Replaced by |19|---|---|20| `initialize` / `initialized` handshake | Protocol version, client identity and capabilities travel in `_meta` **on every request** |21| `Mcp-Session-Id` header | Nothing — there is no protocol-level session |22| Server-initiated elicitation, sampling, roots-list | **Multi Round-Trip Requests**: the server returns `resultType: "input_required"`, the client retries with `inputResponses` |23| Legacy HTTP+SSE transport | Streamable HTTP |24| Dynamic Client Registration | **Client ID Metadata Documents (CIMD)** |25| Roots, Sampling, Logging features | Deprecated, with a minimum 12-month sunset |2627**Added:**2829- **Header-based routing** — streamable HTTP requests carry `Mcp-Method` and `Mcp-Name`, so gateways,30 rate limiters and authorizers can route and authorise **without parsing the JSON body**.31- **Cacheable list results** — `tools/list`, `prompts/list`, `resources/list` and `resources/read`32 responses carry `ttlMs` and `cacheScope`.33- **Authorization hardening** — RFC 9207 issuer (`iss`) validation is now mandatory, an34 `application_type` parameter is supported, and client credentials are bound to the issuing35 authorization server.36- **A formal extensions framework**, with Tasks graduating to `io.modelcontextprotocol/tasks`37 (poll-based `tasks/get`, plus `tasks/update`) and notifications moving to `subscriptions/listen`.38- **A 12-month minimum deprecation policy**, which is what makes planned migration possible.3940### Compatibility is the thing that will bite4142**A server on the new revision may not work with an older client, and vice versa.** Both sides must43share a supported protocol era, or one side must implement deliberate fallback or translation.4445**Before upgrading either side, enumerate what talks to it.** The stateless change is genuinely good46— it lets any instance answer any request behind ordinary round-robin HTTP, with no shared session47store — but it is not backward compatible, and a client you do not control is a hard constraint.4849## 2. Do you need MCP here at all?5051**MCP earns its cost when the tool surface is consumed by clients you do not own** — a desktop52assistant, an IDE, someone else's agent — or when several applications share one integration.5354**It does not earn it for a private tool used by one application you control.** Native function55calling against your own code is simpler, faster, has no transport, no auth layer and no protocol56version to track. Wrapping your own function in a protocol so your own agent can call it is57infrastructure for its own sake.5859**The honest test:** name the second consumer. If there isn't one and isn't likely to be, call the60function.6162## 3. Transport6364| Transport | Use for |65|---|---|66| **stdio** | Local, client-launched servers. Simplest and most reliable — no ports, no CORS, no auth layer |67| **Streamable HTTP** | Remote and shared servers |68| ~~HTTP+SSE~~ | **Deprecated.** Do not build new integrations on it |6970**Default to stdio for anything local.** Reaching for HTTP because it feels more production-grade71adds an authentication surface and an availability dependency to something that was a subprocess.7273## 4. Authorization7475- **Validate the issuer.** RFC 9207 `iss` validation is mandatory in the current revision — it is the76 defence against a token minted by one authorization server being replayed at another.77- **Prefer CIMD over Dynamic Client Registration**, which is now formally deprecated.78- **Bind tokens to an audience, and never forward a user's token to a downstream API unchanged.** A79 server that accepts a user token and reuses it against a third party is a confused deputy: the80 downstream sees your service's authority, not the user's.81- **The permission the server holds is the permission the model effectively has.** Scope credentials82 to what the tools genuinely need, per server, not per organisation.8384## 5. Tool lists cost tokens on every call8586**Every connected server's tool definitions are input tokens on every request**, and a large87undifferentiated toolset also degrades tool selection — the same failure as overlapping skills.8889- **Connect the servers a given surface actually needs**, not every server the organisation runs.90- **Use `ttlMs` / `cacheScope`** to avoid re-fetching lists that have not changed.91- **Place tool definitions in the cached prefix** of your prompt — they are static, so they belong at92 the top where prompt caching can reuse them (`llm-api-optimization` §2).93- **Watch for name collisions** across servers. Two servers exposing `search` is an ambiguity you pay94 for on every call.9596## 6. Third-party servers are untrusted code9798A community MCP server is a dependency that **runs on your machine or holds your credentials, and99supplies text directly into the model's context.**100101- **Tool descriptions are an injection surface.** They enter the prompt, so a malicious description102 can instruct the model. Read them before installing.103- **Pin versions.** An auto-updating server is remote code execution with a changelog.104- **Least privilege per server** — separate credentials, minimum scopes, no shared admin token.105- **Gate destructive tools behind human approval**, at the client (`agentic-architecture` §6).106- **Treat every tool result as untrusted input**, not as trusted context — `llm-security` covers the107 defences, and this is exactly the boundary it is about.108109## 7. Operating remote servers110111- **Statelessness is what makes horizontal scaling ordinary** — no sticky sessions, no shared session112 store, any instance answers any request.113- **Exploit header-based routing** at the edge: `Mcp-Method` and `Mcp-Name` let a gateway authorise114 and rate-limit per tool without deserialising bodies. Per-tool rate limits are the practical115 defence against a runaway agent loop.116- **Handle tool errors as data, never as a crashed process** — one failed call must not take down117 every connected client.118- **Set timeouts and size caps on tool results** at the client. A server you do not control can119 return more than your context can hold.120- **Version-negotiate explicitly and log the negotiated era**, so a client-side incompatibility is a121 clear log line rather than a mystery.122123## 8. Anti-patterns124125- **Migrating to the stateless revision** without enumerating every client and server that talks to126 the thing being upgraded.127- **Building new integrations on HTTP+SSE**, which is deprecated.128- **Assuming a session exists.** There is no protocol session; state you need is yours to carry.129- **Wrapping your own function in MCP** so your own agent can call it.130- **HTTP transport for a local subprocess.**131- **Forwarding a user's token downstream unchanged.**132- **Connecting every available server** to every surface, then paying for the tool list on every call.133- **Installing a community server without reading its tool descriptions.**134- **Auto-updating third-party servers.**135- **Treating tool output as trusted context.**136- **No per-tool rate limit**, so an agent loop becomes a third-party bill.