cat posts/2024-11-28-the-model-context-protocol.md
The Model Context Protocol
Every AI integration I’ve built or reviewed in the last two years has had the same shape. There’s a model, there’s something it needs to read or do (our help articles, a ticket, a database query), and there’s a pile of glue code in between that’s specific to that model’s API, that thing’s API, and this particular app. Nobody else can reuse it. When we put a thin interface in front of the model last year, it fixed half of that, the half facing the model. The other half, the half facing the tools, is still glue.
On Monday Anthropic announced the Model Context Protocol, which is an attempt to standardize that second half. They released a specification, SDKs for Python and TypeScript, support for local MCP servers in the Claude desktop app, and a repository of open-source servers for things like Google Drive, Slack, GitHub, Git, Postgres and Puppeteer. The pitch is the one you’d expect: today, every pairing of an AI app and a data source needs its own integration, and with a shared protocol, each app implements the client side once and each data source implements the server side once.
If that sounds like the Language Server Protocol, it’s supposed to. The MCP documentation says as much. Before LSP, every editor needed its own support for every language. After it, a language ships one server and every editor that speaks LSP gets go-to-definition for free. It’s one of the more successful standards of the last decade, and Microsoft got it adopted mostly by building the first good implementation into VS Code and making it open. Anthropic is clearly trying the same move with the Claude app.
What’s in it
There are three roles. The host is the application the user runs, Claude Desktop for now, or an editor. Inside it, a client keeps a connection to one server. A server is a small program that wraps one system, a folder, an API, a database, and describes what it offers.
A server can offer three kinds of thing. Tools are functions the model can call, with a name, a description and a JSON Schema for the arguments. Resources are data the application can read and put in front of the model, identified by URIs. Prompts are templates a user can pick from a menu. There’s also a feature going the other way, called sampling, where a server can ask the host’s model for a completion, which is interesting and which I haven’t tried.
The messages are JSON-RPC 2.0, the same as LSP. For a local server, the host starts it as a child process and they talk over stdin and stdout. For a remote one, there’s an HTTP transport with server-sent events. A tool call looks like this:
{"jsonrpc": "2.0", "id": 7, "method": "tools/call",
"params": {"name": "search_notes", "arguments": {"query": "busy beaver"}}}
and the result comes back as a list of content items, text or images, with the same id. Before any of that, client and server do an initialize handshake where each says which features it supports, which is how the protocol expects to grow without breaking old servers. If you’ve ever written an LSP server, none of this will surprise you, and if you haven’t, it’s about an afternoon to learn.
My notes server
I spent most of this morning writing one, which is not how I expected to spend Thanksgiving, but the house is quiet at 7 a.m.
My notes live in Obsidian, which means a folder of Markdown files. The reference servers include a filesystem server that would have done this, but I wanted to see the protocol from the inside. Mine has two tools, search_notes, which does a plain substring search and returns titles and the matching lines, and read_note, which returns one note’s contents, and it exposes each note as a resource too. It’s about 90 lines of Python with the official SDK, most of which is the JSON Schema for the two tools and path handling.
Wiring it into Claude Desktop is a few lines in a JSON config file: a name, a command to run, and its arguments. Restart the app, and a little tools icon shows up with my two tools listed. The first time the model wanted to call one, the app asked me to approve it, which I appreciated.
Then I asked it what I’d written about busy beavers, and it searched my notes, read the two matching ones, and gave me a summary that included a point I’d forgotten writing down. That’s a good feeling, and slightly unsettling.
One thing I did before any of that: the vault has a folder of work meeting notes, and the server refuses to read anything under it, by path, before it does anything else. Our AI policy is that company information only goes to AI providers who’ve been through vendor review and are on our subprocessor list, and Anthropic isn’t, so this is a personal-notes experiment, on my own account. I’d rather the code enforce that than rely on me remembering which question is which.
Is it a standard?
Not yet. Right now it’s a specification from one company, with one host that supports it, Anthropic’s own. The announcement says Zed, Replit, Codeium and Sourcegraph are working with it, and Block and Apollo have integrated it, which is a decent start for day one. But a protocol for connecting models to tools becomes a standard when someone who competes with the author adopts it. LSP mattered because editors that weren’t VS Code implemented it. MCP will matter if a host that isn’t Claude does, and the one I’m watching for is OpenAI, which has its own way of doing tools and plugins and no particular reason to adopt a competitor’s protocol.
The other open question is security, and it’s the same one that’s been following me through every post about agents. A local MCP server runs with my user’s permissions, so installing one is like installing any program, and I’d want to read the code of anything I didn’t write. And everything a server returns goes into the model’s context, so a server that wraps something with untrusted content in it, an inbox, a ticket queue, a web page, is a new way for text to reach the model and act like instructions. The approval prompt helps. It also asks the same question every time, which is how people learn to click yes without reading.
For work, if Anthropic gets through vendor review, the obvious first server is the read-only reporting replica that our support and finance people have been writing GPT-4-assisted queries against since last year. A Postgres server that only has a read-only role and can only see that replica is very close to what they already do by hand. Until then, it stays on my laptop, talking to my notes.