AI / Concepts

The Model Context Protocol, explained for working developers

MCP is the reason your coding agent can read a Sentry issue, query your database, or open a Figma file without you pasting anything. It is a small, boring, open protocol - and knowing the four concepts underneath it is the difference between installing servers by cargo cult and building one that is actually useful.

About 9 min read. Written against protocol version 2026-07-28, current as of August 2026.

What MCP actually is

The Model Context Protocol is an open standard for connecting AI applications to external systems. Anthropic released it in late 2024, and it is now supported across Claude, ChatGPT, Visual Studio Code, Cursor, and most of the agent ecosystem. The official analogy is a USB-C port for AI applications: one connector shape, so a tool built once works in every client that speaks it.

The problem it solves is combinatorial. Before MCP, every AI client needed a bespoke integration for every tool - N clients times M tools. After it, a tool ships one server and every client can use it. That is the whole value proposition, and it explains why adoption was fast: nobody had to be convinced the protocol was elegant, only that they were tired of writing the same GitHub integration for the fifth time.

What MCP is not: it is not an agent framework, not a model API, and not a way to run LLMs. It says nothing about how an AI application uses the context it receives. It defines the exchange and stops there, which is why it has survived three generations of agent architecture without needing to be rewritten.

Hosts, clients, and servers

Three participants, and the naming trips everyone up once. The word "server" here has nothing to do with where the code runs.

Host

The AI application you interact with: Claude Code, Cursor, VS Code, ChatGPT. It coordinates one or more clients and decides what to do with the context they return.

Client

A component inside the host that maintains one dedicated connection to one server. Connect three servers and the host instantiates three clients. You never configure a client directly.

Server

A program that provides context. It might be a local process launched on your machine or a service running in somebody else's cloud - "server" describes the role, not the location.

Underneath, the protocol splits into two layers. The data layer is a JSON-RPC 2.0 exchange defining discovery, capabilities, and the primitives below. The transport layer is how those messages move. Same messages, different pipe - which is why a server can switch from local to remote without changing a line of its tool logic.

One design decision worth knowing: MCP is a stateless protocol. Every request carries the protocol version and the relevant capabilities in a _meta field, so a server can process each request on its own without remembering the connection. Clients can call server/discover to fetch a server's identity, supported versions, and capabilities in one round trip, but it is optional - any request can be sent cold and the server will reject it with a version error if it needs to.

Two transports, and which one to use

This is the first real decision when you add or build a server, and it is mostly decided for you by where the data lives.

Transport How it works Use it when
stdio The host launches the server as a child process and talks to it over standard input and output. No network, no ports, no auth layer - the OS process boundary is the boundary. The server needs access to your local machine: filesystem, a local database, a CLI tool, a git repo. Typically serves exactly one client.
Streamable HTTP HTTP POST for client-to-server messages, with optional Server-Sent Events for streaming back. Supports bearer tokens, API keys, custom headers, and OAuth. The server is a hosted service - Sentry, Notion, Stripe, your own internal API. Serves many clients at once.

You will still see a third name in older configs. The standalone SSE transport is deprecated; Streamable HTTP replaced it, and some services keep an SSE endpoint alive only for backwards compatibility. If you are adding a server today and it offers both, take HTTP.

A naming trap worth knowing: the specification calls the HTTP transport streamable-http, and client configuration files often want "type": "http". Claude Code accepts both spellings for exactly this reason - so a config copied out of a vendor's documentation works unchanged.

Tools, resources, and prompts

Three server primitives. Most people only ever use the first one, which is a shame, because the other two solve real problems.

Tools

Model-controlled actions

Executable functions the model can call: run a query, create an issue, send a message. Each has a name, a human-readable title, a description, and a JSON Schema for its input. Clients find them with tools/list and run them with tools/call.

The model decides when to invoke a tool, which makes the description the most important string in your server. A vague description means an unused tool or a wrongly used one.

Resources

Application-controlled data

Read-only context identified by URI: a file's contents, a database schema, an API response. Discovered with resources/list and fetched with resources/read.

In Claude Code you reference one directly in a prompt with @server:protocol://path, and they appear in the same @ autocomplete as your files. Use resources for things the model should be able to look at without deciding to take an action.

Prompts

User-controlled templates

Reusable interaction templates the server ships with: a structured incident triage prompt, a code review checklist, a set of few-shot examples for its own tools.

Hosts surface them as commands - Claude Code exposes them as /mcp__servername__promptname. The most underused primitive, and the best way to ship expertise alongside capability.

The client can expose a primitive back to the server too. Elicitation lets a server ask the user for more information mid-call - a confirmation before a destructive action, a missing parameter, a choice between two matches. The server sends elicitation/create and the host renders the question.

