LabHub

Blog

The Model Context Protocol (MCP): An Engineer's Reference

한국어English日本語中文

Introduction — what MCP is, and the problem it solves

In the words of the official docs, the Model Context Protocol (MCP) is "an open-source standard for connecting AI applications to external systems." It gives applications like Claude or ChatGPT a standardized way to connect to data sources (local files, databases), tools (search, calculators), and workflows (specialized prompts). The docs offer a memorable analogy: think of MCP as "a USB-C port for AI applications" — one connector standard instead of a bespoke adapter per device.

Why standardize? The usual framing is the M×N problem. If you have M AI applications and N tools or data sources, then without a standard you write M×N bespoke integrations by hand. A shared protocol collapses that to M+N — build a server once and every protocol-speaking client can use it, and a client that implements the protocol can reach every server. The docs put it as "build once and integrate everywhere." MCP borrows this idea from the Language Server Protocol (LSP): where LSP standardized the "editor × language" matrix, MCP standardizes the "AI app × tool" matrix.

MCP was introduced and open-sourced by Anthropic in November 2024, shipping initially with Python and TypeScript SDKs and prebuilt servers for Google Drive, Slack, GitHub, Git, Postgres, and Puppeteer. It was subsequently adopted by OpenAI and Google DeepMind, making it a de facto industry standard.

Architecture — hosts, clients, servers, and transports

MCP follows a client-server architecture with three participants:

The key rule is one client per server. The host instantiates a dedicated client for each server it connects to, and each client keeps its own independent connection. If VS Code connects to a filesystem server and a Sentry server, two client objects exist internally.

The protocol has two layers. The data layer is a JSON-RPC 2.0 exchange protocol that defines lifecycle management and the primitives (tools, resources, prompts, notifications); the transport layer handles the actual communication channels and authentication. Connections are stateful and begin with a handshake: the client sends an initialize request to negotiate the protocolVersion and each side's capabilities, then signals readiness with a notifications/initialized message.

There are two transports:

The transport layer abstracts these details away so the same JSON-RPC message format works across any transport.

The three primitives — tools, resources, prompts

Primitives are the most important concept in MCP, and the three a server exposes are the core of it. They differ in who controls them:

Resource URIs come in two shapes — fixed (direct resources) and parameterized (templates), illustrated below:

file:///Users/me/notes.md          # direct resource (fixed URI)
calendar://events/2026             # direct resource
weather://forecast/{city}/{date}   # resource template (parameters)

The design follows a regular pattern — discovery via */list, retrieval via */get, and execution via tools/call. Listings are dynamic, so when a server's tools change it can notify clients with messages like notifications/tools/list_changed.

Conversely, clients can expose primitives to servers:

Building a server — how to think about it

Building a server is really about deciding what to expose as a tool, a resource, or a prompt. Actions become tools, readable context becomes resources, and structured workflows become prompts. The official SDKs are TypeScript, Python, C#, and Go (Tier 1); Java and Rust (Tier 2); Swift, Ruby, PHP, and Kotlin (Tier 3). All provide the same functionality following each language's idioms, so exact APIs differ — check the per-language docs.

A tool definition is a name, a description, and an input schema. The shape from the docs (illustrative):

{
  "name": "searchFlights",
  "description": "Search for available flights",
  "inputSchema": {
    "type": "object",
    "properties": {
      "origin": { "type": "string", "description": "Departure city" },
      "destination": { "type": "string", "description": "Arrival city" }
    },
    "required": ["origin", "destination"]
  }
}

The client first fetches these definitions via tools/list and registers them with the LLM; when the model picks a tool, the client executes it via tools/call. The JSON-RPC on the wire looks like this (illustrative):

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

The response comes back as a content array that can carry multiple formats — text, images, resources. For development and debugging, the official MCP Inspector and the reference server collection are good starting points.

Tradeoffs and maturity — an honest read

The appeal is clear: integrate once, and the whole ecosystem shares one format, LSP-style. But there are things to look at soberly.

Closing

The core of MCP is not a flashy new technology but "boring standardization" — and that is precisely its value. Understand three primitives (tools, resources, prompts) and one thin format (JSON-RPC), and any client connects to any server the same way. If you are an engineer wiring agents into real systems, understanding this one protocol layer will outlast whichever framework you pick on top of it.

References

Comments

No comments yet.

Sign in to leave a comment