Research notes (June 2026). Everything an MCP implementation can offer, on both sides of the wire: the primitives, the utilities, the transports, authorization, and where the protocol is heading (the 2026-07-28 release candidate changes the picture substantially). Companion to the deep-dive notes on resources, prompts, and the LSP comparison.
Spec versions to date: 2024-11-05, 2025-03-26 (Streamable HTTP, OAuth), 2025-06-18 (elicitation, structured tool output, resource indicators), 2025-11-25 (current stable), 2026-07-28 (release candidate, locked May 21 2026).
Host application (Claude Code, an IDE, a chat app) runs an MCP client per connection; each client talks JSON-RPC 2.0 to one server. Both sides declare capabilities during initialization and only negotiated features exist in the session. Messages are requests (expect a response), notifications (fire and forget), and responses; both directions can send requests. The wire format is UTF-8 JSON-RPC over a transport (section 6).
initialize(client -> server): carriesprotocolVersion,capabilities,clientInfo. Server answers with itscapabilities,serverInfo, optionalinstructions(free text the host can inject into model context; in Claude Code this is auto-injected and truncated at ~2KB, and it is the single most reliable way for a server to steer model behavior).notifications/initializedconfirms; then normal traffic.- Version negotiation: client proposes a version, server answers with the same or its closest supported; client disconnects if incompatible.
| Primitive | Controlled by | Methods | Notes |
|---|---|---|---|
| Tools | model | tools/list, tools/call, notifications/tools/list_changed |
The only model-driven primitive. Input via JSON Schema; since 2025-06-18 also outputSchema + structuredContent for typed results. Annotations: readOnlyHint, destructiveHint, idempotentHint, openWorldHint (advisory, not security). |
| Resources | application/user | resources/list, resources/read, resources/templates/list, resources/subscribe, notifications/resources/updated, notifications/resources/list_changed |
Read-only data behind URIs; RFC 6570 templates; text or base64 blob; annotations (audience, priority, lastModified). In Claude Code only surfaced via user @-mention. |
| Prompts | user | prompts/list, prompts/get, notifications/prompts/list_changed |
Parameterized message templates; multi-modal content incl. embedded resources. In Claude Code surfaced as /mcp__server__prompt slash commands. |
Capability flags: tools: {listChanged}, resources: {subscribe, listChanged},
prompts: {listChanged}.
These run in the reverse direction: the server asks, the client (and its user) answers. All three require the client to declare the capability.
Server asks the client to run an LLM completion: sampling/createMessage with
messages (text/image/audio), systemPrompt, maxTokens, and
modelPreferences: hints (substring model-name suggestions, in preference
order) plus three normalized priorities (costPriority, speedPriority,
intelligencePriority). The client controls the actual model and SHOULD keep a
human in the loop on both the request and the response. Lets a server be
"agentic" without owning an API key. Deprecated in the 2026-07-28 RC (12+
month window): direction is direct LLM provider integration instead.
Client exposes filesystem scope to the server: roots/list returns
{uri: "file:///...", name} entries; notifications/roots/list_changed on
change. Defines where the server may operate (workspace boundaries). Client
must guard against path traversal. Deprecated in the 2026-07-28 RC:
direction is tool parameters or configuration instead.
Server requests structured input from the USER mid-flow: elicitation/create
with a message and a requestedSchema (deliberately restricted to a FLAT
object of primitives: string with optional format email/uri/date/date-time,
number/integer with min/max, boolean, enum). Response is one of three actions:
accept (with content matching the schema), decline, or cancel. Servers
MUST NOT elicit sensitive information. This is the standard way to do
"confirm/configure before proceeding" interactively.
- Ping:
pingrequest either way; health check. - Progress: caller attaches a
progressTokenin_meta; receiver emitsnotifications/progress(progress, optionaltotal,message). - Cancellation:
notifications/cancelledwith therequestIdto abort an in-flight request. - Logging (
loggingcapability): client sets level vialogging/setLevel; server emitsnotifications/message(RFC 5424 levels). Deprecated in the 2026-07-28 RC: direction is stderr or OpenTelemetry. - Completion (
completionscapability):completion/completeautocompletes prompt arguments and resource-template variables (the "IDE-style argument autocomplete" for primitives). - Pagination: list operations take a
cursorand returnnextCursor. _meta: extension point on most objects for protocol- and app-level metadata.
Client launches the server as a subprocess; newline-delimited JSON-RPC on stdin/stdout (no embedded newlines); stderr is free-form logging. Nothing but MCP messages may touch stdout (one stray print corrupts the channel).
One MCP endpoint supporting POST and GET:
- Every client message is a POST with
Accept: application/json, text/event-stream. Server answers a request either with a single JSON body or by opening an SSE stream (response arrives as an event, possibly after server-initiated requests/notifications). - GET opens a server-to-client SSE stream for unsolicited messages.
- Sessions: server MAY issue
Mcp-Session-Idon initialize; client then sends it on every request; 404 means re-initialize; DELETE ends the session. - Resumability: SSE event
ids +Last-Event-IDheader replay missed messages per-stream. MCP-Protocol-Versionheader REQUIRED on subsequent HTTP requests.- Security: MUST validate
Origin(DNS-rebinding defense), SHOULD bind localhost only when local, SHOULD authenticate.
Allowed; must preserve JSON-RPC framing and lifecycle.
OAuth 2.1 stack, subset profile:
- MCP server = resource server; MUST serve Protected Resource Metadata
(RFC 9728) advertising its authorization server(s); 401 responses carry
WWW-Authenticatepointing at the metadata. - Client MUST do AS metadata discovery (RFC 8414); SHOULD use Dynamic Client
Registration (RFC 7591); MUST use PKCE; MUST send the RFC 8707
resourceparameter binding tokens to the specific server. - Tokens:
Authorization: Bearerheader only (never query string); server MUST validate audience; token passthrough to upstream APIs is explicitly forbidden (confused-deputy defense). - stdio servers do not use this; they take credentials from the environment.
- Stateless redesign: initialize handshake and
Mcp-Session-Idremoved; client info and protocol version travel in_metaon every request; newserver/discoverreplaces capability exchange. Servers can sit behind plain load balancers. - Routing/caching headers: required
Mcp-Method/Mcp-Nameheaders; list responses gainttlMsandcacheScope; W3C Trace Context propagation. - Extensions framework (SEP-2133 lineage): first-class extensions with
reverse-DNS ids, capability-map negotiation, independent versioning. Official
extensions: MCP Apps (server-rendered HTML in sandboxed iframes) and
Tasks (a
tools/callmay return a task handle for long-running, client-polled operations). - Deprecations (12+ month windows): roots, sampling, logging.
- Schema upgrade: tool input/output schemas become full JSON Schema 2020-12; resource-not-found error moves from -32002 to -32602.
- Authorization hardening: mandatory
issvalidation,application_typeat registration, scope accumulation clarified.
| You want | Use |
|---|---|
| Model performs an action or fetch on demand | Tool (the only model-triggered option) |
| Steer model behavior automatically, every session | instructions (initialize result) + concise tool descriptions |
| Background data the user can attach | Resource (@-mention in Claude Code) |
| Reusable user-fired command | Prompt (slash command in Claude Code) |
| Ask the user a structured question mid-operation | Elicitation |
| Long-running operation | Progress notifications now; Tasks extension when final |
| Argument autocomplete | Completion capability |
| Local single-user deployment | stdio, or Streamable HTTP daemon bound to 127.0.0.1 with Origin validation |
| Multi-client shared/warm deployment | Streamable HTTP (+ sessions today; stateless after the RC lands) |
| Remote multi-tenant deployment | Streamable HTTP + the OAuth 2.1 stack |
| Server needs an LLM / filesystem scope / log channel | Sampling / roots / logging exist today but are RC-deprecated; prefer direct integration, tool params, stderr/OTel |
Ships today: tools (14), resources (skyline://guide), instructions, stdio +
Streamable HTTP daemon (localhost-bound), and a self-reported tool-manifest
digest for drift detection. Unused options with plausible value: elicitation
(confirm before a large non-dry-run srewrite), completion (autocomplete for
language names), Tasks once final (directory-wide rewrites as polled tasks).
Skippable: sampling/roots/logging (RC-deprecated), prompts (the agent prompts
live in the README), OAuth (localhost daemon).
- Spec index: https://modelcontextprotocol.io/specification/2025-06-18
- Sampling: https://modelcontextprotocol.io/specification/2025-06-18/client/sampling
- Roots: https://modelcontextprotocol.io/specification/2025-06-18/client/roots
- Elicitation: https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation
- Transports: https://modelcontextprotocol.io/specification/2025-06-18/basic/transports
- Authorization: https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization
- 2026-07-28 release candidate: https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/
- Companion notes: MCP resources, MCP prompts, LSP primitives (separate gists)