MCP, explained

What Is an MCP Server?

An MCP server is a program that exposes tools, data, or prompt templates to an AI agent through the Model Context Protocol — a standard interface, so the agent doesn't need a custom integration for every tool it uses. This page explains the protocol and works through one concrete server: a phone call.

Connect your agentRead the docs

The problem it solves

Before MCP, connecting an agent framework to an external system meant writing that framework's specific integration for that system — a Slack tool for one framework, a different Slack tool for another, repeated per tool and per framework. Every new combination of agent and capability was its own integration.

MCP replaces that grid with one interface on each side. A server exposes its capabilities once, in a standard shape. Any MCP-speaking client — Claude, an agent framework, a custom harness — can call it without knowing anything about how it's implemented underneath.

The pieces

An MCP server talks JSON-RPC 2.0 over a transport — stdio for a local process, or streamable HTTP for a hosted one reachable over the network. A client connects, calls initialize to handshake, then asks what the server can do.

A server can expose up to three kinds of things:

A server that only does calling can legitimately answer resources/list and prompts/list with empty arrays and still be a complete, compliant MCP server — it just commits everything to tools.

A worked example: phone calls

Take a capability an agent doesn't have by default: placing a phone call. As an MCP tool, it's a name, a description, and a schema for its arguments — make_call from CallMCP:

{
  "name": "make_call",
  "description": "Initiate a real outbound phone call via an AI agent",
  "inputSchema": {
    "type": "object",
    "properties": {
      "agent_id": { "type": "string" },
      "to": { "type": "string", "description": "E.164, e.g. +19085551234" },
      "context": { "type": "string" }
    },
    "required": ["agent_id", "to"]
  }
}

That's the whole contract. Any client that can read JSON Schema knows how to call this tool without anyone writing framework-specific glue code. The full tools/call request wraps it in a JSON-RPC envelope — a method, a tool name, arguments matching the schema, and an id the response echoes back:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "make_call",
    "arguments": { "agent_id": "agt_9f2a1c", "to": "+15551234567" }
  }
}

The response comes back with two things: a text block a language model can read directly, and a structuredContent object with the same data as typed fields, for code that wants to parse it instead of read it.

How a client talks to a server

The handshake before any of this happens is the same for every MCP server, phone calls or otherwise:

1. initialize        → protocol version + server info, no auth required
2. tools/list         → the full tool catalog, public metadata
3. tools/call         → execute one tool, requires auth + the tool's required scope

initialize and tools/list are deliberately unauthenticated — a client (or a marketplace crawling for MCP servers) needs to see what a server offers before deciding whether to connect. tools/call is where auth and per-tool scopes (read vs. write, which resource) actually get enforced — the same handshake CallMCP's own MCP server runs for the make_call tool above.

Connect your agentRead the docsWalk through a full tool call
Connect