Home / Blog / MCP

What is an MCP server? A clear explainer for developers

An MCP server is a program that exposes tools, data, and prompt templates an AI model can use, over a shared standard called the Model Context Protocol. That standard is the whole story: it means any MCP-aware app, Claude Desktop, Claude Code, Cursor, ChatGPT, can use any MCP server without custom integration code. I run a handful of these servers in production, so this explainer is written from how they actually behave, not just the spec.

What is an MCP server?

An MCP server is a small program that exposes a set of capabilities, mainly tools an AI model can call, to any application that speaks the Model Context Protocol. The model decides to call a tool, the server runs the logic and returns a result the model can read. In the protocol's own words, an MCP server is "a program that provides context to MCP clients."

That's the entire idea. A server might wrap a database, a Shopify store, a filesystem, a search API, or your company's internal tooling. Whatever it wraps, it presents that capability through one standard interface, so the model on the other end doesn't need to know anything about the underlying system. It just sees a list of tools it can call and the results it gets back.

People tend to imagine something bigger than it is. An MCP server is not an agent, a framework, or a hosted service. It's a process that advertises what it can do and handles the calls. The smallest useful one is about twenty lines of code. The larger ones are larger because their logic is larger, not because the protocol is.

What is MCP (the Model Context Protocol)?

MCP, the Model Context Protocol, is an open standard for connecting AI applications to external systems. Anthropic introduced and open-sourced it in November 2024. The official docs describe it as "a USB-C port for AI applications": one standardized connector instead of a different cable for every device.

The protocol defines the handshake. When an app connects to a server, the two exchange what each supports (this is called capability negotiation), and from then on they speak a common message format built on JSON-RPC 2.0. Because that format is fixed, the app doesn't care how the server is written or what it wraps, and the server doesn't care which app connected. They agreed on the wire format in advance, so they interoperate by default.

MCP is deliberately narrow about what it covers. As the spec puts it, "MCP focuses solely on the protocol for context exchange, it does not dictate how AI applications use LLMs or manage the provided context." It standardizes the plumbing between a model and a capability, and nothing above that. That narrowness is why it spread: a small, well-defined standard is easy to adopt.

Why MCP exists: the M×N problem

MCP exists to kill the M×N integration problem. Without a standard, connecting M AI applications to N tools means writing M×N separate integrations, every app reimplementing every connection. MCP turns that into M+N: each app speaks MCP once, each tool exposes MCP once, and they all work together.

Before MCP, if you wanted Claude, Cursor, and your own agent to each read from Postgres, Slack, and a Shopify store, you wrote nine integrations, and you rewrote them whenever an API changed. Every new tool multiplied the work across every app. That's the combinatorial trap any integration ecosystem hits, and it's exactly the problem USB solved for hardware: one port, many devices, instead of a custom plug per peripheral.

MCP collapses it. Build a server once, and every MCP client can use it. Adopt MCP in your app once, and it can reach every MCP server in existence. The practical payoff, from running these in production, is real interoperability: a server I wrote to be used by our own platform also works, unchanged, in Claude Desktop and Cursor. I didn't write a line of client-specific code for either. That's the part that's easy to undersell on paper and obvious the first time you see it happen.

The host, client, server model

MCP uses a client-server architecture with three roles: the host is the AI application, the client is the connection-manager inside it, and the server is the program that provides capabilities. The host creates one client per server, and each client keeps a dedicated connection to its server.

The host, client, server model HostClaude, an agent Client Aone per server Client Bone per server MCP Server Aa tool MCP Server Ba database stdio / HTTP stdio / HTTP scalably.io
The host runs one client per server. Each MCP server exposes one capability.

The three roles, in the protocol's own definitions:

RoleWhat it isExample
Host The AI application that coordinates and manages one or more MCP clients. Claude Desktop, Claude Code, Cursor, VS Code
Client A component inside the host that maintains a connection to one server and obtains context from it for the host to use. An internal connection object, one per server
Server A program that provides context (tools, resources, prompts) to MCP clients. A filesystem server, a Shopify connector, a Sentry server

The one-client-per-server rule is the part people miss. When VS Code connects to a filesystem server and a Sentry server, it spins up two clients, one dedicated to each, both living inside the single host. The server is the same program whether it runs on your laptop or on a vendor's platform. A filesystem server launched locally by Claude Desktop and Sentry's hosted server are both "MCP servers"; the only difference is where the process runs and how it's reached.

Tools, resources, and prompts

An MCP server can expose three kinds of capability, called primitives: tools (functions the model can call to do something), resources (data the model can read for context), and prompts (reusable templates that structure an interaction). Tools are the one most servers lead with.

These are the three things a server can offer a client, and they map cleanly to "do," "read," and "template":

PrimitiveWhat it doesControlled byExample
Tools Executable functions the model invokes to perform an action. Model-driven (the model chooses to call) Run a query, send a request, write a file
Resources Data sources that provide context the model can read. Application-driven (the host decides what to load) A file's contents, a DB schema, an API response
Prompts Reusable templates that structure an interaction with the model. User-driven (often surfaced as commands) A system prompt, a set of few-shot examples

The docs give a clean example: a server that provides context about a database "can expose tools for querying the database, a resource that contains the schema of the database, and a prompt that includes few-shot examples for interacting with the tools." Same server, all three primitives, each doing its own job.

