An AI agent without tool access is a chatbot with ambitions. It can reason about what to do, but it cannot actually do it. MCP is the layer that closes that gap, and it does it by turning every integration into a published contract rather than a block of glue code buried in one agent's codebase.
What Model Context Protocol actually standardises
Before MCP, every agent integration was bespoke. Connecting an agent to a CRM meant writing CRM-specific code. Connecting to a mailbox meant writing mailbox-specific code. Each integration carried its own authentication, its own error shapes, and its own maintenance burden, and none of it was reusable by the next agent.
MCP defines three things and deliberately leaves the rest alone:
- Discovery. A server tells a connecting client which tools it exposes, without the client knowing anything in advance.
- The tool contract. Each tool carries a name, a description, and a JSON Schema for its arguments. The schema is what the model plans against.
- Transport. How the two processes talk — stdio for a local process, HTTP with server-sent events for a remote one.
What it does not define is which tool should be called, what an acceptable argument is for your business, or whether the result should be acted on. Those are your decisions, and keeping them out of the protocol is the reason one server can serve several agents.
What a tool contract looks like
This is the level of specificity that makes the difference between an agent that calls a tool correctly and one that hands it a paragraph of prose. A contract for a single CRM lookup, written as an MCP server would advertise it:
{
"name": "crm.find_contact",
"description": "Look up exactly one contact by email address.
Returns null when no contact matches. Never creates a record.",
"inputSchema": {
"type": "object",
"properties": {
"email": { "type": "string", "format": "email" }
},
"required": ["email"],
"additionalProperties": false
}
}Three details in that block carry most of the value. additionalProperties: falsemeans a hallucinated extra argument is rejected at the boundary instead of being silently ignored. required means a missing email is a validation error, not an unfiltered query returning the whole contact table. And the description states the negative case — returns null when no contact matches, never creates a record — because a model choosing between tools reads descriptions, and a tool that might create something is a tool that needs an approval gate in front of it.
The same discipline applies to what comes back. A tool that returns free text puts the parsing burden back on the model on every single call. A tool that returns a fixed shape makes the next step deterministic. It is the same argument we make abouta research agent that cannot fabricate: structure at the data layer removes a class of failure that no amount of prompt tuning reliably removes.
Why MCP matters once you have more than one agent
With one agent and two tools, MCP is overhead. The economics change with the third consumer:
- Write once, reuse. One server for a system serves every agent that needs it, instead of each agent carrying its own copy of the integration.
- Fix once. When the upstream API changes, the server changes. Agents that call it are untouched.
- Portability. The tool layer survives a change of framework. Swapping the agent runtime does not mean rewriting the integrations.
- One place for access control. Authentication, scoping, and audit logging live in the server. The agent never holds the credential for the underlying system.
That last point is the one that matters most in production. An agent with a scoped MCP connection can be given read access to a CRM and no write path at all, and the restriction is enforced by the server rather than by asking the model nicely.
MCP compared with the other integration routes
| Approach | Reuse across agents | Where access control lives | Cost of an upstream API change |
|---|---|---|---|
| Inline integration code | None — copied per agent | In each agent | Every copy edited |
| Platform-specific plugin | Within one platform | In the platform | Wait for the vendor |
| MCP server | Any MCP client | In the server | One server edited |
The table is about coupling, not speed. None of these routes makes an integration correct — they differ in how many places you have to be correct in.
Where MCP does not help
A protocol for tool access solves tool access. It does not solve the failure classes that actually stop agents running unattended. On our own production fleet, none of the recorded scheduled-job failures came from a tool being called wrongly — they came from a model provider revoking access to a free-tier slug mid-flight, from jobs finishing their work with no delivery target configured, and from upstream 500s. MCP would not have caught any of them. Fallback cascades, delivery checks, and an independent verification step would.
It also does not decide control flow. If your workflow needs explicit branching and resumable state, that belongs in the orchestration layer — which is the argument forLangGraph agent development on workflows that genuinely need it, and against it on workflows that do not. The framework question and the tool-protocol question are independent; ourcomparison of CrewAI alternatives covers the first.
How we use MCP
Tool access in the agents we build is MCP-based by default, for the reuse and access-control reasons above rather than as a badge. Practically it means the contracts get written before the prompts: what each tool accepts, what it returns, what it refuses to do, and which calls need a human to approve them. That work is most of the reason a build takes as long as it does — seehow long it takes to build a production AI agentfor the rest of it.
If you are evaluating a vendor, ask to see one of their tool contracts. A schema with required fields, a closed argument set, and a description that states what the tool refuses to do tells you more about how the system will behave in production than any demo.