MCPs Are the New Glue Code
MCPs Are the New Glue Code
The Model Context Protocol buys you a socket, not a clean integration. The hard part was never the wire format.
The first time I wired an MCP server into an agent it felt like a revelation. A schema, a transport, and suddenly the model could call real tools with real data. No brittle string parsing, no ad-hoc function dispatch, no one-off API wrappers. Just a clean boundary.
That feeling lasts until the second integration.
MCP is a real step forward. Standardizing how an agent discovers and invokes tools removes a class of wiring mistakes. But it does not remove the class of problems we have been solving for decades under names like ETL, middleware, adapters, and integration glue. It just gives those problems a new shape.
The first integration is always clean
The canonical MCP demo is a weather tool. The server exposes a single function, get_forecast, with a few typed parameters. The agent calls it, receives structured data, and synthesizes a human answer. It is the perfect onboarding experience.
{
"name": "get_forecast",
"description": "Get the weather forecast for a location",
"parameters": {
"type": "object",
"properties": {
"location": { "type": "string" },
"days": { "type": "number" }
},
"required": ["location"]
}
}
The schema tells the whole story. The implementation is a thin wrapper around a weather API. The model learns the signature in one prompt and rarely hallucinates the arguments. This is the protocol at its best.
But the weather tool is not the median production integration. The median integration has pagination, rate limits, OAuth refresh, deprecated fields, regional endpoints, and a changelog that moves faster than your sprints. MCP makes the discovery of that integration standard. It does not make the integration simple.
The three comfortable lies
Every new integration protocol arrives with a set of promises that are technically true and operationally misleading. With MCP I keep hearing three of them.
1. "It is schema-driven, so the model will use it correctly"
A schema is a contract, not a guarantee. The model can still invent enum values, misinterpret units, pass a 2026-08-10 where a timestamp is expected, or decide that limit means something slightly different from what the server expects. Schemas reduce errors; they do not eliminate the need for validation, examples, and runtime guards at the boundary.
2. "The server is stateless, so scaling is easy"
The transport may be stateless, but the underlying systems rarely are. Sessions, cursor tokens, job IDs, and partial results leak through every real integration. You end up carrying opaque state across calls and explaining it to the model, or worse, hiding it in the adapter and hoping the conversation context is enough.
3. "Auth is just a token in the config"
For the demo, yes. In production, auth is refresh tokens, token rotation, scoped credentials, impersonation, audit trails, and the moment an operator asks why the agent deleted a record it should only have read. The protocol exposes where the token goes; it does not design your permission model.
retry_policy object as a parameter, the protocol has become a facade over a much older problem.
How it becomes glue
The warning signs are the same ones that showed up in SOAP, REST, GraphQL, and every custom RPC layer before them:
| Signal | The hidden glue |
|---|---|
A parameter named options or context keeps growing |
The model is ferrying state the server cannot express cleanly. |
| You write a client-side cache for a "simple" tool | The real API is too slow or too expensive to call naively. |
| You maintain a mapping layer between tool names and internal services | The exposed vocabulary no longer matches your domain. |
| You add pre-hooks for validation and post-hooks for cleanup | The boundary is not as clean as the schema suggests. |
| You version tool names instead of schemas | Backward compatibility becomes a naming convention. |
These are not MCP failures. They are integration realities that MCP politely moves from the protocol layer into your application layer.
A real MCP tool, eventually
Here is what the weather tool starts to look like after a few production iterations:
async function salesforce_query(args: {
soql: string;
page_token?: string;
retry_count?: number;
}): Promise<ToolResult> {
const client = await getSalesforceClient(args.soql);
// The model thinks in terms of SQL; Salesforce thinks in cursors and quotas.
const result = await withRetry(() => client.query(args.soql, { pageToken: args.page_token }), {
maxAttempts: args.retry_count ?? 3,
onRateLimit: 'exponential-backoff',
});
// The schema says `records` is an array. It does not say some fields are
// null, deprecated, or returned as strings that look like numbers.
const sanitized = result.records.map(record => normalizeSchema(record, SALESFORCE_FIELD_MAP));
if (result.nextRecordsUrl) {
return {
content: sanitized,
follow_up: {
tool: 'salesforce_query',
args: { ...args, page_token: result.nextRecordsUrl },
},
};
}
return { content: sanitized };
}
The MCP layer is still there. The model still calls a tool by name. But most of the code is now retry logic, schema normalization, cursor management, and domain translation. That is glue code. It is necessary, expensive, and mostly invisible to the agent.
What to do differently
MCP is not a trap; it is a boundary. Boundaries are valuable, but only if you defend them.
- Own the adapter. Do not let the tool's public surface be the same as the external API's surface. Your internal model and the model's vocabulary should drift at different rates.
- Fail explicitly. A tool should return a clear, structured error rather than a stack trace or a vague timeout. The agent cannot retry, escalate, or apologize unless you give it the signal.
- Assume state exists. Design for conversation-scoped context, idempotency keys, and pagination cursors from the first implementation, even when the demo does not need them.
- Test the failure modes. The interesting tests are not whether the happy path returns weather. They are what happens when the rate limit hits, the schema drifts, or the model passes a string where a number belongs.
- Keep the protocol replaceable. Today it is MCP. Tomorrow it may be another protocol. The integration cost lives in the adapter, not in the socket shape.
Conclusion
MCP is the best interface layer we have had for agent-tool integration, and it will probably become the default plumbing for a lot of systems. That is exactly why we should be honest about what it does and what it does not do.
It standardizes discovery and invocation. It does not standardize error semantics, state management, auth, rate limiting, schema evolution, or domain translation. Those problems do not disappear because the wire format is clean. They move one layer up and wait for you there, wearing a slightly different uniform.
Every integration protocol eventually becomes glue code. The question is whether you treat the glue as an afterthought or as a first-class engineering concern.
Diego Vallejo, August 2026