In practice, tools carry almost all the weight. Every server I run leads with tools, because a tool is the thing that lets the model take an action and get a fresh result. If you're coming from raw function calling, an MCP tool is the same idea behind a standard interface, and the difference between MCP and function calling is mostly about reuse and where the tool lives. Resources and prompts are useful, but a lot of real servers ship tools and little else, and that's fine. Each primitive also has discovery methods (tools/list, resources/list, prompts/list) so a client can ask a server what it offers before using anything.

How a server talks: stdio vs HTTP

An MCP server talks to its client over one of two transports. Stdio uses standard input/output for a local process on the same machine, with no network involved. Streamable HTTP uses HTTP POST (with optional Server-Sent Events for streaming) for a remote server reached over the network.

The transport is the channel, separate from the messages themselves. Because MCP uses the same JSON-RPC message format regardless of transport, the same server logic runs over either one; you choose based on where the server lives.

TransportRuns whereHow it connectsAuth
Stdio Locally, launched by the host Standard input/output streams, no network None needed (same machine)
Streamable HTTP Remotely, on a server or platform HTTP POST + optional Server-Sent Events Bearer tokens, API keys, OAuth

A local stdio server is the easy on-ramp: Claude Desktop launches the process, pipes messages in and out, and you never think about ports or auth. A remote HTTP server is what you reach for when many users need the same connector, or the server has to live somewhere central. The MCP docs recommend OAuth for obtaining auth tokens on remote servers, which matters the moment a server is reachable over a network rather than spoken to on a local pipe.

Who uses MCP servers

MCP servers are used by AI applications that act as hosts: Claude (Desktop and Code), ChatGPT, and development tools like Visual Studio Code and Cursor, plus any custom agent built to speak the protocol. MCP is an open standard with support across a wide range of clients and servers, so a single server can serve all of them.

That last point is the reason to care. The protocol's promise, in the docs' own framing, is "build once and integrate everywhere." When I write a server, I'm not writing it for one app. The read-only Shopify connector we run is used by our own platform's agents and works just as well in Claude Desktop or Cursor, with no changes. That's not a tutorial claim; it's the day-to-day reality of building against a real standard instead of a vendor's private plugin format.

If you want to go from using servers to writing one, the path is short. You can build an MCP server in Python in about twenty lines, decorate a function as a tool, and point any MCP client at it.

A concrete example

Here's MCP end to end: the host connects to a server, the client asks the server what tools it has, the model picks one and calls it with arguments, and the server returns a result the model reads back. The exchange below is the actual message shape, JSON-RPC over the wire.

First the client discovers what's available with a tools/list request. The server answers with each tool's name, a human-readable title, a description, and an input schema:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list"
}

// server responds
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [{
      "name": "weather_current",
      "title": "Weather Information",
      "description": "Get current weather for any location",
      "inputSchema": { "type": "object" }
    }]
  }
}

Now the model has a tool it can use. When it decides to use it, the client sends a tools/call with the tool name and arguments, and the server returns the result:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "weather_current",
    "arguments": { "location": "San Francisco" }
  }
}

// server responds
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [{
      "type": "text",
      "text": "San Francisco: 68F, partly cloudy."
    }]
  }
}

That's the loop. List, call, read the result, and the model folds that result into its answer. You almost never write this JSON by hand; the SDKs generate it from a decorated function and your type hints. But it's worth seeing once, because it makes clear how little there is to the protocol. The model doesn't know what's behind weather_current. It sees a tool, calls it, gets text back. Everything specific to weather, or Shopify, or your database lives inside the server.

The mental model: the server is an adapter. On one side, a standard interface the model understands. On the other, whatever real system you're wrapping. MCP standardizes the side facing the model so every client can plug in the same way.

Common questions

Is an MCP server the same as an AI agent?

No. An MCP server exposes capabilities; an agent decides what to do with them. The server is the tool, the agent is the thing wielding it.

A server has no plan and no autonomy. It waits for calls and answers them. An agent is the loop that reads a goal, decides which tool to call, calls it through an MCP client, reads the result, and decides what to do next. Many agents use MCP servers; no MCP server is an agent.

Do I need to know JSON-RPC to use MCP?

No. The SDKs handle the protocol entirely. You write ordinary functions and the SDK turns them into MCP tools and manages the JSON-RPC messages for you.

The example above shows the wire format so you understand what's happening, but in practice you decorate a function, declare your inputs with type hints, and the SDK does the rest. The protocol is the part you don't have to think about.

Is MCP only for Claude?

No. MCP is an open standard supported by many clients, including ChatGPT, Cursor, and Visual Studio Code, not just Claude. Anthropic created it, but it's open-source and vendor-neutral.

That's the whole reason it's worth building on. A server written against MCP isn't locked to one company's app. It works anywhere the protocol is supported, which is now most serious AI dev tools.

If there's one thing to take away: an MCP server is an adapter between a model and a real capability, and MCP is the standard that lets any model use any adapter. The protocol is small on purpose. The value is what that small standard makes possible, real interoperability across every client that speaks it. When you're ready to write one, building an MCP server is a short job, and the standard does the heavy lifting.

P

Pavle Lazic is the founder of Scalably, where he builds and runs multi-tenant Claude agent platforms in production for real businesses. He writes about the Claude Agent SDK, MCP servers, and what it actually takes to put AI agents to work. See the platform.