Two client primitives were deprecated in protocol version 2026-07-28 and you should not build on them. Sampling, which let a server borrow the host's model, is retired in favour of integrating with a model provider directly. Logging is retired in favour of writing to stderr on stdio or using OpenTelemetry. Plenty of blog posts still describe both as current; they are not.

Servers developers actually install

There are thousands of MCP servers now and most of them are demos. These are the categories that survive contact with real work, along with what they let an agent do that it could not before.

Category What it unlocks Typical transport
Error tracking "Fix the top error from the last deploy." The agent reads the stack trace, the release, and the affected users, then goes to the code. Remote HTTP with OAuth
Issue trackers "Implement ENG-4521 and open a PR." The ticket, its comments, and its acceptance criteria become the spec without a copy-paste. Remote HTTP with OAuth
Databases Real schema instead of a guess. The agent stops inventing column names, and can check a query plan before shipping the query. Local stdio against a read-only role
Design tools Build a component from the actual frame: real spacing tokens, real colours, real component names rather than an approximation of a screenshot. Remote HTTP or a local bridge
Documentation Current API docs for a library the model's training data predates. The highest-value category and the least glamorous. Remote HTTP
Filesystem and shell Scoped access outside the working directory. Mostly redundant now that coding agents ship their own file tools. Local stdio

Gotcha: every connected server's tool list is loaded into context. Five chatty servers can cost thousands of tokens before you type a word, on every single turn. Connect what this project needs, not what looked interesting last month, and use /context in Claude Code to see what you are paying for.

When building your own is worth it

Build one when

  • The system is internal. Your deploy tool, your feature-flag service, your customer admin API. Nobody else will ever write this server and it is the highest-value one you can own.
  • The workflow is multi-step and repeated. If the same five API calls in the same order happen weekly, one tool that does the whole thing beats five tools the model has to sequence correctly.
  • The data needs shaping. A raw API returns fields the model does not need and omits the join it does. A server is where you fix that once instead of in every prompt.
  • You need an audit trail. A server is a real process you control, so you can log every call, rate-limit it, and revoke it.

Do not build one when

  • A CLI already exists. If the agent can run gh or psql in a shell, that is already an integration. A server that wraps a CLI adds a process and removes flexibility.
  • It is a one-off script. A skill or a slash command is lighter, is version-controlled with the repo, and does not need a protocol.
  • An official one exists. Vendor-maintained servers track their own API changes. Yours will not.
  • You only need to read files. Every coding agent already has file tools that are faster and better integrated than an MCP round trip.

If you do build one, the SDKs cover the protocol so you write handlers and nothing else. Start with the smallest useful surface - two or three well-described tools - because tool descriptions are prompt engineering and every extra tool makes selection harder for the model, not easier. The MCP Inspector lets you exercise a server without wiring it into a client first.

Reference material lives at modelcontextprotocol.io, and the specification is versioned by date, so pin the version you built against.

Security: an MCP server is code you are running

This is the part the quickstarts skip. Adding a server grants an autonomous agent the ability to call somebody else's code with your credentials, and the failure modes are not theoretical.

A stdio server runs as you

Installing one with npx is running an arbitrary npm package with your user's permissions and your environment variables. It is exactly as safe as any other dependency, which is to say: read who publishes it, pin the version, and prefer official servers over the community wrapper with forty stars.

Tool descriptions are untrusted input

A server supplies the text that tells the model when to use its tools, and that text lands in the model's context. A malicious or compromised server can attempt prompt injection through it - and so can the data a tool returns. Treat anything crossing that boundary as hostile, especially from a server that also reads a public source.

Scope credentials down

Give a database server a read-only role on a replica, not your application user. Give an issue-tracker token read and comment, not admin. The agent will eventually try something you did not anticipate, and the credential is the only thing that stops it.

Project-scoped servers need approval

A committed .mcp.json means cloning a repo can propose new servers to your agent. Claude Code prompts before using project-scoped servers for exactly this reason. Read the file on a fresh clone the way you would read a postinstall script.

Gotcha: the dangerous combination is an agent with network-writing tools, a server reading untrusted content, and permission prompts turned off. Any two are manageable. All three is how data leaves your machine without anyone deciding it should.

Where to go next

For the commands that add, authenticate, and scope servers, see the MCP section of the Claude Code cheatsheet. Cursor supports MCP too - the Cursor cheatsheet covers where it fits alongside rules and @ mentions.

If you are building AI features into a product rather than wiring up your own tooling, the layer you want is AI APIs and SDKs, and the AI app stack guide assembles it end to end. The AI-assisted development workflow guide covers the permission and guardrail discipline that makes any of this safe to leave running.