Up front: MCP (Model Context Protocol) is not another name for Function Calling, and it is not a model. It is an open protocol between an AI app (the Host) and external tool processes (MCP Servers). The messages are JSON-RPC 2.0. The model still speaks each vendor’s Tool Calling / Function Calling. The Host translates tools/list into the model’s tools array, then translates tool_calls into tools/call. Those three layers together are how most 2026 agents invoke tools.
This article is dated 7 September 2026. The current spec is 2026-07-28: no protocol session, no initialize handshake, every request carries _meta, and capability discovery uses server/discover. Our August piece Agent JSON data flow still shows the old initialize example; treat this guide as the current reading. For “do I have to change Server code?”, see the MCP 2026 migration guide.
What MCP is
Model Context Protocol is an open standard for how AI applications discover, read, and invoke external context. Anthropic shipped it in November 2024; governance later moved to the Agentic AI Foundation. It specifies how context is exchanged. It does not specify which model you use, how you orchestrate a multi-step agent, or how you write business logic.
Think USB-C: the socket is standard; whether a disk, a display, or a power supply is plugged in is out of scope. MCP standardizes the Host ↔ Server socket. A filesystem, GitHub, an internal orders API, or a JSON validator like this site are all just Servers.
| Phrase | What it actually means | Common misread |
|---|---|---|
| MCP | A JSON-RPC protocol between Host and tool processes | A model, an agent framework, or OpenAI’s Tools API |
| MCP Server | A program that exposes tools / resources / prompts | Must be on the public internet, or must replace your REST API |
| MCP Client | The connection manager inside the Host for one Server | The same thing as the language model |
| MCP Host | An AI app such as Cursor, VS Code, or Claude Desktop | The MCP spec or an SDK |
Two layers: the data layer is JSON-RPC 2.0 (methods, params, error codes, notifications); the transport layer is how those JSON frames move — stdio on the same machine, Streamable HTTP remotely. Swap the transport and the message shape stays. That is why MCP debugging starts by splitting “the envelope is JSON-RPC; the business payload is often JSON too.”
Host, Client, Server
The spec’s triangle is easy to mix up with everyday “client / server” talk:
- Host: the AI app the user opened. It creates Clients, feeds tool schemas to the model, authorizes and validates before execution, and writes results back into the thread.
- Client: one connection object inside the Host. One Server, one Client. VS Code talking to a filesystem and to Sentry is two Clients at runtime.
- Server: the program that serves context. It can share a machine with the Host (stdio) or run elsewhere (Streamable HTTP). “Server” is a role, not a requirement for a public hostname.
The model is not in that triangle. GPT-5.5, Claude 4.8, and Gemini 3.7 see the Host’s translated tools array. They do not see JSON-RPC, and they do not see Mcp-Session-Id (the session header is gone in 2026-07-28). “The model speaks MCP” is marketing. In engineering there is always a Host in the middle.
How to read JSON-RPC 2.0
JSON-RPC is a convention for remote procedure calls using JSON — closer to “call a function” than REST. MCP picked it because method names stay stable (tools/list, tools/call), the request / response / notification split is clean, and the whole envelope is model-friendly JSON.
| Field | Who uses it | Meaning |
|---|---|---|
jsonrpc | Every message | Always "2.0" |
id | Requests and responses | Correlation; notifications have no id |
method | Requests / notifications | e.g. tools/call, server/discover |
params | Requests | Parameter object; from 2026-07-28 often includes _meta |
result / error | Responses | Exactly one; success uses result, failure uses error |
A tools/call on spec 2026-07-28 looks like this. Note: no handshake, no session header. Version and client identity live in _meta, so any Server instance can handle the frame.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "validate_json",
"arguments": {
"payload": {"orderId": "A-1001", "total": 42.5},
"schemaId": "order.v1"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "json-toolbox-host",
"version": "1.0.0"
}
}
}
}
A success response is the same envelope. The business result sits in result.content, often type: "text", and that text may itself be a JSON string — protocol outside, payload inside. When debugging, match id to the request first, then schema-check the inner object.
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"content": [
{
"type": "text",
"text": "{\"valid\":true,\"schemaId\":\"order.v1\"}"
}
]
}
}
Failures use the JSON-RPC error object: code, message, optional data. 2026-07-28 changed “resource not found” from the MCP-specific -32002 to standard -32602 (Invalid Params). Clients that match the old literal will miss it. Notifications have no id and expect no reply — for example a tools-list change.
Tools, Resources, Prompts
A Server may expose three primitives. Agents live on Tools; the other two are easy to skip and often save a round of model guessing.
| Primitive | Discover | Use | For |
|---|---|---|---|
| Tools | tools/list | tools/call | Actions: query a DB, call an API, write a file, validate JSON |
| Resources | resources/list | resources/read | Read context by URI: a schema file, a log slice, config |
| Prompts | prompts/list | prompts/get | Reusable prompt templates, optionally parameterized |
A tool is name, description, and inputSchema. inputSchema is JSON Schema (2020-12 as of 2026-07-28; the root must still be type: "object"; oneOf / $ref / $defs are allowed). Optional outputSchema constrains the return shape. Hosts almost 1:1 copy inputSchema into the model API’s parameters / input_schema.
{
"name": "validate_json",
"title": "Validate JSON",
"description": "Check a JSON payload against a named schema. Returns valid and errors.",
"inputSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"payload": { "type": "object", "description": "Already parsed JSON object, not a raw string" },
"schemaId": { "type": "string", "description": "Stable schema id such as order.v1" }
},
"required": ["payload", "schemaId"]
}
}
Resources fit “read, then think”: loading schema://order.v1 is cheaper than making the model memorize a 200-line schema in the thread. Prompts fit a team’s canned openers. Roots, Sampling, and Logging are deprecated in 2026-07-28: pass workspace paths as tool arguments or resource URIs; Servers should not ask the Host for a completion; logs go to stderr or OpenTelemetry.
How it stacks with Tool Calling
Three names get flattened into one. They are not the same layer — the Agent JSON data-flow article traces each hop. Here, only the mapping:
| Layer | Between | Typical message |
|---|---|---|
| Function Calling / Tool Calling | Model API ↔ Host | tools[] + tool_calls.arguments |
| MCP | Host ↔ Server | JSON-RPC tools/list, tools/call |
| JSON Schema | The contract, not the transport | inputSchema / parameters |
Function Calling is OpenAI’s early name; Tool Calling is the later generic term (Claude tools, Gemini Function Calling, OpenAI Tools API). For developers it is one flow: Host sends a schema, the model returns a call with JSON arguments, Host runs it, then stuffs a JSON result back into the thread.
MCP does not replace that layer. A Host that calls in-process functions with Tool Calling only is still valid. MCP makes tools discoverable, cross-process, and reusable across Hosts. Enterprise agents almost always stack both; scripts and demos often skip MCP.
Two mapping traps: model APIs often give arguments as a string; MCP params.arguments is an object. And the name from tools/list must reach the model and tools/call unchanged — do not invent a “friendlier” alias in the middle. Validate before the real tools/call; see Tool Calling and JSON Schema validation.
One complete tool call
The user says: “Validate this order JSON with order.v1.” On 2026-07-28, the path is:
- Host → Server:
server/discover(cacheable) to confirm tools; or send the next request and retry on a version error. - Host → Server:
tools/listreturns items withinputSchema; the result may carryttlMs/cacheScope. - Host → model: map the list to
tools[].parameters(still JSON Schema). - Model → Host:
tool_callswithnamevalidate_json;argumentsis often stringified JSON. - Host validates:
JSON.parse, then checkinputSchema. On failure, write the error as a tool result — do not touch the real Server. - Host → Server:
tools/callwith objectargumentsand protocol version in_meta. - Server → Host:
result.content; Host may checkoutputSchemaagain. - Host → model: a
role: toolJSON string; the model answers the user or starts another tool turn.
User natural language
│
▼
Host ──JSON Schema──► LLM Tool Calling
│ │
│ ▼
│ arguments JSON
▼ │
MCP JSON-RPC ◄──── tools/call only after validation
│
▼
result JSON ──► tool message ──► model’s final answer
On remote transport, HTTP headers must include MCP-Protocol-Version, Mcp-Method, and Mcp-Name, and they must match the body or the Server should reject. Load balancers can route on headers without parsing JSON. Local stdio has no those headers; the JSON-RPC method names are the same.
What to remember from 2026-07-28
The July spec is the largest revision since launch, and 28 July 2026 is the final publication date. For “what is MCP,” keep the list below. Whether your Server needs code changes is still the migration article’s decision tree.
- No handshake, no protocol session:
initialize/initializedandMcp-Session-Idare gone. Every request is self-contained. Thread application state with an explicitbasket_id(or similar) as a normal argument. Do not expect the transport to remember you. - Discovery is
server/discover: optional, but one call returns supported versions, capabilities, and serverInfo. List results carryttlMs; a long SSE stream is no longer the only way to learn that tools changed. - Schemas are JSON Schema 2020-12: input root stays an object; composition and refs are allowed; do not auto-dereference external
$ref. Output schemas are no longer object-only. - Roots / Sampling / Logging are deprecated: methods still work inside the one-year window. New Servers should not implement Sampling to ask the Host for a completion.
- Extensions: Tasks and MCP Apps are official extensions, not core must-haves. Long work uses a task handle +
tasks/get. Do not invent your own session.
Hosts and Servers still on 2025-11-25 keep using initialize. When versions mix, use the negotiated protocolVersion. Do not send this article’s sessionless frames to an old Server. For what to install, see 2026 MCP Server rankings.
What to do now
- Draw three layers before you write code: the model API’s Tool Calling, Host orchestration, MCP Server. Scripts can stop at the first two. Cross-IDE reuse is when you write a Server.
- Use an official SDK; do not hand-roll JSON-RPC frames:
@modelcontextprotocol/sdkand the other official language packs already handle discovery, transport, and error codes. Hand-written SSE or private fields are the usual “you must change code” case in the migration guide. - Write
inputSchemaas a contract you can validate alone:additionalProperties: false,required, enums, length caps. Models omit fields and stringify numbers. Block once with the same schema before execution. - stdio locally, Streamable HTTP remotely: personal debugging does not need HTTP. Shared team access, many clients, or a gateway is when you go remote — plus OAuth and least privilege.
- Cache lists, trim results: honor
ttlMs. Do not pour raw stacks back into the model. A bigger window does not make dirty JSON safe — see 1M token context windows. - Check fixtures in the browser before you hit a live Server: save
inputSchema, good / bad arguments, and sample Server returns as JSON; validate and Diff on this site. Nothing is uploaded. Same habit as testing a REST contract.
FAQ
Is MCP a model or a framework?
Neither. MCP is an open protocol between a Host and external tool processes. Messages are JSON-RPC 2.0. Models still come from vendor APIs; orchestration still lives in the Host / agent runtime. There is no “MCP model.”
If I already have Tool Calling, do I need MCP?
If tools are in-process and hardcoded in the Host, Tool Calling is enough. Add MCP when you need reuse across apps, process isolation, or dynamic discovery. 2026 IDE agents usually run both layers; one-shot CLI scripts often have no MCP.
Is MCP JSON-RPC or REST?
The data layer is JSON-RPC 2.0, not “one HTTP path per tool.” Remote transport may use Streamable HTTP, but the body is still a JSON-RPC object, with the method in both method and the Mcp-Method header. Do not split MCP as if it were REST resources.
Do I still write initialize after 2026-07-28?
The new spec has no initialize / initialized and no Mcp-Session-Id. Version and client identity go in _meta on every request. If you only talk to a 2025-11-25 Server, keep the old handshake. Follow the negotiated protocolVersion; do not mix envelopes.
Will MCP replace OpenAPI?
No. OpenAPI describes HTTP APIs; MCP describes how an agent runtime discovers and calls tools. The usual pattern is keep OpenAPI on the REST service and wrap a thin MCP Server that maps paths to tools/call.
How do I check MCP JSON locally?
Save inputSchema, sample model arguments, and sample tools/call returns as files. Use the JSON toolbox in the browser for syntax and structure checks, then Diff two schema versions. Data never leaves the browser.
Takeaways
MCP is the 2026 agent tool socket: JSON-RPC 2.0 moves discovery and invocation between Host and Server; the model side is still Tool Calling; JSON Schema is the shared contract. It is not a model, not a framework, and not a replacement for OpenAPI. Spec 2026-07-28 removed sessions from the protocol, so requests must be self-contained. The three primitives — Tools, Resources, Prompts — did not change.
This guide is only the layering. Byte shapes per hop are in the data-flow article; whether an old Server must change code is in the migration article; which Servers to install is in the ranking article. Before you wire anything live, validate the schema and sample JSON locally — you can swap models; field names and required should not move.