GUIDE
What an MCP server is, and what it is not
MCP standardizes the protocol layer between a language model and the systems it needs to reach. This note walks through the architecture, the server primitives, and where authorization actually happens — plus four things MCP is not.
Connecting a language model to an enterprise system is not a model problem. It is an integration problem. The Model Context Protocol (MCP) exists to standardize exactly that layer. This note treats MCP as a protocol rather than a product: what it specifies, what it deliberately declines to specify, and which box it occupies in an enterprise architecture. Every technical claim below is grounded in the official specification. Spec revisions use a YYYY-MM-DD identifier and are only incremented when a backwards-incompatible change lands. This note is based on revision 2025-11-25. The 2026-07-28 revision, due on 28 July 2026, makes the protocol stateless, removes the initialize handshake and the session identifier, moves Tasks out of the core into a separate extension, and marks Roots, Sampling and Logging deprecated with a twelve-month removal window. The session and primitive details below change in that revision.
Before the protocol: one bridge per pair
Prior to MCP, wiring an AI application to a data source meant writing bespoke code for that particular application-source pair. The original announcement frames it plainly: every new data source requires its own custom implementation, which makes truly connected systems difficult to scale. The industry shorthand for this is the N×M problem — N applications, M systems, N×M hand-written bridges between them. That label is not official terminology, but the situation it describes is described in the official text. The trade MCP proposes is straightforward: replace fragmented integrations with a single protocol, so each side implements the protocol once.
MCP was announced and open-sourced by Anthropic on 25 November 2024, created by David Soria Parra and Justin Spahr-Summers. The first release shipped in three parts: the specification and SDKs, local MCP server support in the Claude Desktop apps, and an open-source repository of ready-made servers for systems such as Google Drive, Slack, GitHub, Postgres and Puppeteer.
On 9 December 2025, Anthropic donated MCP to the Agentic AI Foundation (AAIF), a directed fund under the Linux Foundation. It was co-founded by Anthropic, Block and OpenAI, with support from Google, Microsoft, AWS, Cloudflare and Bloomberg. MCP is a founding project alongside goose and AGENTS.md. The maintainer structure carried over unchanged: the governing board handles budget, membership and approval of new projects, while individual projects retain full autonomy over technical direction. So describing MCP today as simply Anthropic’s protocol is incomplete. The accurate framing: originated and open-sourced by Anthropic, and since December 2025 governed under the AAIF within the Linux Foundation. The official documentation lists Claude, ChatGPT, Visual Studio Code, Cursor and MCPJam among clients that support it.
Architecture: host, client, server
MCP follows a client-server architecture and defines three distinct roles. The MCP host is the AI application that coordinates one or more MCP clients — Claude Code or VS Code, for example. An MCP client is the component that maintains a connection to a single server and obtains context on the host’s behalf. An MCP server is a program that provides context to MCP clients. The detail that matters operationally: the host creates a separate client object per server, and each client holds a dedicated connection to its own server. Servers do not see each other.
The term MCP server says nothing about where the code runs; it can be local or remote. In practice, local servers over stdio typically serve a single client, while remote servers over Streamable HTTP serve many. The protocol splits into two layers: a data layer (JSON-RPC 2.0 messaging, lifecycle, primitives, notifications) and a transport layer (connection establishment, message framing, authorization). MCP is a stateful protocol. A session opens with initialize, where capabilities are negotiated, and client and server must agree on a single protocol version.
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {
"roots": { "listChanged": true },
"sampling": {}
},
"clientInfo": { "name": "example-host", "version": "1.0.0" }
}
} The spec defines two standard transports: stdio and Streamable HTTP. Clients should support stdio whenever possible, and custom transports are permitted as long as they preserve the JSON-RPC message format and lifecycle requirements. Streamable HTTP exposes a single MCP endpoint path supporting both POST and GET; the server may optionally stream responses over SSE. The older HTTP+SSE transport from revision 2024-11-05 has been replaced by Streamable HTTP and is deprecated. Over HTTP, clients must send an MCP-Protocol-Version header on all requests following initialize, and the value sent should be the version negotiated during initialize; a server that receives no header assumes 2025-03-26. A server may issue an MCP-Session-Id at initialization and expect it on subsequent requests.
The specification states outright that MCP takes some inspiration from the Language Server Protocol. The analogy holds up: LSP standardized the seam between an editor and a language; MCP standardizes the seam between an AI application and an external system.
What a server actually exposes
Servers expose capability through three core primitives. What separates them is not what they do, but who controls them:
- Tools — functions the model can invoke to take action: write to a database, call an external API, modify files. Controlled by the model. Methods: tools/list, tools/call.
- Resources — passive, read-only data sources that supply context: file contents, database schemas, API responses. Controlled by the application. Methods: resources/list, resources/templates/list, resources/read, resources/subscribe.
- Prompts — reusable, parameterized interaction templates. Controlled by the user; the spec expects them to be explicitly invoked. Methods: prompts/list, prompts/get.
Tool inputs are declared with JSON Schema. That lets the server author trust the schema rather than the model: an incoming call is validated against the schema before it reaches any business logic.
{
"name": "get_order_status",
"title": "Get order status",
"description": "Returns the current status of a given order number.",
"inputSchema": {
"type": "object",
"properties": {
"orderNumber": { "type": "string", "pattern": "^[A-Z]{2}-[0-9]{6}$" },
"verbose": { "type": "boolean", "default": false }
},
"required": ["orderNumber"]
}
} On the resource side, each resource carries a unique URI and declares a MIME type. Beyond fixed URIs, servers can publish parameterized Resource Templates — a template taking a city and a date, for instance. The flow is not one-directional: clients expose primitives to servers too. Sampling lets a server request a completion from the host’s model (sampling/createMessage). Elicitation lets a server ask the user for additional input or confirmation (elicitation/create). Roots lets a server query the filesystem boundary it has been granted. Logging rounds it out. A Tasks primitive for long-running operations is marked experimental in the current revision, so it should not be treated as a fixed assumption in a rollout plan. Servers whose capabilities change can emit notifications such as notifications/tools/list_changed — but only if they advertised listChanged during initialize.
Where authorization actually happens
This is the part readers most often get wrong. In MCP, authorization is defined at the transport level and it is optional. HTTP-based transports should conform to the authorization specification; STDIO transports should not follow it and should retrieve credentials from the environment instead. Looking for an OAuth flow inside a local stdio server means looking at the wrong layer.
Over HTTP the roles are unambiguous. A protected MCP server acts as an OAuth 2.1 resource server. An MCP client acts as an OAuth 2.1 client. The authorization server is a separate party — it may be hosted alongside the resource server or run entirely independently. That separation is what grounds the claim that an MCP server is an authorization boundary: the server does not mint tokens, it validates them and constrains access accordingly. The standards this section lists compliance with are the OAuth 2.1 draft, RFC 8414, RFC 7591, RFC 9728 and the OAuth Client ID Metadata Documents draft. Separately, the same document requires RFC 8707 for the resource parameter.
The requirements that translate directly into deployment decisions:
- MCP servers must implement RFC 9728 (Protected Resource Metadata), and clients must use it for authorization server discovery.
- Clients must implement PKCE and use the S256 challenge method when technically capable; if PKCE support cannot be verified from the code_challenge_methods_supported field in the authorization server metadata, the client must refuse to proceed.
- Servers must validate that access tokens were issued specifically for them as the intended audience, and must reject tokens that do not name them.
- When calling an upstream API, the MCP server acts as an OAuth client in its own right and must not pass through the token it received from the MCP client. Token passthrough is an explicitly forbidden pattern.
- Tokens must not appear in the URI query string; every HTTP request carries an Authorization: Bearer header, even within the same logical session.
- Session identifiers are not an authentication mechanism: servers must not use sessions for authentication.
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope",
scope="orders:read orders:write",
resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource",
error_description="Write permission required" The error codes are specified as well: 401 for authorization required or an invalid token, 403 for insufficient scope, 400 for a malformed request. On 403 the server advertises the scopes needed in the WWW-Authenticate header, and the client can run a step-up authorization flow. Scope minimization is officially recommended, and omnibus scope names such as *, all or full-access are listed among common implementation mistakes.
What MCP is not
MCP is not a model. It is an open standard for connecting AI applications to external systems. There are no weights in it, no inference engine, no opinion about model behavior. Which model you run is outside the protocol’s concern.
MCP is not an agent framework. The official scope note is explicit: MCP focuses solely on the protocol for context exchange and does not dictate how AI applications use LLMs or manage the provided context. Planning, loop control, memory, retry policy — all of that lives in your application, not in the protocol.
MCP is not a RAG system. The resources documentation says it directly: applications access the information and decide how to use it, whether that means selecting relevant portions, searching with embeddings, or passing everything to the model. Indexing, chunking and vector search are not defined anywhere in the protocol. They are application decisions.
MCP does not replace an API gateway. An MCP server is not a transparent pass-through in front of upstream APIs. The access token used upstream is a separate token issued by the upstream authorization server, and the server must not forward the one it received. The server carries its own identity and its own authorization boundary. Rate limiting, quotas, protocol translation and edge routing remain gateway concerns.
The official analogy is a good one: think of MCP like a USB-C port for AI applications. The port does not define what is on the other end of the cable, or what the connected device does with the connection.
Where the server belongs in an on-premises deployment
The specification’s security section lists four principles: user consent and control, data privacy, tool safety, and LLM sampling controls. The same section adds a caveat: MCP cannot enforce these principles at the protocol level, so implementors are expected to. That single caveat explains why architectural decisions carry so much weight here. Most of the control lives not in the protocol but in who runs the server and where it runs.
The security requirements in the spec make on-premises hosting a natural fit. Servers running locally should bind only to 127.0.0.1 rather than all interfaces. Servers using Streamable HTTP must validate the Origin header and return 403 on an invalid value, which is the defense against DNS rebinding. Authentication is recommended for all connections. A local server is a process executing code on the host machine: the spec recommends that the client run that process in a sandbox with minimal default privileges, and that a locally running server restrict access to stdio or a constrained IPC channel such as a unix domain socket. MCP clients fetching OAuth discovery URLs should block requests to private and reserved IP ranges, and server-side MCP client deployments should consider an egress proxy — the part covering server-side request forgery, where a server directs a client at internal network addresses. Proxy servers using static client IDs must obtain user consent per dynamically registered client — the rule that closes the confused deputy case. Token audience isolation already says the same thing in a different vocabulary: the server is the boundary.
Put together, the picture is this. The MCP server is where enterprise data and enterprise actions pass through. Even when the model runs elsewhere, the server determines which tools exist, which resources are readable, and which identity carries which call upstream. If that server sits inside your network and under your control, all of those decisions stay somewhere you can audit. The spec also notes that tool descriptions and annotations should be considered untrusted unless they come from a trusted server — and whoever defines trusted is the one drawing the boundary.
The shortest way to position MCP: most of the code you used to write when connecting a model to an enterprise system was never about the model. It was about discovery, schemas, identity, authorization, error shapes and lifecycle. MCP standardizes that part and stays out of the rest. Which is why the design questions for an MCP server are not protocol questions at all: which actions become tools, which data becomes readable as resources, and which identity reaches which upstream system with which scope. The protocol clarifies where those questions get asked. Answering them is still architecture work.
Sources
- Model Context Protocol — specification, 2025-11-25 revision
- MCP specification — Authorization section (OAuth 2.1 roles, RFC 9728, error codes)
- MCP specification — Versioning and feature lifecycle
- MCP Blog — The 2026-07-28 MCP Specification Release Candidate
- MCP Blog — MCP joins the Agentic AI Foundation (9 December 2025)
- Anthropic — Introducing the Model Context Protocol (25 November 2024)