agentsdir.

What Is an MCP Server, and How Does It Work?

Updated September 5, 2026

An MCP server exposes tools, resources and prompts to an AI app over JSON-RPC 2.0. Here is what that means in practice, and why an MCP badge in a README proves nothing.

agentsdir.ai9 min read
An MCP server answering a tools list request and a tool call from one agent client over two transports

An MCP server is a program that exposes tools, resources and prompts to an AI application over the Model Context Protocol, using JSON-RPC 2.0 messages. It is not a web server in the usual sense, and it often does not run on a server at all: most of them run as a local subprocess that your editor or agent launches on startup. The protocol fixes the wire format. The server decides what sits behind it.

What an MCP server exposes

An MCP server is a process that speaks the Model Context Protocol over a transport, declares a set of capabilities, and answers requests for them. The specification names three things a server can offer, and they are not interchangeable.

PrimitiveWho controls itWhat it isExample
PromptsUser-controlledTemplates invoked by user choiceSlash commands, menu options
ResourcesApplication-controlledContextual data the client attachesFile contents, git history
ToolsModel-controlledFunctions the model calls to actAPI POST requests, file writing

That control column is the part most write-ups skip, and the one that matters when debugging. A resource that never reaches the model is a client decision, not a server bug. So is a tool that fires without a confirmation step.

Most servers ship tools and nothing else. Resources and prompts are optional, and a server with only one of the three still conforms.

How a tool call travels from the model to the server and back

Here is the full round trip, in the order it happens.

  1. The client asks for the tool list. It sends tools/list. A server that declares the tools capability must respond with the set of tools currently available to that caller.
  2. The server answers with schemas, not documentation. Each tool carries a name, a description and an inputSchema in JSON Schema, plus an optional outputSchema and title.
  3. The host puts those definitions into the model's context, where they read as callable functions.
  4. The model picks one and produces arguments that fit the input schema.
  5. The client checks with a human. The tools specification says there should always be a human in the loop able to deny tool invocations, and that clients must treat tool annotations as untrusted unless the server is trusted.
  6. The client sends tools/call with the name and arguments. The server does the work and returns content blocks, optionally with a structuredContent value matching the output schema.
  7. The result goes back to the model, which decides what to do next.

A tool definition on the wire looks like this:

{
  "name": "get_weather",
  "title": "Weather Information Provider",
  "description": "Get current weather information for a location",
  "inputSchema": {
    "type": "object",
    "properties": {
      "location": { "type": "string", "description": "City name or zip code" }
    },
    "required": ["location"]
  }
}

Errors split into two paths. A malformed request or an unknown tool comes back as a standard JSON-RPC error. A failure inside the tool comes back as a normal result with isError set to true, and the spec says clients should hand those to the model so it can correct itself and retry.

Host, client and server are three different words

The spec is precise here and almost every write-up is not. Hosts are the LLM applications that start connections. Clients are the connectors inside the host application. Servers are the services that provide context and capabilities. One host can hold many clients, one per connected server.

The split also decides how much a system does without asking, which is the axis behind agent autonomy levels. A server exposing a destructive tool and a client that auto-approves every call are two separate design choices, and only one of them is the server's fault.

Which transports does an MCP server use?

Two are standard.

stdio. The client launches the server as a subprocess. The server reads JSON-RPC messages from stdin and writes them to stdout, one per line, with no embedded newlines. It may write anything to stderr for logging, and the spec tells clients not to assume stderr output means something failed. That one rule explains a lot of noisy terminal output.

Streamable HTTP. Each message is an HTTP POST to a single MCP endpoint. The reply arrives either as a JSON object or as a request-scoped SSE stream.

Custom transports are allowed, as long as they keep the JSON-RPC message format and the per-request metadata model.

The practical difference is trust. A stdio server runs on your machine, under your user, with your network position and whatever credentials that implies. A remote server does not. Picking a transport is a security decision before it is a plumbing decision.

The client's approval prompt is not the thing that limits a stdio server, either. That distinction is worked through in why an agent's permission mode is not a security boundary.

