What is MCP?
Operations, versioning, and tradeoffs
Production MCP integrations need explicit failure handling, compatibility testing, observability, and a reasoned choice between a standard server boundary and a direct API.
Before you start
Why this matters
A ticket tool times out after the user confirms “Create.” The host does not know whether the ticket exists. If it retries blindly, it may create a duplicate. If it reports failure, the user may create another ticket manually. If it reports success, it may be lying.
The plug analogy is least helpful at this moment. Production reliability depends on the semantics of the underlying operation, not only on whether the protocol message was well formed.
1Learn the idea
Read
Classify failures by layer
An MCP workflow can fail at several layers:
- Configuration: executable missing, endpoint wrong, or required setting absent.
- Transport: process exits, network drops, framing breaks, or request times out.
- Protocol: initialization is incompatible, a method is unsupported, or a message is invalid.
- Capability: tool name disappeared, arguments fail validation, or a resource is unavailable.
- Authorization: the current identity lacks permission or a token has expired.
- Domain: the downstream API rejects a project, document, or state transition.
- Outcome: the operation may have succeeded, but its response was lost.
These failures should not collapse into one generic exception. A user can fix expired authorization, an operator can fix configuration, and application logic can change invalid arguments. An unknown write outcome needs reconciliation, not a cheerful retry.
Errors should be useful without exposing secrets, internal stack traces, or restricted resource names. Logs can hold diagnostic identifiers under access controls while the interface gives the person a safe, actionable explanation.
Read
Retry according to operation semantics
Retries are a policy decision. Read-only search is often safe to retry with backoff, though it can still consume quota. A write may be safe only if the operation supports an idempotency key or the application can query for the original result.
For each tool, document:
- whether it has side effects;
- whether repeating it produces the same outcome;
- what identifier can deduplicate attempts;
- how to check an unknown outcome;
- when a person must decide.
Timeout does not mean failure. It means the caller stopped waiting. The server or downstream provider may still be working. Design the recovery path before exposing the tool.
Cancellation also needs honest semantics. A client can stop caring about a result without necessarily undoing a downstream action. “Cancel requested” is safer wording than “Canceled” until the executing system confirms it.
Read
Observe the full operation
Useful telemetry connects host intent to downstream outcome. Record a trace or correlation identifier, server identity, capability name, timing, result category, retry count, and approval event. Redact credentials and sensitive arguments, and avoid storing full model context or tool output by default.
Measure connection success, initialization latency, invocation latency, timeout rate, authorization denials, validation failures, server restarts, and unknown outcomes. For actions, also measure duplicate prevention and reconciliation success.
Health checks should not claim that every tool works merely because a process is alive. A server can initialize while its downstream API is unavailable. Use bounded checks that reflect dependencies without creating side effects.
Set alerts by consequence. One failed public-data search is different from one ambiguous production deployment. Operational safety follows impact, not just error percentage.
Read
Expect capability and version change
MCP evolves, SDKs change, servers add capabilities, and downstream APIs change independently. Initialization and capability negotiation help participants find a compatible operating set, but they do not remove the need for tests.
Pin dependencies according to your release practice, read current migration guidance, and test the client against supported server versions. Do not build by copying raw message envelopes from an old blog post. Maintained SDK types can reduce accidental incompatibility, while protocol-level tests can verify the behavior that matters to your product.
Treat descriptor changes as product changes. Renaming a tool, tightening an input schema, or changing result structure can alter model selection and host rendering. Adding a dangerous tool should never make it automatically available just because discovery finds it.
Version the domain contract where necessary and prefer additive evolution when possible. If behavior must break, provide a migration window or a clear incompatibility error rather than silently changing the meaning of an existing operation.
Read
MCP versus a direct API
A direct API integration can be the right choice. If one application needs one stable provider, direct code may be simpler, easier to optimize, and able to use provider-specific features immediately. It avoids running or operating another server boundary.
MCP becomes attractive when the same capability should be reusable across compatible hosts, when a host needs a portfolio of integrations, when runtime discovery is valuable, or when an organization wants a consistent adapter boundary around varied services.
Compare total cost:
- adapter development and duplication;
- authentication and authorization integration;
- server deployment or local process management;
- protocol and SDK upgrades;
- observability and support;
- provider-specific feature access;
- portability and ecosystem reuse.
An MCP server frequently calls a direct API internally. The decision is where to place the reusable boundary, not whether APIs disappear.
Read
Avoid overpromising portability
A server that follows the protocol may still depend on host-specific user experiences, authentication extensions, deployment assumptions, or optional capabilities. “Works everywhere” requires testing, not branding.
Likewise, tool descriptions that perform well with one model may select poorly with another. Protocol interoperability ensures recognizable communication; it does not guarantee identical model behavior, latency, interface rendering, or approval controls.
Define a compatibility matrix for the clients, server versions, transports, and capabilities you support. Test the narrow combinations you promise. Gracefully hide unsupported features and state prerequisites clearly.
Portable design favors narrow, well-described capabilities, stable schemas, explicit errors, standard content forms, and minimal assumptions about host UI. Product-specific enhancements can exist, but users should know which parts are standard and which are not.
Read
Build a safe operating envelope
Before launch, inventory every capability and assign an owner, data classification, side-effect level, authorization rule, consent rule, timeout policy, retry policy, and rollback or reconciliation path. Test the server with malformed model arguments and unavailable dependencies.
Set limits on concurrency, argument size, result size, and execution time. Provide a kill switch or capability disablement path in the host. If a server behaves unexpectedly, removing it from model exposure should not require an emergency application release.
Run failure exercises: disconnect during a read, expire a token, change a schema, return hostile content, and lose the response after a write. Verify that the system fails honestly, preserves evidence, and gives operators a path to recovery.
Operational maturity is not separate from MCP design. A standard connection can increase reuse, which also increases the blast radius of a flawed server. Shared components deserve stronger ownership, testing, and change control.
Continue learning · glossary & guides
- Is every timeout safe to retry? No. Retry depends on side effects and idempotency.
- Does protocol compatibility guarantee identical behavior across hosts? No. Optional features, policy, UI, and models differ.
- When may a direct API be better? When a narrow one-app integration benefits more from simplicity than portability.