MCP and the Tool-Protocol Wars
MCP is useful when it makes tool boundaries explicit. The real tool-protocol decision is how you preserve authority, schemas, observability, and change control.
The tool-protocol debate is often framed as a contest for the connector layer: which client can talk to which service, and through whose registry. That framing is too small for production agents. A tool protocol is also a contract for what an agent is allowed to attempt, how the result is represented, who can change the contract, and what evidence survives after the call.
MCP has made this conversation concrete. It gives clients and servers a common shape for discovering capabilities and invoking tools. That can remove bespoke integration work. But adopting a common protocol does not make a tool safe, stable, or understandable to an agent. Those are harness responsibilities.
The practical takeaway: adopt MCP or another protocol for portability when it earns its keep, but keep authority, schemas, versioning, and verification under your control. The winning protocol is not the one with the largest catalog. It is the one that lets a task complete correctly after the catalog changes.
A protocol is not a tool design
A protocol can say that a server exposes a create_invoice operation. It cannot decide whether that operation is too broad, whether its fields are unambiguous, or whether the caller has authority to use it. Those are choices made by the tool owner and enforced by the harness.
This distinction matters because agents act on the surface they can see. A broad capability discovered at runtime can become an accidental permission grant. A vague description can invite invented arguments. A response that mixes a human summary with an opaque error can be hard to route or retry.
The durable unit of design remains a narrow, testable operation:
{
"name": "create_draft_invoice",
"input": {
"customer_id": "cus_123",
"line_items": [{"sku": "support-annual", "quantity": 1}],
"currency": "USD"
},
"effect": "creates a reviewable draft; cannot charge a customer"
}
The important property is not whether this arrives through MCP, an SDK, or an internal RPC endpoint. It is that the effect is named, bounded, and independently verifiable. The tool design rules still apply at the protocol boundary: make tools narrow, make inputs explicit, and return results that help the next decision.
Interoperability moves the boundary; it does not remove it
The promise of a shared protocol is real: a client can connect to a new server without a custom adapter for every pair. But the integration work moves into configuration, trust, identity, policy, and lifecycle management.
Before connecting a server, answer four questions:
| Question | Operational consequence |
|---|---|
| Who operates it? | Determines who can change behavior or inspect data |
| What data crosses the boundary? | Determines what credentials, redaction, and retention rules apply |
| What side effects can it cause? | Determines permission tiers and approval gates |
| How is it updated or removed? | Determines whether runs can be reproduced and incidents contained |
Treat a server as a dependency with a blast radius, not as a menu of conveniences. Discovery is useful for an exploratory interface; it is risky as the only source of truth for a production workflow. A curated allowlist of server identities and tool names gives the harness a stable control point. It also makes review possible when a server adds a new operation that sounds adjacent to an approved one but has a larger effect.
This is the same principle behind guardrails, budgets, and kill switches: constraints must live outside the model. A model may select a discovered tool. It should not be the system that decides whether the tool was authorized to exist in this run.
The protocol war is mostly a change-management war
The visible competition is often about transport, discovery, and developer ergonomics. The production failure usually comes later: an argument changes meaning, a server alters a response shape, an authentication scope expands, or a deprecated tool remains in a model’s learned path.
Pin the things that affect behavior. At minimum, record the server identity, tool name, schema or contract version, policy version, and client configuration with each consequential call. For workflows that must be reproducible, keep a checked-in manifest rather than resolving the entire tool surface dynamically at runtime.
tools:
crm.lookup_account:
server: crm.internal.example
contract: "2026-08-15"
permissions: ["accounts:read"]
billing.create_draft_invoice:
server: billing.internal.example
contract: "2026-08-15"
permissions: ["billing:draft_write"]
This is not an argument against evolution. It is a way to make evolution testable. A new server release should enter a staging path, run against representative tasks, and produce a diff of calls, outputs, errors, and verified outcomes. That resembles a model-swap drill: the component may improve in isolation, but the harness needs evidence that the whole task still works.
Schemas are necessary, but semantics still leak
An input schema can prove that limit is an integer. It cannot prove whether it means “maximum records returned,” “maximum dollars spent,” or “maximum days searched.” The latter meaning belongs in a stable tool contract with examples, defaults, and explicit units.
For agent-facing tools, document at least:
- Preconditions and authority required.
- Exact side effect and idempotency behavior.
- Input units, defaults, and mutually exclusive fields.
- Result states: success, no result, retryable error, permanent error, and unknown outcome.
- How to verify the claimed effect.
The last item is often omitted. A tool that replies {"ok": true} leaves the agent with an assertion, not proof. Prefer a response with a durable reference and enough state to verify it:
{
"status": "created",
"invoice_id": "inv_764",
"state": "draft",
"idempotency_key": "task-832:invoice",
"verification": {"tool": "billing.get_invoice", "invoice_id": "inv_764"}
}
That response supports a verifier, an audit record, and a safe retry. It also makes the difference between a protocol-level success and a business-level completion visible. Measuring that difference is central to cost per completed task, where a cheap call that needs human repair is not a cheap outcome.
Capability discovery needs a trust model
Tool descriptions are instructions supplied by another system. If a server can influence the text an agent sees, it can influence the agent’s choices. That does not make discovery unusable; it means descriptions should be treated as untrusted input until they pass the same controls as other external content.
A practical posture is layered:
- Authenticate the server and scope its credentials to the smallest useful access.
- Allowlist tools for each workflow; do not grant a new side-effecting tool merely because it appears.
- Separate read-only discovery from execution permissions.
- Route high-impact operations through a policy check or human approval.
- Log tool metadata and the exact request/response references used in the run.
The aim is not to build an impossibly sterile tool ecosystem. It is to preserve a clear line between content that can advise an agent and a policy that can authorize one. The human escalation pattern is useful here: when authority or evidence is missing, the harness should enter a controlled state rather than converting ambiguity into a side effect.
Choose based on the work, not the flag
There are sensible reasons to use MCP: common integration mechanics, ecosystem reach, and a clean separation between a client and independently operated tools. There are equally sensible reasons to use a narrow internal API: a critical workflow may need a smaller surface, tighter release control, and an ownership model your team already understands.
The choice should follow the task:
| Workload | Useful default |
|---|---|
| Prototyping with read-only data | Discovery can be broad, with isolated credentials |
| Repeated production workflow | Curated manifest, pinned contracts, explicit verification |
| High-impact side effect | Minimal purpose-built tool plus policy gate and idempotency |
| Multi-team platform | Shared protocol with ownership, deprecation, and audit rules |
Avoid making protocol adoption a proxy for agent maturity. An agent with many interoperable tools but no verifier is simply able to fail in more places. Observability should show the selected tool, contract version, latency, error class, and verified outcome—not only a transcript of what the model said. That is how a tool layer becomes debuggable rather than magical.
Takeaway
MCP is valuable because it makes integration less bespoke. The larger problem is governing the capability surface it exposes. Keep tools narrow, pin the contracts that matter, treat discovered metadata as untrusted until authorized, and require evidence of effects. Protocols can make agents more portable. Only a disciplined harness makes them dependable.