MCP / Model Context Protocol Explained for Builders
MCP is a standard wire protocol for connecting models to tools, data, and prompts — so you stop writing a bespoke integration for every app and every source.
The Model Context Protocol is an open standard for connecting a model to the tools, data, and prompts it needs, using one common interface instead of a custom integration per app and per source. A source, say your order database, a GitHub account, a filesystem, exposes its capabilities once as an MCP server. Any MCP-capable host, Claude Desktop, an IDE, your own agent, connects to it and gets those capabilities without you writing glue code for that specific pairing. That is the whole pitch: turn an N-by-M mess of bespoke integrations into an N-plus-M set of standard connections.
I build agents for a living, and before MCP the tax was real. Every new data source meant hand-wiring tool definitions into every app that needed it, then rewriting the same wiring when the app or the model changed. MCP is the USB-C analogy everyone reaches for, and it earns it: a standard plug so the thing providing the capability and the thing consuming it stop having to know about each other's internals. This is the developer's version — what MCP actually is, how it slots into an agent, when to bother, and where it bites.
The architecture: host, client, server
Three roles. The host is the application the user interacts with, the thing that talks to the model and manages context. Inside the host live one or more clients, and each client holds a one-to-one connection to one server. The server is a separate program that exposes capabilities. Your host might run a filesystem server, a database server, and a Slack server at once, three clients, three servers, one host coordinating them.
Servers talk to clients over JSON-RPC 2.0, across one of two transports. stdio runs the server as a local subprocess and pipes messages over standard in/out, which is how most local integrations work. Streamable HTTP is for remote servers you reach over the network, with OAuth for auth. The transport is deliberately boring; the point is that the same primitives ride over either one, so a tool that runs locally today can move behind an HTTP endpoint later without the host caring.
Crucially, MCP is an interface layer, not a runtime. It does not run your agent loop, decide when to call a tool, or manage your context window. It standardizes how tools and data are described, discovered, and invoked. The loop is still yours — see building AI agents that actually work for that part. MCP just changes where the tools come from.
The three primitives servers expose
A server can expose up to three kinds of capability, and knowing which is which matters because hosts treat them differently.
Tools are model-controlled executable functions: search orders, create a file, send a message. Each has a name, a description, and a typed input schema, and the model decides when to invoke one. This is the primitive that maps directly onto function calling, and it is the one every host supports.
Resources are application-controlled read-only context, addressed by URI: a file, a database row, a page of docs. The distinction is who decides to use them. A tool is something the model chooses to call; a resource is context the host or user chooses to load into the conversation. Think "attach this document" rather than "the model went and fetched something."
Prompts are user-controlled reusable templates, frequently surfaced as slash commands. A server can ship a /summarize-pr prompt that expands into a well-structured instruction with the right arguments filled in.
Tools are universally supported; resource and prompt support varies by client, so build assuming tools work everywhere and check before you lean on the other two. There's also a reverse channel worth knowing: sampling lets a server ask the host to run a model completion on its behalf, so a server can use the model without holding its own API key. Support for that is thinner still, so treat it as a bonus, not a foundation.
MCP versus plain function calling
This is the question I get most, and the honest answer is that MCP is not a replacement for function calling, it wraps it. When you define a few tools inline in the same codebase as your agent, you are doing plain function calling, and for a single app with tools that only it needs, that is the right call. No extra process, no protocol, less to break. The mechanics of getting the model to emit clean, valid tool calls are the same either way, and that's covered in structured output and tool use.
MCP earns its keep the moment reuse or decoupling enters the picture. Reach for it when you want the same tool server usable across several hosts, when you want to pull in a third-party server you didn't write, when you want tools isolated in their own process or a different language than your agent, or when you want to expose your own data to other people's agents. A Postgres server written once serves your agent, your teammate's IDE, and a desktop app without any of them re-implementing it. That decoupling is the entire value; on a small, self-contained app it is overhead you don't need. The general discipline of picking the lightest thing that does the job is in single prompt vs agent vs workflow and the field guide to building with LLMs.
How it fits an agent
Wiring is straightforward. Your agent host starts up, connects its clients to whatever servers you've configured, and calls tools/list on each to discover what's available. Those tool definitions get merged and passed to the model exactly like inline tools. When the model emits a tool call, the host routes it to the owning server via tools/call, gets the result back, and feeds it into the loop. Same loop as always: model decides, tool runs, result feeds back, repeat until your stopping condition. MCP has just made the tools pluggable and swappable instead of hardcoded.
The gotchas
Tool overload is the big one. The temptation is to connect every server you can and let the model sort it out. Don't. Every tool definition costs context tokens on every turn, and a model staring at forty tools from six servers picks worse than one staring at the handful that matter. Curate which servers load for a given task, the same way you'd manage any other context budget — see context engineering.
Security is not optional. A local stdio server is a subprocess running with your privileges, so installing an untrusted one is arbitrary code execution on your machine, full stop. Then there's tool poisoning, where malicious instructions hide in a tool's description that the model reads and obeys, and prompt injection that rides in on the content a resource returns. Vet servers before you install them, give them least privilege, sandbox where you can, and use scoped OAuth for anything remote. Treat a third-party MCP server with the same suspicion as any dependency that runs code.
Reliability adds hops. Each server is a separate process or network endpoint that can crash, hang, or return junk. Handle a server going down without taking the whole agent with it. And namespace your tools, because two servers exposing a search tool will collide and confuse the model about which is which.
It doesn't make the model smarter about when to call things. MCP standardizes the plumbing; it does nothing for tool selection. A vague description still gets a tool called at the wrong moment. The discipline of writing descriptions that say when to use a tool applies exactly as much to an MCP tool as an inline one.
MCP is a genuinely useful standard for the narrow, real problem of not rewriting the same integrations forever. It is not a framework, not an agent, and not magic. It's a well-designed plug. Use it where reuse and decoupling pay for the extra moving parts, skip it where a plain inline tool would do, and keep the same rigor around tool design, context, and security that you'd bring to any agent — the protocol handles the wiring and nothing else. Which is exactly what you want a protocol to do.
Use the free, no-API prompt generators to put it into practice.
Building AI Agents That Actually Work
An agent is a loop: model, tools, memory, and a stopping condition. Here's how to build one that finishes the job instead of spiraling.
ComparisonAI Agent Frameworks Compared
Framework or roll your own? An honest comparison of LangChain, LlamaIndex, CrewAI, and provider SDKs against a plain API loop — on control, lock-in, debuggability, state, and production-readiness.
GuideBuilding eval datasets that catch regressions
Your eval set is only as good as the cases in it. Here's how I source real failures, write pass/fail criteria that hold, and keep the set honest as it grows.