17 KiB
MCP Specification — 2026-07-28 Draft (RC)
Status: Draft / Release Candidate (pre-release). Subject to change — not final. Tag:
2026-07-28-RC· rendered at/specification/draftSpec site: https://modelcontextprotocol.io/specification/draft Authoritative schema: schema/draft/schema.ts
The 2026-07-28 draft is a foundational redesign of the Model Context Protocol, not an incremental revision. It moves from the prior stateful-connection model to a stateless base protocol with self-contained requests, replaces connection-level capability negotiation (the initialize handshake) with per-request capability negotiation, and introduces a formal extensions framework for opt-in modular functionality. Several older client/server features are deprecated under a new feature-lifecycle policy. This is the direction future Skald MCP work should anticipate; the per-request shift and the Tasks extension are the most impactful changes to plan for.
At a glance
- Protocol style: stateless, self-contained requests (no session state inferred across requests)
- Capability negotiation: per-request, via
_meta.io.modelcontextprotocol/clientCapabilities - Transports: stdio (newline-delimited JSON-RPC over a client-launched subprocess) and Streamable HTTP (single MCP endpoint;
POSTper message, request-scoped SSE for replies). Custom transports MAY be defined. (HTTP+SSE was deprecated earlier, in2025-03-26.) - Server features: Resources, Prompts, Tools
- Client features (core): Elicitation only. (Sampling and Roots are deprecated — see below.)
- Extensions (opt-in): Tasks (
io.modelcontextprotocol/tasks), MCP Apps (io.modelcontextprotocol/ui), Skills over MCP (in Working Group / experimental), OAuth client-credentials, enterprise-managed authorization, … - Authorization: OAuth 2.1 + PKCE, HTTP transports only; stdio uses environment credentials
The redesign (why this matters)
Three structural changes define this draft:
- Stateless base protocol. All information needed to process a request is contained in the request itself — protocol version, client identity, and capabilities travel in the
_metafield on every request. Servers MUST NOT rely on prior requests to establish context, and SHOULD handle requests associated with multiple tasks/threads/conversations. - Per-request capability negotiation. The connection-level
initializehandshake is gone for modern clients; capabilities are declared on each request, and the server's capabilities are discoverable viaserver/discover. This replaces session-scoped negotiation entirely. - Extensions framework. Optional, always opt-in, modular capabilities (Tasks, MCP Apps, …) negotiated through the
extensionsfield of capabilities. Core client features are trimmed to Elicitation; Sampling, Roots, and Logging move to deprecated status under a formal lifecycle policy (not silent removal).
Architecture
The client-host-server topology is retained. A host creates and manages multiple client instances; each client has a 1:1 relationship with exactly one server and enforces isolation (a server cannot see the whole conversation or other servers). The change is that clients now "attach protocol version and capabilities to every request" rather than establishing a session. Servers expose resources/tools/prompts and MAY request client input (sampling/elicitation/roots) by returning an InputRequiredResult within a reply. Design principles are unchanged: servers should be easy to build, highly composable, mutually isolated, and progressively extensible.
Base Protocol
Messages
All messages MUST be JSON-RPC 2.0, UTF-8 encoded. Three kinds: Requests (with a string/integer id; the id MUST NOT be null and MUST NOT match any in-flight request id), Responses, and Notifications (no id; receiver MUST NOT reply). A notable addition is polymorphic results: every result MUST include a resultType field — "complete" (final content), "input_required" (an InputRequiredResult, driving a multi-round-trip request), or extension-defined values; an absent resultType MUST be treated as "complete" for backward compatibility. JSON-RPC's reserved server-error range is now partitioned: -32000–-32019 is legacy (new codes MUST NOT be allocated there); -32020–-32099 is reserved for the MCP specification. Defined codes: -32020 HeaderMismatch, -32021 MissingRequiredClientCapability, -32022 UnsupportedProtocolVersion. Three message patterns are supported: Request/Response, Multi Round-Trip Requests (MRTR), and Subscribe/Notify (subscriptions/listen).
Lifecycle / Negotiation
There is no negotiation handshake in the modern protocol. Every request declares its protocol version in _meta (also mirrored in the MCP-Protocol-Version header on HTTP). If the server does not support the requested version it MUST respond UnsupportedProtocolVersionError (-32022) listing its supported versions; the client SHOULD pick a mutually supported version and retry. Servers MUST implement server/discover; clients MAY call it first to learn supported versions and capabilities up front, but are free to invoke any RPC inline and handle the error. Capability negotiation is therefore per-request: clients advertise capabilities in _meta.io.modelcontextprotocol/clientCapabilities; servers expose theirs through server/discover. Extensions are advertised the same way, via a capabilities.extensions map keyed by extension identifier.
Transports
A transport is a binding (framing + metadata + cancellation signalling); message semantics are identical on every transport. Two standard bindings:
- stdio — newline-delimited JSON-RPC over a client-launched subprocess;
notifications/cancelledabandons an in-flight request. Clients SHOULD NOT tie the subprocess lifetime to a single task/thread/conversation. - Streamable HTTP — every client message is a
POSTto a single MCP endpoint; a reply arrives as a JSON object or a request-scoped SSE stream. Selected_metafields are mirrored into HTTP headers so intermediaries can route without parsing the body (body remains source of truth). Cancellation closes the response stream.
Custom transports MAY be defined but MUST preserve JSON-RPC format, the message patterns, and the per-request metadata model; those over a reliable byte stream SHOULD reuse stdio framing.
Authorization
Optional. For HTTP transports it is built on OAuth 2.1 with PKCE; stdio SHOULD NOT use it and instead retrieves credentials from the environment. The MCP server is an OAuth 2.1 resource server and MUST implement OAuth 2.0 Protected Resource Metadata (RFC 9728), signalling the metadata URL via WWW-Authenticate on 401. Authorization servers MUST provide discovery via OAuth 2.0 Authorization Server Metadata (RFC 8414) or OIDC Discovery; clients MUST support both. Client registration priority: Client ID Metadata Documents (new, preferred) → pre-registered → Dynamic Client Registration (RFC 7591, now deprecated). Resource Indicators (RFC 8707) and the iss parameter (RFC 9207) apply. Servers SHOULD advertise required scope in the WWW-Authenticate challenge; clients follow a least-privilege scope-selection strategy with step-up authorization.
Versioning
Protocol versions are date strings (e.g. 2026-07-28). Terminology: Modern = per-request metadata (this revision and later); Legacy = initialize-handshake versions (2025-11-25 and earlier); Dual-era = implementations supporting both. A dual-era server selects behaviour from how the client opens: a request carrying modern _meta is served statelessly; an initialize request selects legacy semantics. Clients detect a server's era via transport-specific probing (stdio: server/discover and fall back on any non-modern error; HTTP: attempt a modern request and inspect a 400 body). The era is a property of the server and SHOULD be cached for the process/origin lifetime. A full compatibility matrix (Modern/Legacy/Dual-era × client/server) is specified.
Server Features
Servers advertise implemented primitives in their capabilities. Control model unchanged: Prompts user-controlled, Resources application-controlled, Tools model-controlled.
Resources
Context/data exposed by the server, addressed by URI. Discovery and reading are RPC-driven; clients open a subscriptions/listen stream to receive notifications/* (tagged with a subscriptionId) when resources change. The old -32002 "resource not found" code is replaced by -32602; clients SHOULD still accept -32002 from legacy servers.
Prompts
Templated messages/workflows invoked by user choice (e.g. slash commands, menu options). Listed and fetched on demand; the model does not pick them autonomously.
Tools
Functions exposed to the LLM (model-controlled). Tool invocation requires the server to declare tool capabilities. Tools MAY return structured output, and — via extensions such as MCP Apps — can reference interactive UI resources.
Utilities
Cross-cutting concerns now consist of Configuration, Progress tracking, Cancellation, and Error reporting. Logging is no longer a core utility: it is deprecated (SEP-2577). The migration path is to log to stderr for stdio transports and to use OpenTelemetry for observability.
Client Features
Elicitation
The only core client feature. Servers MAY request user input during request processing by returning an InputRequiredResult containing an elicitation/create request. Two modes:
- Form mode — in-band structured data with optional JSON-Schema validation. Schemas are restricted to flat objects of primitive properties (string/number/integer/boolean/enum). Servers MUST NOT use form mode to request secrets (passwords, API keys, tokens, payment credentials).
- URL mode — out-of-band interaction via URL navigation; data (other than the URL) is not exposed to the client. Servers MUST use URL mode for sensitive information.
Clients supporting elicitation MUST declare _meta.io.modelcontextprotocol/clientCapabilities.elicitation (with form and/or url sub-capabilities; empty object ≡ form only) on each request. Clients MUST make clear which server is asking, and provide decline/cancel options.
Extensions (new)
Overview
Extensions are optional additions beyond the core protocol — modular, specialized, or experimental. They are identified by {vendor-prefix}/{extension-name} (official ones use io.modelcontextprotocol/), advertised in the capabilities.extensions map (per-request), and always disabled by default — requiring explicit opt-in from both sides. If one side supports an extension the other lacks, it MUST fall back to core behaviour or reject with an appropriate error. Extensions evolve independently and SHOULD use capability flags or in-extension versioning rather than new identifiers for breaking changes. Official extensions live in ext-* repositories; experimental ones (incubating in Working/Interest Groups) use the experimental-ext- prefix.
Tasks
Extension io.modelcontextprotocol/tasks (repo ext-tasks). Lets a server return a durable handle instead of blocking on long-running operations (CI pipelines, batch jobs, human approvals). Flow: the client declares the extension per-request; when a request will be long-running the server returns a CreateTaskResult (resultType: "task") carrying a taskId, initial status, TTL, and suggested pollIntervalMs; the client polls tasks/get; if status becomes input_required, the response carries inputRequests which the client fulfils via tasks/update; terminal states are completed / failed / cancelled. The client MAY send tasks/cancel (cooperative). Servers MAY push notifications/tasks via subscriptions/listen; polling remains the default. Task IDs are durable and survive client disconnect/restart.
Skills over MCP
An emerging extension (Skills Over MCP Working Group; current direction is SEP-2640, a Resources-based Extensions-Track proposal; reference work in experimental-ext-skills). It defines how "agent skills" — rich, structured instructions for agent workflows — are discovered, distributed, and consumed through MCP. Not yet a finalized official extension at the time of this draft.
MCP Apps
Extension io.modelcontextprotocol/ui (repo ext-apps). Lets a server return interactive HTML (charts, forms, video players, dashboards) rendered inline in the conversation. A tool declares a UI reference via _meta.ui.resourceUri pointing at a ui:// resource; the host fetches and renders the HTML inside a sandboxed iframe, isolated from the parent page. Communication uses a JSON-RPC dialect over postMessage with a ui/ method prefix (e.g. ui/initialize); _meta.ui.csp and _meta.ui.permissions control loading and capabilities. Already supported by several clients (Claude, Claude Desktop, VS Code Copilot, Microsoft 365 Copilot, Goose, Postman, and others).
Changes vs 2025-11-25
- Stateless base protocol: requests are self-contained; servers MUST NOT rely on connection/session state.
- Per-request capability negotiation replaces the
initializehandshake;server/discoverprovides up-front discovery. - Polymorphic results (
resultType:complete/input_required/ extension values) and a formal MRTR pattern viaInputRequiredResult. - New spec-reserved error range (
-32020–-32099) and codes (HeaderMismatch,MissingRequiredClientCapability,UnsupportedProtocolVersion). - Elicitation is the only core client feature; Sampling and Roots are deprecated (SEP-2577), retained ≥12 months, eligible for removal in the first revision released on/after 2027-07-28. Migration: Roots → tool parameters/resource URIs/server configuration; Sampling → integrate directly with LLM provider APIs.
- Logging deprecated as a utility (SEP-2577) →
stderr/ OpenTelemetry. - Dynamic Client Registration deprecated (→ Client ID Metadata Documents).
- Extensions framework introduced; Tasks stabilized as an official extension (
io.modelcontextprotocol/tasks), MCP Apps added (io.modelcontextprotocol/ui), Skills over MCP incubating.
Skald relevance
Skald's MCP surface lives in crates/mcp-client/ (the McpServer stdio wrapper, McpHttpServer, and the McpServerClient trait), src/core/mcp/ (McpManager), and src/core/elicitation/ (ElicitationManager + bridge, surfaced in the Inbox). Two draft changes matter most for future planning: (1) the stateless / per-request shift means capability and version metadata must be attached to every request rather than assumed from a session, and server/discover becomes the discovery primitive; (2) the Tasks extension maps closely onto Skald's async/background work and would let MCP servers return durable, pollable handles for long-running operations. Skald's existing elicitation bridge already corresponds to the one remaining core client feature, so that path forward is well aligned. Until the draft finalizes, treat Sampling/Roots/Logging as deprecated-but-present for interop only.
References
- Specification (draft)
- Architecture
- Base protocol
- Versioning and compatibility
- Transports
- Authorization
- Server features
- Client features — Elicitation
- Deprecated features registry
- Extensions overview
- Tasks extension
- MCP Apps extension
- Skills over MCP Working Group
- Schema (schema.ts)
- Release 2026-07-28-RC