← Back to Learning Hub

MCP Fundamentals

The 2025 standard for agentsIntermediate14 min

By: Anacodic Team

TL;DR

  • MCP (Model Context Protocol) is an open standard from Anthropic (announced Nov 2024) that defines how LLM applications connect to external tools and data. Think of it as "USB-C for AI tools" — one connector standard instead of a custom cable for every device.
  • It solves the M×N integration problem: instead of building a bespoke connector for every (app × tool) pair, each app implements an MCP client once and each tool ships an MCP server once → the problem collapses from M×N to M+N.
  • Architecture has three roles: Host (the app, e.g. Claude Desktop / Cursor / your agent), Client (the connector living inside the host, one per server), and Server (exposes capabilities).
  • Servers expose three primitives: Tools (model-callable functions), Resources (readable data/context), and Prompts (reusable templated workflows).
  • Wire protocol is JSON-RPC 2.0 over one of two main transports: stdio (local subprocess) or Streamable HTTP (remote; superseded the older HTTP+SSE transport).
  • By 2025 MCP became a de-facto industry standard (OpenAI, Google, Microsoft, AWS adopted it) and was donated to the Linux Foundation's Agentic AI Foundation in December 2025.
  • MCP is not a replacement for function calling — it is the standardized delivery layer underneath it.

Simple explanation + analogy

An LLM by itself is a brain in a jar. It can reason, but it cannot read your database, open a file, or post to Slack. To do anything useful it needs tools and context.

Before MCP, every AI app wired up tools in its own private way. If you had M apps (Claude Desktop, Cursor, your custom agent) and N tools (GitHub, Postgres, Slack, your filesystem), someone had to write M×N custom integrations — and every one broke differently.

The USB analogy. Before USB, every peripheral had its own port: PS/2 for keyboards, serial for mice, parallel for printers. USB replaced all of them with one standard shape. Any USB device works in any USB port. MCP does exactly this for AI: any MCP-compatible app can talk to any MCP server, with no bespoke glue.

