MCP (Model Context Protocol): The Standard for AI Agent Tools
MCP (Model Context Protocol)
MCP is an open protocol that lets AI models call external tools. Instead of an LLM being limited to generating text, MCP gives it the ability to read files, query databases, control browsers, send emails, and interact with any system that exposes an MCP server. Anthropic published the spec in late 2024, and by early 2026 it has become the default way AI coding agents connect to the outside world.
If you have used Claude Code, Cursor, Windsurf, or any similar tool and noticed it can interact with your browser, calendar, or Slack, there is a good chance MCP is the plumbing underneath.
How MCP Works
The protocol follows a client-server architecture. The AI agent (the client) connects to one or more MCP servers. Each server advertises a list of tools it can execute. When the model decides it needs to use a tool, it sends a JSON-RPC request to the server, which runs the operation and returns the result.
The transport layer is typically stdio (the server runs as a subprocess and communicates over stdin/stdout) or SSE (Server-Sent Events over HTTP for remote servers). The stdio approach is the most common for local development because it requires zero network configuration.
The key insight: the model never talks to Gmail or Chrome directly. It talks to an MCP server, which translates the request into the correct API call. This is what makes MCP composable. You can swap servers without changing the model or the prompt.
The Lifecycle of an MCP Call
When an agent boots up, the initialization handshake looks like this:
- The client spawns the server process (or connects via HTTP)
- The client sends an
initializerequest with its capabilities - The server responds with its own capabilities and the list of available tools
- The client sends
initializedto confirm - Normal tool calls can begin
Each tool call follows a simple request/response pattern:
{
"method": "tools/call",
"params": {
"name": "read_email",
"arguments": {
"query": "from:support@example.com",
"maxResults": 5
}
}
}
The server executes the function, returns the result as structured content (text, images, or both), and the model incorporates that result into its next response.
Setting Up MCP Servers
Most AI coding tools store MCP configuration in a JSON file. For Claude Code, it lives in ~/.claude/settings.json or the project's .claude/settings.json:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@anthropic-ai/playwright-mcp"]
},
"filesystem": {
"command": "npx",
"args": [
"@anthropic-ai/mcp-filesystem",
"/Users/you/projects"
]
}
}
}
For stdio servers, you specify the command and arguments to launch the process. For SSE servers, you provide a URL instead. The agent handles the lifecycle: it starts the server when needed and shuts it down when the session ends.
Popular MCP Servers in 2026
The ecosystem has grown fast. Here are the servers that see real daily usage across developer workflows:
| Server | What it does | Transport | |---|---|---| | Playwright MCP | Browser automation via CDP snapshots and clicks | stdio | | Filesystem | Read, write, search files in allowed directories | stdio | | Gmail | Read, send, search email programmatically | stdio | | Google Calendar | Create, read, update calendar events | stdio | | GitHub | Issues, PRs, repo operations via the GitHub API | stdio | | Postgres/MySQL | Run SQL queries against databases | stdio | | Slack | Send and read messages across channels | stdio | | macos-use | Control any macOS app via the accessibility API | stdio | | Linear | Create and manage issues and projects | stdio |
The Playwright and filesystem servers come from Anthropic. The rest are community-built. Quality varies. Some servers return 50KB of JSON per call and blow through context windows in a few turns. Others are tight and well-scoped.
Where MCP Shines
Composability. You can mix and match servers for your workflow. A single agent session might use Playwright to browse a website, the filesystem server to save results, and the Gmail server to email a summary. Each server is independent.
No vendor lock-in. Because MCP is an open protocol, the same server works with Claude Code, Cursor, Cline, and any other client that implements the spec. You write the integration once.
Local-first. The stdio transport means most servers run on your machine with no cloud dependency. Your data stays local. The agent talks to a subprocess, not a remote API (unless the server itself calls one).
Where MCP Falls Short
Context window bloat. Every tool the server advertises costs tokens in the system prompt. A server with 40 tools can eat 2,000+ tokens before the conversation even starts. We wrote about this in detail in MCP tool token overhead optimization. The practical fix: use fewer servers and disable tools you do not use.
Discovery is still messy. There is no single, trusted registry of MCP servers. New registries appear every week, each with different quality standards. Finding the right server for a task still involves searching GitHub and hoping the README is accurate. We covered this in the MCP discovery problem.
Debugging is painful. When an MCP server fails, the error message is often swallowed by the stdio pipe. You get a generic "tool call failed" from the agent with no stack trace. Logging to stderr helps, but you need to set it up yourself. See debugging MCP servers for the approach we use.
Security surface. An MCP server runs with whatever permissions its process has. A poorly written server can expose your filesystem, leak credentials, or execute arbitrary commands. There is no built-in sandboxing in the protocol itself. We explored this in MCP server trust surface security.
MCP vs CLI Tools vs Direct API Calls
A common question: why not just let the agent run shell commands or call APIs directly? The answer depends on what you are optimizing for.
| Approach | Strengths | Weaknesses | |---|---|---| | MCP server | Structured tool schema, composable, discoverable by the model | Extra process overhead, token cost for tool definitions | | Shell commands via Bash | Zero setup, universal, model already knows common CLI tools | Unstructured output, easy to misparse, no schema | | Direct API calls (curl/fetch) | Full control, no middleware | Model must know exact endpoints, auth handling is ad-hoc |
In practice, most workflows mix all three. The agent uses MCP for structured integrations (email, calendar, browser), Bash for quick system operations (git, file manipulation), and direct API calls when no MCP server exists yet. We compared the tradeoffs in more detail in MCP vs CLI for AI agents.
Building Your Own MCP Server
If you need to integrate a tool that no existing server covers, building one is straightforward. The minimum viable server in TypeScript:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server(
{ name: "my-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
server.setRequestHandler("tools/list", async () => ({
tools: [{
name: "greet",
description: "Return a greeting for the given name",
inputSchema: {
type: "object",
properties: {
name: { type: "string", description: "Name to greet" }
},
required: ["name"]
}
}]
}));
server.setRequestHandler("tools/call", async (request) => {
if (request.params.name === "greet") {
return {
content: [{
type: "text",
text: `Hello, ${request.params.arguments.name}!`
}]
};
}
});
const transport = new StdioServerTransport();
await server.connect(transport);
The SDK handles the JSON-RPC framing, the initialization handshake, and the lifecycle management. You just define your tools and implement the handlers. Python, Go, and Rust SDKs also exist.
Common Pitfalls
-
Too many servers at once. Each server adds tool definitions to the context window. Running 10 servers simultaneously can consume 10,000+ tokens of context before the user says a word. Start with 2 or 3 and add more only when needed.
-
Returning raw API responses. If your server returns the full JSON blob from a third-party API, the model has to parse it all. Filter and summarize the response server-side. Return only the fields the model actually needs.
-
No error messages in tool responses. When something fails, return a clear error in the tool result content. Do not throw an exception and let the transport swallow it. The model can recover from a well-described error; it cannot recover from silence.
-
Hardcoded credentials in server config. Use environment variables or a secrets manager. Never put API keys in the MCP config JSON. If you are on macOS, the system keychain is a good option.
-
Forgetting the initialize handshake. If you are building a custom client, make sure you complete the full
initialize/initializedexchange before sending tool calls. Skipping it causes silent failures on many server implementations.
The Bigger Picture
MCP is infrastructure, not magic. It gives agents a standardized way to call tools, which is genuinely useful because it means you do not have to re-implement integrations for every new AI client that launches. But the protocol itself does not make agents smarter or more reliable. The quality of an agent workflow still depends on the model's reasoning, the prompt guiding it, and how well the tools are designed.
The ecosystem is still young. Servers break, registries fragment, and token overhead is a real constraint. But the direction is right: a shared protocol for tool use is better than every platform inventing its own.
Fazm is an open source macOS AI agent. Open source on GitHub.