mcp-2026-07-28
Build and consume stateless MCP servers and clients on the 2026-07-28 revision: server/discover, per-request metadata via _meta, tasks extension, OAuth 2.1 with PKCE, backward-compat negotiation down
SKILL.mdskills/agentic-data/mcp-2026-07-28/SKILL.md
GitHubMCP 2026-07-28 — stateless servers and clients
When to invoke
Scaffolding an MCP server or client; debugging a protocol handshake; mapping error codes to actions; verifying statelessness or version pinning in a deployment; integrating OAuth for an MCP tool consumer. Do NOT use for generic REST APIs or non-MCP integrations.
When to invoke (concrete triggers — if none match, do not load this skill)
| Trigger (what the user says or the repo shows) | Load? |
|---|---|
| "scaffold an MCP server/client", "write an MCP tool", "add an MCP integration" | YES |
| "handshake fails", "initialize not found", "Mcp-Session-Id rejected", "400 on POST" | YES |
| "which protocol version", "negotiate a version", "-32022", "UnsupportedProtocolVersion" | YES |
| "long-running tool", "tool times out", "poll a task", "tasks/get", "InputRequiredResult" | YES |
| "set up OAuth for MCP", "PKCE", "Client ID Metadata Document", "DCR" | YES |
| "is my deployment stateless", "replay test", "repeated call returns different result" | YES |
| "build a plain REST API", "design a GraphQL schema", "write a gRPC service" | NO |
| "use an SDK function", "call an existing API" (no MCP involved) | NO |
| "chat with a model" (no tool protocol) | NO |
Trigger rule: the description is pushy by design — a prompt that merely mentions MCP loads this skill. The table above is the precision half: if a prompt matches a row in the left column but the task is really about something else, narrow the description, not the body.
Procedure (numbered — follow in order)
- Pin the revision in config, never in logic. Primary
2026-07-28, fallbacks2025-11-25and2025-06-18. Read from envMCP_PROTOCOL_VERSIONwith a pinned default; validate against the vendored list inreferences/changelog.md. - Server: implement
server/discover(MUST). Advertise supported versions, capabilities and identity. Clients MAY call it up front for version selection or as a backward-compat probe on STDIO. - Client: send per-request
_meta. Every request carriesio.modelcontextprotocol/protocolVersion,io.modelcontextprotocol/clientInfoandio.modelcontextprotocol/clientCapabilities. There is noinitializehandshake. - Streamable HTTP: no sessions. No
Mcp-Session-Id, no protocol-level sessions. Send theMCP-Protocol-Versionheader and the standardMcp-Method/Mcp-Nameheaders on POST. SSE stream resumability andLast-Event-IDare removed. - Tasks extension. Long-running tools return a result with
resultTypeset; usetasks/getto poll andtasks/updatefor client-to-server input. The extension identifier isio.modelcontextprotocol/tasksand it is only available to clients that declare it in per-requestclientCapabilities.extensions. - OAuth 2.1. Authorization Code with PKCE (
S256only;code_verifier43-128 chars). Client ID Metadata Documents replace Dynamic Client Registration, which is deprecated but kept for backwards compatibility with ASes that do not support the document flow (2026-07-28 changelog, PR #2858). Key persisted credentials by issuer and re-register when the issuer changes. Validateissbefore redeeming the code (RFC 9207, SEP-2468). Full ordered flow inreferences/oauth-flow.md. - Map error codes.
-32000..-32019implementation-defined (grandfathered),-32020..-32099reserved for MCP:-32020HeaderMismatch,-32021MissingRequiredClient Capability,-32022UnsupportedProtocolVersion.server/discoverfailures return-32601(Method not found) with HTTP 404. - Verify statelessness. Replay a request with the same
_metaand assert an identical result; assert no session state between requests.
Decision tables
- Capability negotiation: client version ∈ server
supportedVersions-> use the highest common version; no overlap -> refuse with-32022, never silently downgrade. - Result handling:
resultType: "complete"-> ordinary result;"input_required"-> Multi Round-Trip Request, retry withinputResponses;"task"-> Tasks extension. - Deprecations: Roots, Sampling, Logging are deprecated (pass roots as tool params or resource URIs, call provider APIs directly, log to stderr or OpenTelemetry). HTTP+SSE is deprecated; use Streamable HTTP.
_metacompleteness: all four reserved keys must be present on every request —io.modelcontextprotocol/protocolVersion,io.modelcontextprotocol/clientInfo,io.modelcontextprotocol/clientCapabilities, and optionallyio.modelcontextprotocol/logLevel. Missing any of the first three ->-32021(HTTP 403).- Tasks availability: the
io.modelcontextprotocol/tasksextension is usable only when BOTH the server advertised it inserver/discover.capabilities.extensionsAND the client declares it in per-requestclientCapabilities.extensions. Either missing -> the tasks methods return-32601or-32021. resultTypedispatch:complete-> ordinary result;input_required-> Multi Round-Trip Request, respond withtasks/update+inputResponses;task-> Tasks extension, poll withtasks/get. AbsentresultType-> short tool, block normally.
Near-miss triggers (stop and re-check before proceeding)
- A server still sending
Mcp-Session-Idor aninitializehandshake -> not 2026-07-28. - Hardcoding a version string in logic -> it goes stale; read from config/env.
- Assuming
tasks/resultexists -> it was removed; usetasks/get. - Using Dynamic Client Registration for a new client -> it is deprecated; use Client ID Metadata Documents.
- Reusing credentials across authorization servers -> credentials are bound to the issuer.
- Sending
_metaonly on the first request ->-32021on the second. Per-request means per-request. - Calling
tasks/resultortasks/list->-32601. Usetasks/get/tasks/update. - Treating
input_requiredas an error -> it is a legitimate MRTR; respond, do not abort. - A server that advertises
tasksinserver/discoverbut the client omits the extension fromclientCapabilities-> the tasks methods are unavailable (-32021).
Pitfalls from research
- P1: Shipping a 2025-06-18 server that breaks on a 2026-07-28 client because the initialize handshake was removed.
- P2: Neglecting
server/discover— it is a MUST, not a MAY. - P3: Forgetting that per-request
clientCapabilitiesmust be sent on every request; servers MUST NOT infer capabilities from prior requests. - P4: Treating
allowed-toolsas a hard gate — it is experimental metadata. - P5: Casing of
Mcp-*headers — treat as case-insensitive per HTTP and pin in config.
Verification checklist
- Revision pinned in config, read from env with fallback.
-
server/discoverimplemented and returning supportedVersions, capabilities, serverInfo. - Every request carries
_metawith protocolVersion, clientInfo, clientCapabilities. - No
Mcp-Session-Id, noinitializehandshake, no SSE resumability. - Tasks handled via
tasks/get+tasks/update, nevertasks/result. - OAuth uses Authorization Code + PKCE with Client ID Metadata Documents.
- Error codes mapped to actions;
-32022used for version refusal. - Statelessness proven by a replay test.
-
server/discoverresult validated byscripts/protocol_check.py --json(valid: true). - Version agreement recorded by
scripts/version_negotiate.py --json. -
_metapresent on every request with all four reserved keys. - Tasks extension declared on both sides before any
tasks/*call. -
resultTypedispatch table applied: complete / input_required / task. -
scripts/stateless_probe.pypasses on a replay pair.
Worked examples
Good and bad client behaviour, with the detection signal for each, live in
references/examples.md (discover-first negotiation, -32022 refusal, tasks
extension, header-casing trap).
Related skills
- skill-authoring-evals — an MCP skill is a skill like any other; audit its description and evals the same way.
References
- changelog: references/changelog.md
- error codes: references/error-codes.md
- oauth flow: references/oauth-flow.md
- server/discover: references/server-discover.md
- per-request _meta: references/meta-schema.md
- tasks extension: references/tasks-extension.md
- compat matrix: references/compat-matrix.md
- compat versions: references/compat-versions.md
- examples: references/examples.md
- DESIGN: references/DESIGN.md
- EVALS: references/EVALS.md
- SOURCES: references/SOURCES.md
- scripts: scripts/protocol_check.py, scripts/stateless_probe.py, scripts/version_negotiate.py