MCP in Production: What It Solves
Every agent framework claims Model Context Protocol support. Fewer teams have run an MCP server in production and dealt with the consequences. Kinetic Edge runs one: a read-only server on this site at /api/public/mcp that exposes our published writing through four tools (search posts, get one post, list posts, and a firm overview), rate limited by IP, with nothing that writes. It is deliberately narrow, and most of what follows applies even to a server this small.
The short version: MCP solves a concrete problem, and not the one most people think it does. It's a well-designed protocol for one pattern: exposing tools and resources to LLM clients through a standard interface. Once you understand what that means, MCP gets useful.
The problem MCP solves
Before MCP, integrating a new data source or tool into an agent looked like this: write a custom tool wrapper, hardcode the schema into the agent prompt, redeploy the agent every time the tool changed. Every framework had its own tool interface. Every model provider had a different function-calling format. Every integration was custom.
MCP standardizes three things: how a client discovers what tools and resources are available, how it calls them, and how it receives structured results. The host is the LLM application (Claude Desktop, Cursor, your agent runtime), and it runs one MCP client per server. The server is anything that wants to expose capabilities: a database, an API, a filesystem, a custom internal service.
Reference architecture
Each MCP server exposes three primitives: tools (functions the model can call), resources (data the model can read), and prompts (parameterized templates). The client negotiates capabilities on connect, then the model decides what to invoke. Our server exposes tools only, over JSON-RPC 2.0 on HTTP POST.
Where MCP pays off
Internal tool sprawl. If you have five agents integrating with the same six internal systems, MCP lets you write each integration once as a server, then any agent client can consume it.
Model-agnostic tooling. MCP servers work across providers. The same filesystem server works with Claude, GPT, and any client that speaks MCP. If you're multi-model, MCP is close to essential.
Local data with strict boundaries. MCP's stdio transport is useful for local dev workflows where the agent shouldn't touch the network.
What you still have to build
You still own authorization. The spec defines an OAuth 2.1 flow for connecting to remote servers, but what a caller may do once connected is your server's job to enforce. Every tool call needs its own permission check on the server side, and every resource its own scoping. The protocol only defines the shape of the conversation. Our server needs no authentication because nothing protected is reachable through it: no contact form, no newsletter, no subscriber data, no writes. That exclusion list is the access control.
The hard part is deciding whose permissions the agent uses. In a multi-user system the agent should act on the user's behalf with delegated credentials, so it can only reach data that user is already entitled to see. Get this wrong and an agent answers one user with another user's data. Multi-Tenant AI and Workload Identity for Agents cover the mechanics.
You still own the context budget. Every tool a server exposes has a name, a description, and a schema, and all of it goes into the model's context on every request, whether or not the model calls it. Our server exposes four tools, and every one of them costs context on every call. Tool Design Is Prompt Design covers how to budget the catalog.
You still own observability. The protocol carries requests and responses. It doesn't carry who invoked what, when, and why. Build that yourself, or you'll debug agent behavior by staring at prompt histories.
You still own orchestration. An MCP client talks to servers. It doesn't route between agents, coordinate multi-agent workflows, or manage state. Those go on top of MCP (LangGraph, custom orchestration, or a supervisor pattern).
Production patterns worth stealing
One domain per server. A monolithic internal-services server exposing thirty tools is miserable to debug. Split servers by domain (jira-mcp, github-mcp, warehouse-mcp) and let the client compose them.
Version your tool schemas. MCP handles capability discovery. It doesn't handle schema evolution. When you change a tool's parameters, existing agent prompts and evals break without warning. Version your tools explicitly and treat breaking changes like API breaking changes.
Wrap every server in a permission layer. Before the tool executes, check: is this client allowed to call this tool with these arguments on this resource? Do it on the server, every time, no exceptions. The agent will try things it shouldn't.
Write errors the model can act on. Whatever a tool returns on failure becomes the model's next context. Our server answers a bad slug with the slug format and the name of the search tool to try instead, and an unknown method with the list of methods it supports.
Log at the protocol level. Log every JSON-RPC request and response. Protocol logs capture exactly what crossed the wire, discovery included, which is what you need when an agent does something surprising. Our server logs the tool name, the arguments, the latency, and whether the call succeeded, on every call.
When we don't reach for MCP
Single-agent, single-provider systems where all tools are internal. If you're building one agent that calls three of your own APIs, direct function calling is simpler and one fewer moving part. MCP earns its complexity when you have multiple clients, multiple providers, or a growing internal tool catalog.
Working on something like this?
Start a Conversation