"MCP support" is three separate claims, and a badge is none of them

This is the part the category gets wrong. "MCP support" can mean any of three things that have almost nothing to do with each other:

  1. It is an MCP client. It connects to servers other people wrote and calls their tools. The evidence is a documented list of transports and a config format for adding a server.
  2. It is an MCP server. It exposes its own capabilities to any MCP client. The evidence is a published binary or endpoint whose tool list you can enumerate.
  3. It ships an SDK. You can build either side with it. The evidence is the package.

A vendor can be all three, one, or none. Claude Code documents two: it connects out to servers, and it exposes itself as one through claude mcp serve, per its own MCP documentation. LangChain, CrewAI and LlamaIndex document the client role only. Their MCP pages describe adapters that pull tools out of a server and convert them into the framework's own tool objects. None of the three documents exposing itself as a server.

A README badge is evidence of nothing, because the protocol does not hand them out. The check that settles it takes one request: a server that declares the tools capability must answer tools/list with the tools currently available. If nothing answers, there is no server. If the docs never name a transport, there is probably no client either.

Whether you need a server at all is a different question, and the tradeoff against defining functions directly in your model call is covered in MCP versus function calling.

Where the listed tools actually sit

Placed on the three axes this directory uses, with the MCP role each vendor documents:

ToolAutonomyEnvironmentEcosystemDocumented MCP role
Claude CodeFully AutonomousCodeMCP-nativeClient and server
LangChainSupervisedCodeLangChainClient adapter
CrewAISupervisedCodeCustomClient adapter
LlamaIndexCopilotAPILlamaIndexClient adapter
OpenAI Computer UseFully AutonomousComputer-UseOpenAI function-callingNone recorded

Verification dates on those listings run from 2026-05-18 to 2026-06-20, so treat the MCP role as accurate as of then, not as a permanent property.

The protocol version is part of the claim

The current revision is dated 2026-07-28, and MCP versions are YYYY-MM-DD strings marking the last backwards-incompatible change. Two shifts in that revision change how a server is written.

The base protocol moved from stateful connections with a one-time capability negotiation to stateless, self-contained requests with per-request capability negotiation. And the overview for the 2025-06-18 revision lists three client features (sampling, roots and elicitation), where the 2026-07-28 overview lists one, elicitation. The roots page now carries a deprecation notice pointing implementations at tool parameters, resource URIs or server configuration instead.

So "supports MCP" with no revision next to it is a claim with no date on it. Ask which revision, the way you would ask which API version.

Every entry in this directory records the three axes plus what the vendor documents about MCP, with the date somebody last checked. Start with the Claude Code listing if you want a client that also runs as a server.

Frequently asked questions

Is an MCP server the same thing as a REST API? No. A REST API defines its own paths, verbs and payloads, so every integration is bespoke. An MCP server answers a fixed set of JSON-RPC methods that any MCP client already knows how to call, and it publishes a JSON Schema for each tool so a model can fill the arguments without custom glue code.

Does an MCP server need to run on a server? Usually not. On the stdio transport the client launches the server as a local subprocess and talks to it over standard input and output, so nothing is hosted and nothing listens on a port. Remote servers use Streamable HTTP instead, where each message is an HTTP POST to one endpoint.

What is the difference between an MCP client and an MCP server? The client lives inside the AI application and opens the connection. The server answers it and provides the capabilities. One host application can run many clients, one per connected server. A product can implement either side, both sides, or neither, so ask which side a vendor means.

How do I verify that a tool really supports MCP? Call it. A server that declares the tools capability must answer a tools/list request with the tools currently available. For a client, look for documented transports and a config format for adding a server. A badge in a README is not evidence of either side.

Which languages can I write an MCP server in? The protocol publishes official SDKs for TypeScript, Python, C#, Go and Rust at its top tier, with Java, Ruby, Swift, PHP and Kotlin at lower tiers. Every SDK covers both roles, so the same package builds a server that exposes tools and a client that consumes them.