The Model Context Protocol (MCP) is an open standard from Anthropic that lets AI applications connect to external tools and data through one uniform interface. Instead of writing custom glue for every model–tool pairing, you build an MCP server once and any MCP-capable client can use it. Under the hood, every MCP message is JSON — specifically JSON-RPC 2.0. Learn that shape and MCP stops being an acronym and becomes something you can read off the wire.
This guide explains the JSON behind MCP, with a copy-ready example you can open and inspect.
> MCP and the related tool-use shapes live in the AI & LLM category of the JSON Examples Library.
The problem MCP solves
Without a standard, connecting *M* AI apps to *N* tools means writing *M × N* bespoke integrations. MCP turns that into *M + N*: each app speaks MCP, each tool exposes MCP, and they interoperate. It's the same idea that USB or the Language Server Protocol brought to their domains — a common protocol so things just plug together.
JSON-RPC 2.0 in 60 seconds
MCP is built on JSON-RPC 2.0, so every message is a small JSON object. There are three kinds:
| Kind | Has id? | Has method? | Has result/error? |
|---|---|---|---|
| Request | yes | yes | no |
| Response | yes (matching) | no | yes (one of them) |
| Notification | no | yes | no |
Every message carries "jsonrpc": "2.0". A request names a method and passes params; the response echoes the request id and returns either a result (success) or an error.
// Request
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {} }
// Response
{ "jsonrpc": "2.0", "id": 2, "result": { "tools": [] } }The core MCP methods
An MCP server typically implements a handful of methods. The important ones:
initialize— the handshake; client and server exchange capabilities and protocol versions.tools/list— discover the tools the server exposes.tools/call— invoke a tool with arguments.resources/listandresources/read— expose readable data (files, records) to the model.prompts/listandprompts/get— share reusable prompt templates.
See all of these shapes in the MCP Message example, which shows tools/list, tools/call, and the error response side by side.
Discovering and calling tools
The two methods you'll use most are tools/list and tools/call. Listing returns each tool's name, description, and an inputSchema (a JSON Schema for its arguments):
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "get_weather",
"description": "Get the current weather for a city.",
"inputSchema": {
"type": "object",
"properties": { "location": { "type": "string" } },
"required": ["location"]
}
}
]
}
}Calling passes the tool name and arguments:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": { "name": "get_weather", "arguments": { "location": "Ahmedabad, IN" } }
}If you've done LLM function calling, this will feel familiar — the model still decides *which* tool and *what* arguments. MCP standardizes the transport so the same server works across clients. Compare the shapes with the LLM Tool / Function Call example and the Agent Tool Registry.
Errors
When a call fails, the server returns a JSON-RPC error object instead of a result:
{ "jsonrpc": "2.0", "id": 3, "error": { "code": -32602, "message": "Invalid params: 'location' is required" } }MCP reuses the standard JSON-RPC codes: -32700 parse error, -32600 invalid request, -32601 method not found, -32602 invalid params, and -32603 internal error. Servers may define additional codes outside that reserved range.
Building & debugging MCP servers with JSON tools
- Inspect the traffic. Pipe a captured
tools/listortools/callpayload into the JSON Tree Explorer to read it cleanly. - Validate your inputSchema. A malformed tool schema is the most common MCP bug — check it in the JSON Schema Validator.
- Type your handlers. Paste a request/response pair into JSON to TypeScript so your server code matches the protocol exactly.