TL;DR

MCP 2026-07-28 is not a small update to the 2025 protocol. It introduces a modern, stateless era: no initialize handshake, no protocol-level Session ID, no GET event stream, and no SSE resume. Every request declares its protocol version, client identity, and capabilities; servers expose server/discover; server-to-client requests become Multi Round-Trip Request results; and optional features move into negotiated extensions. Upgrade through a dual-era compatibility layer, not an in-place header rename.

Table of Contents

  1. Version Timeline
  2. The Modern Stateless Model
  3. Streamable HTTP Changes
  4. Multi Round-Trip Requests
  5. OAuth Authorization Changes
  6. Skills and Tasks Extensions
  7. Tool Contracts and Cache Hints
  8. Runnable Request Validator
  9. Dual-Era Migration Plan
  10. Conformance and Abuse Tests
  11. Frequently Asked Questions
  12. Primary Sources

Version Timeline

Read every MCP claim against a pinned revision. Features added in one 2025 revision may be changed, deprecated, or removed in 2026.

Revision High-impact changes
2025-03-26 introduced Streamable HTTP, OAuth-based authorization, tool annotations, and JSON-RPC batching
2025-06-18 removed JSON-RPC batching; added structured tool output, protected-resource metadata, Resource Indicators, and elicitation
2025-11-25 added OIDC discovery, incremental scope consent, Client ID Metadata Documents, URL elicitation, and experimental tasks
2026-07-28 removed initialization and protocol sessions; added per-request metadata, server/discover, MRTR, subscriptions/listen, required resultType, cache hints, and negotiated extensions

This history exposes a practical rule: MCP version is part of the wire contract, not documentation metadata. Store it alongside SDK, transport, and authorization-profile versions.

The Modern Stateless Model

MCP calls revision 2026-07-28 and later modern; versions through 2025-11-25 are legacy because they establish state through initialize.

Every modern request includes these _meta fields:

  • io.modelcontextprotocol/protocolVersion
  • io.modelcontextprotocol/clientCapabilities
  • preferably io.modelcontextprotocol/clientInfo

Every result contains resultType. Ordinary results use "complete"; MRTR uses "input_required"; negotiated extensions may add values such as "task".

Servers must implement server/discover to advertise supported versions, capabilities, and identity. Clients may call it before normal requests or optimistically send a preferred version and handle UnsupportedProtocolVersionError (-32022).

sequenceDiagram participant C as Modern client participant S as MCP server C->>S: server/discover with per-request _meta S-->>C: versions, identity, capabilities C->>S: tools/list with selected version S-->>C: resultType complete plus cache hints C->>S: tools/call with selected version S-->>C: complete, input_required, or negotiated task

Stateless does not mean an implementation cannot own business state. It means protocol state is not implicit in a connection or Mcp-Session-Id. A tool that needs continuity must return an explicit server-minted handle and receive it in later arguments.

Streamable HTTP Changes

Modern Streamable HTTP uses one endpoint and one POST per JSON-RPC request or notification. The response is either one JSON object or a request-scoped SSE stream.

The 2026-07-28 revision removes:

  • the GET stream endpoint
  • Mcp-Session-Id
  • SSE event IDs and Last-Event-ID replay
  • independent server-initiated JSON-RPC requests

It adds or requires:

  • MCP-Protocol-Version on each POST
  • matching protocol version in request-body _meta
  • Mcp-Method for requests
  • Mcp-Name for tools/call, resources/read, and prompts/get
  • cancellation by closing the request's SSE response stream
  • subscriptions/listen for opted-in long-lived change notifications

If an in-flight SSE response breaks, the client cannot resume it. The client must decide whether the logical operation is safe to issue again, create a new JSON-RPC ID, and rely on application idempotency for side effects.

Transport security still requires Origin validation. An invalid Origin must receive HTTP 403. Local servers should bind to loopback rather than all interfaces.

Multi Round-Trip Requests

MRTR replaces separate server-initiated requests for Sampling, Elicitation, and Roots.

When a server needs additional input:

  1. it returns resultType: "input_required"
  2. inputRequests contains one or more requested interactions
  3. optional opaque requestState preserves server correlation
  4. the client gathers approved responses
  5. the client retries the original method with a new JSON-RPC ID, inputResponses, and requestState

The client must treat requested model sampling, user elicitation, or roots access according to its normal trust and consent model. MRTR changes message flow; it does not grant the server those capabilities.

Validate:

  • each input-request key is unique and recognized
  • retries use a new request ID
  • requestState is treated as opaque and bounded
  • repeated or already-satisfied keys are rejected or deduplicated
  • cancellation and deadline still cover the full logical operation

OAuth Authorization Changes

Authorization remains optional for MCP as a whole. HTTP implementations that support authorization should follow the MCP profile; stdio implementations should obtain credentials from the environment rather than running the HTTP OAuth flow.

