Move MCP clients and servers to 2026-07-28
MCP 2026-07-28 is the largest MCP revision so far: no handshake, no session,
and new extensions such as Tasks and MCP Apps. DVARA, the AI governance
platform, keeps every tool call governed while you move.
You do not have to move everything at once. The DVARA MCP Gateway serves MCP
2026-07-28, 2025-11-25 and 2025-06-18 on the same /mcp endpoint, at the
same time. It also picks a revision for each upstream server on its own. So
your clients and your servers can move separately, one at a time, in any
order.
This page is the checklist. It says what changes, in what order to move, and what to check. The details are on the pages it links to.
Not included in DVARA Open Source.
The short version
- Measure. Find out which revisions your clients use today.
- Read the operator changes. A few answers and defaults differ from older releases. Know them before you upgrade the Gateway.
- Move clients. A client on
2026-07-28drops the handshake and sends its version on every request. - Move servers. Nothing to configure. The Gateway uses
2026-07-28with a server as soon as the server speaks it. Expect one approval when a server's new release reports a new version. - Turn on extensions, if you want them. Tasks and MCP Apps work only on
2026-07-28, and are off until a workspace allows them.
What the Gateway does on each revision
2026-07-28 | 2025-11-25 and 2025-06-18 | No revision named | |
|---|---|---|---|
| Handshake | None. Each request carries its version and client details in _meta | initialize, then requests | Served as an older client |
| Headers | MCP-Protocol-Version, Mcp-Method and Mcp-Name required | Optional, but checked when sent | None |
| Invalid tool arguments | A tool result marked as an error, which a model can correct | 2025-11-25: a tool result marked as an error. 2025-06-18: JSON-RPC error -32602 | JSON-RPC error -32602 |
| Caching hints on lists | ttlMs, 15 seconds at most, and cacheScope: "private" | None | None |
| Change notifications | subscriptions/listen | Fetch the list again | Fetch the list again |
| Questions mid-call (elicitation) | Relayed | Refused with 502 MCP_INPUT_REQUIRED_UNSUPPORTED | Refused |
| Tasks and MCP Apps | When the client, the workspace and the server all agree | Never | Never |
| Governance and audit | The same on every revision | The same | The same |
Tool names keep the Gateway's form, serverId__toolName, on every revision.
API keys and OAuth tokens work the same way on every revision.
Step 1: measure
The Gateway counts every /mcp request by revision in the Prometheus metric
mcp_requests_by_protocol_version_total. Its revision label is
2026-07-28, 2025-11-25, 2025-06-18, none (no revision named) or
unsupported (refused for its revision).
Look at none first. Those clients get the oldest behaviour, and they are the
easiest to fix: send the MCP-Protocol-Version header.
The audit record of each governed call also has mcp_protocol_version_source:
header, meta or none. Use it to find which client sent a request with no
version.
Clients that still use features 2026-07-28 deprecates (Roots, Sampling,
Logging) are recorded as MCP_DEPRECATED_FEATURE_USED, at most once a day per
client and feature.
Step 2: read the changes operators must know
Each of these is a default. Check it against what your clients expect.
| Change | What you see | What to do |
|---|---|---|
A request with no version is treated as 2025-03-26 | A call with invalid arguments gets JSON-RPC error -32602, not a tool result marked as an error | Have clients send the MCP-Protocol-Version header. Clients on 2025-06-18 and later must send it anyway |
| Lists can be reused for a short time | 2026-07-28 lists carry ttlMs of 15 seconds at most, and cacheScope: "private". A longer time asked for by an upstream server is cut to 15 seconds | A client or proxy must keep a separate copy per API key. Change the limit with dvara.mcp-gateway.caching.max-ttl; 0 means fetch every time |
| Tasks need the audit secret | Task ids are sealed with a key made from DVARA_AUDIT_HMAC_SECRET. Without it, Tasks is not relayed | Set the same secret on every Gateway replica. Changing it ends every open task id |
| Sampling is refused | A server's request for a model call fails the call with MCP_SAMPLING_REFUSED | To allow it, a workspace chooses Make the call through the LLM Gateway and a model. See sampling |
| Extensions are off | Every extension a client declares is refused and recorded, and the client falls back to core MCP | Allow the ones you want, per workspace. See Govern MCP Apps and Tasks |
| A changed server waits for approval | A change to a tool's description or schemas, a new server name or version, or a STDIO command or TLS key that no longer matches its pin quarantines the server until someone approves it | Plan one approval for each server you upgrade. See a tool that changes after approval |
| Response trimming is off | Tool results are passed on whole | Nothing to do. To trim, see keep only the fields a result needs |
| The old HTTP+SSE upstream transport has an end date | It works until 2027-07-28, with a warning and an audit event on each use. From that date a call is refused with 410 mcp_transport_sunset | Move those servers to STREAMABLE_HTTP |
Tool arguments are also checked against the tool's input schema. A schema with
no $schema is read as JSON Schema 2020-12, as 2026-07-28 says. Arguments that
fail it are refused before the server sees them.
Step 3: move a client
Point the client at the same URL, https://<your-gateway>/mcp, with the same
API key or OAuth token. Then change how it talks:
Before (2025-11-25 or 2025-06-18) | After (2026-07-28) |
|---|---|
Send initialize, then requests | Send requests straight away. initialize and ping now return 404 with "method not found" |
| Name the version once, in the handshake | Send MCP-Protocol-Version: 2026-07-28 on every request, with Mcp-Method (and Mcp-Name for a request that names a tool, prompt, resource or task) |
| Declare capabilities once | Put io.modelcontextprotocol/protocolVersion, clientCapabilities and, usually, clientInfo in each request's _meta |
Fetch tools/list again to see changes | Keep the list for its ttlMs, or open subscriptions/listen to be told when it changes |
Ask initialize what the server offers | Send server/discover |
| A long call blocks | A call can return a task, if the workspace allows Tasks |
Before, a client opened a session:
curl -s https://<your-gateway>/mcp \
-H "Authorization: Bearer $DVARA_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
"protocolVersion":"2025-11-25","capabilities":{},
"clientInfo":{"name":"my-agent","version":"1.0"}}}'
After, each request stands alone:
curl -s https://<your-gateway>/mcp \
-H "Authorization: Bearer $DVARA_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: tools/list' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientInfo":{"name":"my-agent","version":"1.0"},
"io.modelcontextprotocol/clientCapabilities":{}}}}'
What can go wrong, and why:
| Answer | Why |
|---|---|
400 with MCP's header-mismatch error (-32020) | A header and the body disagree: a different method, tool or version, or a tool argument sent in an Mcp-Param-… header with another value |
400 with "unsupported protocol version" (-32022) | The client named a revision the Gateway does not serve. The error lists the ones it does |
400 with a missing-header or missing-capabilities error | A 2026-07-28 request without the required headers, or without the version and client capabilities in _meta |
404 "method not found" | A method 2026-07-28 removed, such as initialize or ping |
Tool names stay serverId__toolName. Policies, approvals, PII scans, budgets and
the audit trail work the same as before, so a client move changes no
governance setting.
Details: Connect a 2026-07-28 client and tool arguments in headers.
Step 4: move an upstream server
The Gateway is also an MCP client of each server you register. You do not configure the revision it uses.
HTTP servers (STREAMABLE_HTTP). The Gateway asks each server which
revisions it speaks and uses the newest one both sides support. It remembers the
answer for 15 minutes, and asks again sooner when you change the server's URL or
credential, or when the server refuses the remembered revision. So when you
upgrade a server to 2026-07-28, the Gateway moves to it on its own. A server
that speaks only revisions the Gateway does not know fails the call with
mcp_protocol_version_unsupported.
STDIO servers. A server the Gateway runs as a local process is asked the
same question as its first message. If it answers as a 2026-07-28 server, it
is called on that revision. If it gives any other answer, or none within 10
seconds, it is treated as an older server and started again with initialize.
A STDIO server gets no headers and no credential from the Gateway. It reads its
own settings from its environment.
Old HTTP+SSE servers (SSE). These stay on 2025-11-25 or 2025-06-18,
and stop working on 2027-07-28. Move them to STREAMABLE_HTTP.
Expect one approval per upgraded server. A new release usually changes what the server reports about itself, and sometimes its tool text. The Gateway holds each of these for approval, and quarantines the server until then:
| What changed | Audit event | Who approves |
|---|---|---|
| A tool's description, input schema, output schema or hints | MCP_TOOL_DEFINITION_CHANGED | A platform operator (Release quarantine) or the workspace admin (Approve tool changes) |
| The server's reported name or version | MCP_SERVER_IDENTITY_CHANGED | The same |
| A STDIO command's package version, image digest or program file, or an HTTPS server's TLS key | MCP_SERVER_PIN_MISMATCH | The same. The found value becomes the new pin |
Agents keep seeing the approved version until then, and calls to the server are refused. To keep the gap short, sync the server's tools in Flightdeck right after the upgrade and approve the change at once. See a server that reports a new version and a server is pinned to what it runs.
Tool schemas. If a tool marks a parameter with x-mcp-header, the Gateway
sends that value as an Mcp-Param-… header too. A tool whose markings break the
protocol's rules is left out of the tool list, as the protocol requires.
A server that asks for input. On 2026-07-28 a server can answer a call with
a request for more input. A question for the user (elicitation) is passed to
2026-07-28 clients after a prompt-injection scan. A request for a model call
(sampling) is never passed to the client: the Gateway refuses it, or makes the
call itself through the LLM Gateway if the workspace chose that. A request for
the client's folders (roots) is refused by default.
Step 5: turn on Tasks and MCP Apps, if you want them
Both are MCP extensions. Both work only on 2026-07-28, and only when the
client, the workspace and the server all agree. Both are off by default. See
Govern MCP Apps and Tasks for the order to turn
them on and what to set first.
Check after each move
mcp_requests_by_protocol_version_totalshows traffic moving fromnoneand the older revisions to2026-07-28.- The audit record of each tool result names two revisions: the one your client used with the Gateway, and the one the Gateway used with the server.
- MCP → Tool Calls in Flightdeck (platform roles), or Agents → MCP Tool Calls (workspace roles), shows the calls with no new refusals.
- No server waits in quarantine longer than you planned.
What does not change
- The older revisions are not being switched off. If one is ever retired, it will be announced in advance, with a date.
- Authentication: API keys and OAuth tokens work the same way on every revision.
- Governance: policy, PII and injection scans, approvals, budgets, rate limits and the signed audit trail apply to every call on every revision.
Where to go next
- MCP protocol versions, the reference for each revision.
- Govern MCP Apps and Tasks
- Govern tool calls with the MCP Gateway