The trip-planning analogy. In a trip-planning assistant, a set of agents call tools like search_flights, get_activities, and preference tools. Today those are Python functions wired directly into the agents. If you wrapped each capability as an MCP server — a "flights server", a "hotels server", a "preferences server" — then any MCP host (Claude Desktop, Cursor, another team's agent) could reuse them without importing that app's Python code. That reuse across hosts is the entire point of MCP.


Diagram

                          ┌───────────────────────── HOST (the AI app) ─────────────────────────┐
                          │   e.g. Claude Desktop / Cursor / your LangGraph or Strands agent      │
                          │                                                                       │
   User ⇄ LLM  ◄────────► │   ┌─────────┐      ┌─────────┐      ┌─────────┐                        │
                          │   │ Client A │      │ Client B │      │ Client C │   (one client per     │
                          │   └────┬─────┘      └────┬─────┘      └────┬─────┘    connected server)  │
                          └────────┼─────────────────┼─────────────────┼───────────────────────────┘
                                   │ JSON-RPC 2.0     │                 │
                          stdio ───┤          Streamable HTTP ──────────┤
                                   ▼                  ▼                 ▼
                            ┌────────────┐    ┌──────────────┐   ┌──────────────┐
                            │ Filesystem │    │  GitHub MCP  │   │ Postgres MCP │   ← SERVERS
                            │   server   │    │    server    │   │   server     │
                            └─────┬──────┘    └──────┬───────┘   └──────┬───────┘
                                  ▼                  ▼                  ▼
                             Local files         GitHub API         Database

   Each server exposes:  [ TOOLS ]  (functions the model can call)
                         [ RESOURCES ] (data the app can read into context)
                         [ PROMPTS ] (reusable templated workflows)

How it works (deep)

The M×N → M+N argument

Say you have M AI applications and N external systems. In the pre-MCP world each app integrates each system its own way: M×N integrations, each with its own auth, schema, and error handling. Add one new tool and you must update all M apps.

MCP introduces a shared contract. Every app implements the client side of the protocol once. Every tool provider implements the server side once. Now:

  • Total integrations to build: M + N (each app once, each server once).
  • Adding a new tool = write one server; all M apps can use it immediately.
  • Adding a new app = implement one client; it instantly speaks to all N servers.

This is the same combinatorial win that USB, LSP (Language Server Protocol — MCP's explicit design inspiration), and ODBC delivered in their domains.

The three roles

  • Host — the user-facing application that contains the LLM and orchestrates everything (Claude Desktop, Cursor, VS Code, ChatGPT, or your own agent process). The host manages security, user consent, and how many servers to connect to.
  • Client — a protocol connector instantiated inside the host. There is a 1:1 relationship between a client and a server: if the host connects to 3 servers, it holds 3 client objects. The client handles the handshake, capability negotiation, and message routing for its one server.
  • Server — a separate program (local subprocess or remote service) that exposes capabilities. Servers are typically small, focused, and stateless-ish; they do not contain the LLM.

The three primitives (server → client)

PrimitiveWho controls invocationAnalogyExample
ToolsModel-controlled — the LLM decides to call itPOST endpoints / function callscreate_issue(repo, title), run_sql(query)
ResourcesApp/host-controlled — attached to contextGET endpoints / filesfile:///logs/app.log, postgres://schema
PromptsUser-controlled — user picks itSlash commands / templates/summarize-pr, /plan-sprint

This "who is in control" distinction is a favorite interview question. Tools are for actions the model chooses; resources are read-only context the application chooses to load; prompts are pre-authored workflows the user chooses to trigger.

There are also two primitives that flow client → server:

  • Sampling — a server can ask the host's LLM to complete a prompt (the server "borrows" the model), always gated by user approval.
  • Elicitation — a server can request additional input from the user mid-operation (added in the 2025 spec revisions).

The wire protocol: JSON-RPC 2.0

Every MCP message is a JSON-RPC 2.0 object. Two kinds:

  • Requests (have an id, expect a response): initialize, tools/list, tools/call, resources/read, prompts/get.
  • Notifications (no id, no response): notifications/initialized, notifications/tools/list_changed.

A session is stateful and begins with a mandatory handshake:

  1. Client → initialize (declares protocol version + client capabilities).
  2. Server → response (declares its capabilities: does it offer tools? resources? prompts?).
  3. Client → notifications/initialized.
  4. Normal operation: tools/list, tools/call, etc.

Capability negotiation matters: neither side may use a feature the other didn't advertise. If a server never declared tools, the client won't call tools/list.

Transports

  • stdio — the server runs as a local subprocess; messages go over stdin/stdout. Zero network exposure, lowest latency, ideal for local tools (filesystem, git). This is how most desktop MCP setups run today.
  • Streamable HTTP — the modern remote transport (introduced 2025-03-26 spec), which replaced the earlier HTTP + SSE two-endpoint design. A single /mcp endpoint handles POST requests and can upgrade to Server-Sent Events for streaming/server-initiated messages. It supports stateless operation on commodity HTTP infrastructure, which is what enables scalable hosted servers.

The math

MCP is a protocol, not an algorithm, so the only "math" that matters is the combinatorial integration count — and it is the whole reason MCP exists.

Let M = number of AI applications, N = number of tools/data sources.

$$ \text{Integrations}{\text{bespoke}} = M \times N \qquad\Longrightarrow\qquad \text{Integrations}{\text{MCP}} = M + N $$

Marginal cost of adding one new tool:

$$ \Delta_{\text{bespoke}} = M \quad (\text{update every app}) \qquad \Delta_{\text{MCP}} = 1 \quad (\text{write one server}) $$

For M = 10 apps and N = 50 tools: 500 bespoke integrations vs 60 with MCP — and each new tool afterward costs 1 instead of 10. This linear-vs-quadratic scaling is the elevator-pitch justification interviewers want to hear.


Real code

MCP is defined by messages on the wire. Here is the actual JSON-RPC exchange that opens a session and calls a tool — knowing this raw shape separates people who use MCP from people who understand it.

// 1) Client -> Server: initialize (handshake begins)
{ "jsonrpc": "2.0", "id": 1, "method": "initialize",
  "params": {
    "protocolVersion": "2025-06-18",
    "capabilities": { "roots": {}, "sampling": {} },
    "clientInfo": { "name": "my-agent", "version": "1.0.0" }
  } }

// 2) Server -> Client: response advertises capabilities
{ "jsonrpc": "2.0", "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": { "tools": { "listChanged": true }, "resources": {} },
    "serverInfo": { "name": "github-mcp", "version": "0.4.0" }
  } }

// 3) Client -> Server: initialized notification (no id, no reply)
{ "jsonrpc": "2.0", "method": "notifications/initialized" }

// 4) Client -> Server: discover tools
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }

// 5) Server -> Client: tool catalog (name + JSON Schema)
{ "jsonrpc": "2.0", "id": 2,
  "result": { "tools": [
    { "name": "create_issue",
      "description": "Open a new GitHub issue",
      "inputSchema": { "type": "object",
        "properties": { "repo": {"type":"string"}, "title": {"type":"string"} },
        "required": ["repo","title"] } } ] } }

// 6) Client -> Server: call the tool (the LLM chose to do this)
{ "jsonrpc": "2.0", "id": 3, "method": "tools/call",
  "params": { "name": "create_issue",
              "arguments": { "repo": "acme/api", "title": "Fix flaky test" } } }

// 7) Server -> Client: result
{ "jsonrpc": "2.0", "id": 3,
  "result": { "content": [ { "type": "text", "text": "Created issue #128" } ],
              "isError": false } }

You rarely hand-write this — SDKs (Python's mcp/FastMCP, TypeScript's @modelcontextprotocol/sdk) generate it — but every interview about MCP eventually asks "what actually goes over the wire?" The answer is JSON-RPC 2.0, starting with initialize.


Real-world example