For a protected remote MCP server:

  1. the MCP server acts as an OAuth resource server
  2. it publishes RFC 9728 Protected Resource Metadata
  3. the client discovers and validates authorization-server metadata
  4. the client obtains a client ID
  5. authorization and token requests include RFC 8707 resource
  6. each MCP HTTP request carries Authorization: Bearer ...
  7. the server validates issuer, audience, expiry, signature, and scope

Client registration priority

MCP 2026-07-28 defines this preferred order:

  1. pre-registered credentials when available
  2. Client ID Metadata Documents when the authorization server advertises support
  3. RFC 7591 Dynamic Client Registration as a deprecated compatibility fallback
  4. user-provided client information

Persisted client credentials must be keyed by authorization-server issuer and must not be reused after the issuer changes. Client ID Metadata Document identifiers are self-hosted HTTPS URLs and follow their own validation rules.

Scope and issuer validation

Use the scope in WWW-Authenticate as authoritative for the current operation when present. A runtime 403 with insufficient_scope can trigger step-up authorization, but the client should request the union of newly required and previously granted scopes.

Authorization servers should return RFC 9207 iss; clients must validate a present value against the issuer recorded before redirect. Resource servers must reject tokens not intended for their own canonical resource. Never forward an incoming token to a downstream service unless token exchange or another explicit delegation design authorizes it.

Skills and Tasks Extensions

MCP 2026-07-28 introduces an extensions capability map. An extension is usable only when the required party declares it.

Skills

The io.modelcontextprotocol/skills extension publishes Agent Skills through Resources:

  • skills/list enumerates Skill entries
  • skills/get returns one entry
  • resources/read retrieves SKILL.md and supporting files
  • optional resources/directory/read lists directory children

Skill identity is the pair of originating server identity and Skill URI. File digests protect integrity during the acting window but do not establish publisher trust. Activating a nested Skill requires fresh consent.

Tasks

The io.modelcontextprotocol/tasks extension currently augments tools/call. A server may return resultType: "task" with a durable task handle after the client advertises support. Clients then use:

  • tasks/get to poll
  • tasks/update to answer outstanding input requests
  • tasks/cancel to request cancellation

The server decides whether to materialize a task. A task handle must not be returned until tasks/get can resolve it. Task IDs, TTLs, polling intervals, authorization, and terminal results need durable storage and tenant isolation.

Tool Contracts and Cache Hints

Modern tool descriptors use JSON Schema and may declare outputSchema. If an output schema exists, servers must return conforming structuredContent, and clients should validate it. For backward compatibility, structured results should also provide serialized text content.

Tool annotations remain hints, not security controls. Read-only, destructive, idempotent, and open-world declarations cannot replace server-side authorization or side-effect checks.

List and read results now carry:

  • ttlMs: freshness hint in milliseconds
  • cacheScope: "public" or "private"

Cache keys still need protocol version, authorization context, origin, method, name or URI, cursor, and relevant arguments. A freshness hint is not permission to share private data.

The x-mcp-header JSON Schema annotation can mirror selected primitive tool parameters into Mcp-Param-* HTTP headers. Clients must reject invalid annotations and should never mirror secrets or personal data into headers.

Runnable Request Validator

The following standard-library Go program builds and validates one modern tools/list request. A production client must also emit matching HTTP headers and validate the full schema, but this example makes the per-request metadata invariant executable.

go
package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
)

const protocolVersion = "2026-07-28"

type ClientInfo struct {
	Name    string `json:"name"`
	Version string `json:"version"`
}

type Meta struct {
	ProtocolVersion    string         `json:"io.modelcontextprotocol/protocolVersion"`
	ClientInfo         ClientInfo     `json:"io.modelcontextprotocol/clientInfo"`
	ClientCapabilities map[string]any `json:"io.modelcontextprotocol/clientCapabilities"`
}

type Params struct {
	Cursor string `json:"cursor,omitempty"`
	Meta   Meta   `json:"_meta"`
}

type Request struct {
	JSONRPC string `json:"jsonrpc"`
	ID      int    `json:"id"`
	Method  string `json:"method"`
	Params  Params `json:"params"`
}

func validateRequest(request Request, headerVersion string) error {
	if request.JSONRPC != "2.0" {
		return errors.New("jsonrpc must be 2.0")
	}
	if request.ID == 0 || request.Method == "" {
		return errors.New("request id and method are required")
	}
	if request.Params.Meta.ProtocolVersion != protocolVersion {
		return fmt.Errorf(
			"unsupported protocol version %q",
			request.Params.Meta.ProtocolVersion,
		)
	}
	if headerVersion != request.Params.Meta.ProtocolVersion {
		return errors.New("MCP-Protocol-Version header mismatch")
	}
	if request.Params.Meta.ClientInfo.Name == "" {
		return errors.New("clientInfo.name is required by local policy")
	}
	if request.Params.Meta.ClientCapabilities == nil {
		return errors.New("clientCapabilities must be present")
	}
	return nil
}

func main() {
	request := Request{
		JSONRPC: "2.0",
		ID:      1,
		Method:  "tools/list",
		Params: Params{
			Meta: Meta{
				ProtocolVersion: protocolVersion,
				ClientInfo: ClientInfo{
					Name:    "example-client",
					Version: "1.0.0",
				},
				ClientCapabilities: map[string]any{
					"extensions": map[string]any{},
				},
			},
		},
	}

	if err := validateRequest(request, protocolVersion); err != nil {
		log.Fatal(err)
	}
	body, err := json.MarshalIndent(request, "", "  ")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(body))
}

The request also needs these HTTP headers:

http
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/list

For tools/call, add Mcp-Name from params.name. The HTTP version and body version must match.

Dual-Era Migration Plan

1. Inventory actual behavior

Record every client and server's protocol revisions, SDK version, transport, authorization profile, extensions, session use, server-initiated requests, streaming, and retry behavior. Do not infer support from package version alone.

2. Add a protocol boundary

Centralize version detection, request metadata, headers, result decoding, and transport behavior. Business tools should not know whether the peer is modern or legacy.

3. Implement modern behavior

Add server/discover, per-request metadata, required HTTP headers, resultType, request-scoped streaming, MRTR, subscription streams, cache hints, and selected extensions.

4. Isolate legacy behavior

A dual-era implementation can fall back to initialize and legacy Streamable HTTP only after the transport-specific probe identifies a legacy server. Cache the detected era per stdio process or HTTP origin and re-probe when the assumption fails.

5. Remove implicit session state

Replace Mcp-Session-Id state with explicit, server-minted handles passed as normal arguments. Bind each handle to identity, tenant, expiry, and operation class.

6. Shadow and canary

Replay a sanitized conformance corpus against both paths. Compare logical results, authorization decisions, stream behavior, retries, and side effects. Route a small cohort to modern mode and keep independent rollback.

7. Retire legacy only with evidence

Measure real client versions and negotiation failures. Announce an end date, provide actionable errors, and remove legacy code only after supported traffic reaches the agreed threshold.

Conformance and Abuse Tests

Area Required tests
versioning supported version, unsupported version list, body/header mismatch
lifecycle modern request without initialize, legacy fallback, ambiguous errors
transport JSON response, SSE response, close-as-cancel, no replay
MRTR new request ID, opaque state, duplicate keys, denied user input
subscriptions opt-in types, subscription ID, disconnect cleanup
authorization metadata discovery, resource/audience, issuer binding, scope step-up
tools schema validation, output validation, annotation distrust, deterministic list
caching TTL expiry, private scope, auth-aware keys, list-change invalidation
Skills origin-plus-URI identity, digest mismatch, nested consent, path traversal
Tasks capability gate, durable creation, poll interval, tenant isolation, cancellation
side effects idempotency, retry after broken stream, duplicate request protection

Run the matrix against real SDK combinations. A schema-only test cannot prove proxy behavior, cancellation, authentication, or duplicate side-effect safety.

Frequently Asked Questions

Can a 2026 client send initialize for compatibility?

A dual-era client can probe and fall back according to the transport-specific rules. A modern-only client does not use initialize. Do not send both modern and legacy lifecycle messages speculatively on the same execution path.

Does stateless MCP remove all server state?

No. It removes implicit protocol session state. Servers may keep business state, jobs, subscriptions, caches, or explicit handles, but those objects need normal identity, authorization, expiry, and lifecycle rules.

Is SSE removed?

No. Streamable HTTP can return a request-scoped SSE stream, and subscriptions/listen uses a long-lived SSE response. The removed pieces are the standalone GET stream, protocol sessions, and SSE resume through event IDs.

Can cache hints be trusted across users?

Only when the result is public and the complete cache key is authorization-independent. cacheScope: "private" must not enter shared caches, and even public data needs version, origin, method, name, cursor, and argument dimensions.

Are Skills executable code?

A Skill is an instruction directory with supporting resources. It may reference scripts, but the host decides whether and how anything runs. The MCP Skills extension transports files; it does not bypass consent, sandboxing, or tool authorization.

Summary

MCP 2026-07-28 creates a cleaner stateless protocol, but it is a real compatibility boundary. Modern requests carry their own version and capabilities, HTTP streams are request-scoped, additional interaction uses MRTR, and optional systems such as Skills and Tasks are negotiated extensions. Migrate with explicit era detection, strict OAuth binding, idempotent retries, and a full conformance matrix.

Primary Sources