GitHub via MCP. GitHub ships an official MCP server. A developer using Cursor (the host) says "open an issue for the failing CI job and link the last passing commit." Cursor's GitHub client calls tools/list (finding create_issue, get_commit, ...), the LLM picks create_issue with the right arguments, and the server calls the GitHub REST API. The exact same GitHub server works unchanged in Claude Desktop, VS Code, or a custom LangGraph agent — that reuse is the payoff.

Grounding in example projects. A fixed multi-step review pipeline on LangGraph could expose an MCP server whose tools are its retrieval and grading steps, so other clinical apps consume them without importing the pipeline's code. A trip-planning assistant (Strands multi-agent) with clean tool boundaries — flight_tools.py, activity_tools.py, preference_tools.py — has each @tool-decorated function mapping conceptually 1:1 onto an MCP tool; repackaging tools/ as an MCP server would let any MCP host reuse that travel intelligence.


Interview questions companies actually ask

1. What is MCP and what problem does it solve? [easy] An open standard (Anthropic, Nov 2024) for connecting LLM apps to tools and data. It replaces the M×N explosion of bespoke integrations with M+N: each app implements the client once, each tool ships a server once. (modelcontextprotocol.io, DataCamp)

2. Explain the host/client/server architecture. What's the client-to-server relationship? [medium] Host = the app containing the LLM; Client = a connector inside the host; Server = exposes capabilities. One client per server (1:1). The host may hold many clients, one for each connected server. The LLM lives in the host, never in the server. (Tenable FAQ)

3. What are the three server primitives and who controls each? [medium] Tools (model-controlled actions), Resources (app-controlled read-only context), Prompts (user-controlled templated workflows). The "who controls invocation" distinction is the crux. (modelcontextprotocol.io)

4. MCP vs plain function calling — aren't they the same thing? [hard] Function calling is a model capability: the LLM emits a structured request to call a function you defined. MCP is a transport and discovery standard for where those functions live and how they're advertised. Function calling still happens — MCP just standardizes the plumbing so tools are discoverable at runtime and portable across apps. They're complementary layers, not competitors. (Interview Kickstart)

5. What protocol and transports does MCP use? [medium] JSON-RPC 2.0 messages over stdio (local subprocess) or Streamable HTTP (remote; replaced the older HTTP+SSE transport). (modelcontextprotocol.io lifecycle)

6. Walk me through the session lifecycle. [hard] initialize request (client declares version + capabilities) → server response (declares its capabilities) → notifications/initialized → normal ops (tools/list, tools/call, resources/read, ...) → shutdown. Neither side may use un-negotiated features. (Medium: MCP lifecycle)

7. Who governs MCP now, and why does that matter? [easy] Anthropic donated MCP to the Linux Foundation's Agentic AI Foundation (AAIF) in Dec 2025; OpenAI, Google, Microsoft, AWS are involved. Neutral governance signals it's a durable cross-vendor standard, not a single-company play. (Linux Foundation, MCP blog)

8. What are sampling and elicitation? [hard] Client→server primitives. Sampling: a server asks the host's LLM to run a completion (server borrows the model), user-gated. Elicitation: a server requests more input from the user mid-task. Both require the capability to be negotiated at initialize. (modelcontextprotocol.io)

9. Is MCP a security improvement or a new attack surface? [hard] Both. It centralizes auth and consent, but connecting an agent to third-party servers introduces tool poisoning, prompt injection via tool descriptions, and confused-deputy risks. (See the security article in this module.) (Simon Willison)


When to use / tradeoffs

Use MCP when:

  • You want tools reusable across multiple hosts/agents (the reuse dividend is the whole point).
  • You're integrating third-party or off-the-shelf capabilities (GitHub, Slack, Postgres, filesystem) — official servers already exist.
  • You need runtime tool discovery so the tool catalog can change without redeploying the app.

Skip / defer MCP when:

  • You have a single app with a handful of private tools — a direct function-calling wire-up is simpler; MCP's process/handshake overhead isn't worth it.
  • Ultra-low-latency in-process calls matter (stdio adds subprocess/serialization cost).
  • You can't yet afford the security review third-party servers demand.

Tradeoffs: standardization + portability + ecosystem vs. extra moving parts (server processes, handshake, transport) and a genuinely larger attack surface. MCP shines at M×N scale; it's overkill for M=1, small N.


  • MCP is the open USB-C standard for connecting LLM apps to tools and data, turning M×N integrations into M+N.
  • Host ↔ Client (1:1) ↔ Server; servers expose Tools / Resources / Prompts over JSON-RPC 2.0 on stdio or Streamable HTTP.
  • It's complementary to function calling, now under Linux Foundation governance, and adopted across the industry.

Related articles in this module (6-3):

Sources: modelcontextprotocol.io · Wikipedia: Model Context Protocol · Linux Foundation / AAIF · MCP joins AAIF · DataCamp MCP interview Qs · MCP lifecycle spec

Runnable notebook

Run it end to end — the mock model needs no API key; add your own key for the real Claude section.

Open In Colab