Introduction
Every AI agent needs tools. Before standardized protocols, every tool integration was a custom hack.
Model Context Protocol (MCP) standardizes how LLMs discover and call external tools. Instead of writing a bespoke integration for each API, you expose tools through a common protocol. The model sees a standard interface. Your backend handles authorization, execution, and error handling.
Think of MCP like OpenAPI for AI agents: one spec, many tools, consistent calling conventions.
Why This Matters
Backend engineers scale systems by standardizing interfaces. REST replaced ad-hoc RPC. OpenAPI replaced tribal knowledge about endpoints. MCP applies the same principle to agent tool access.
Before MCP, connecting an agent to Slack, a database, and a search API meant three different integration patterns, three auth flows, and three error-handling conventions. That does not scale when your tool catalog grows from 3 to 30.
Prerequisites
This article assumes you have read Blog 001 and Blog 002. You should understand LLM inference basics and how RAG provides external knowledge at query time.
The Problem
Custom tool integrations create:
- N×M coupling: N agents times M tools means N×M integration code paths.
- Schema drift: Tool signatures change; agent prompts break silently.
- Inconsistent auth: Each tool handles credentials differently.
- Poor observability: No uniform logging across tool calls.
- Vendor lock-in: Switching agent frameworks means rewriting integrations.
Understanding the Core Concept
MCP defines a client-server model:
| Role | Responsibility |
|---|---|
| MCP Host | The application (IDE, chat UI, agent runtime) that runs the LLM |
| MCP Client | Connects host to one or more MCP servers |
| MCP Server | Exposes tools, resources, and prompts over the protocol |
| Tools | Callable functions with typed input schemas |
| Resources | Readable data (files, records) the model can fetch |
The LLM does not call HTTP endpoints directly. The host translates model tool requests into MCP messages, routes them to the correct server, and returns structured results.
Tools vs resources
Tools are actions: query a database, send a message, create a ticket. Resources are read-only context: file contents, configuration, documentation snippets. Separating reads from writes helps you apply different auth policies.
Discovery
MCP servers advertise available tools with JSON Schema descriptions. The host injects tool definitions into the model context. When the model emits a tool call, the host validates arguments against the schema before execution.
How It Works Internally (High Level)
- Host starts MCP client and connects to configured servers (stdio, HTTP, or SSE transport).
- Client requests
tools/listfrom each server. - Host merges tool catalogs and presents them to the LLM.
- Model generates a tool call with name and arguments.
- Host validates, routes to the correct MCP server via
tools/call. - Server executes, returns structured content or error.
- Host feeds result back into the conversation for the next model turn.
Step-by-Step Example
Task: Agent looks up a customer's order status.
- MCP server for orders exposes
get_order(order_id: string). - User asks: "Where is order 48291?"
- Model selects
get_orderwithorder_id: "48291". - Host validates schema, calls MCP server.
- Server queries internal API, returns
{"status": "shipped", "eta": "2026-07-08"}. - Model summarizes for the user.
If the server returns an error, the host should surface it to the model so it can retry or escalate.
Architecture
Standardize the interface layer first. Then scale the number of tools.
Python Example
Illustrative MCP-style tool registry pattern. Production MCP servers use the official SDK.
"""
Illustrative tool registry pattern (MCP-style).
Production: use the official MCP Python SDK.
"""
from dataclasses import dataclass
from typing import Any, Callable
import json
@dataclass
class Tool:
name: str
description: str
parameters: dict
handler: Callable[[dict], Any]
class ToolRegistry:
def __init__(self):
self._tools: dict[str, Tool] = {}
def register(self, tool: Tool) -> None:
self._tools[tool.name] = tool
def list_tools(self) -> list[dict]:
return [
{
"name": t.name,
"description": t.description,
"parameters": t.parameters,
}
for t in self._tools.values()
]
def call(self, name: str, arguments: dict) -> str:
if name not in self._tools:
return json.dumps({"error": f"Unknown tool: {name}"})
try:
result = self._tools[name].handler(arguments)
return json.dumps({"result": result})
except Exception as exc:
return json.dumps({"error": str(exc)})
def get_order_handler(args: dict) -> dict:
order_id = args.get("order_id")
if not order_id:
raise ValueError("order_id required")
return {"order_id": order_id, "status": "shipped", "eta": "2026-07-08"}
registry = ToolRegistry()
registry.register(Tool(
name="get_order",
description="Fetch order status by order ID",
parameters={
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"],
},
handler=get_order_handler,
))
if __name__ == "__main__":
print("Tools:", json.dumps(registry.list_tools(), indent=2))
print(registry.call("get_order", {"order_id": "48291"}))
Wrap handlers with auth checks, rate limits, timeouts, and audit logging.
Real-World Applications
- IDE assistants accessing repositories, linters, and documentation via MCP servers
- Enterprise agents querying internal databases through governed MCP gateways
- Multi-tool agents where Slack, Jira, and search share one protocol layer
- Local-first workflows exposing filesystem and CLI tools to a model host
Performance Considerations
- Cold start: Each MCP server connection adds startup latency. Pool connections in long-running hosts.
- Serialization: Large tool results bloat context. Truncate or summarize before feeding back to the model.
- Concurrency: Parallel tool calls need idempotent handlers and clear ordering semantics.
- Network hops: Remote MCP servers add RTT. Co-locate servers with data when possible.
Common Mistakes
- Exposing destructive tools without confirmation gates.
- Returning raw API responses instead of structured, model-friendly summaries.
- No schema validation before execution.
- Building MCP servers without auth scoped to the requesting user.
- Treating MCP as a replacement for RAG (tools fetch live data; RAG indexes documents).
Interview Questions
Q1: What problem does MCP solve?
A: It standardizes how LLM applications discover and invoke external tools, reducing bespoke integration code.
Q2: How is MCP similar to OpenAPI?
A: Both define machine-readable interfaces. OpenAPI describes HTTP APIs; MCP describes tools and resources for LLM hosts.
Q3: What is the difference between an MCP tool and a resource?
A: Tools perform actions with side effects. Resources provide read-only context the model can fetch.
Q4: Who validates tool call arguments?
A: The MCP host validates against the tool schema before invoking the server.
Q5: When would you not use MCP?
A: For a single static integration with no growth in tool count, a direct API wrapper may be simpler.
Q6: How does MCP relate to function calling in chat APIs?
A: Chat APIs define how models emit tool calls. MCP defines how hosts connect to and execute those tools across servers.
MCP Transport and Deployment
MCP supports multiple transports:
| Transport | Use case | Notes |
|---|---|---|
| stdio | Local tools, IDE plugins | Simple, single machine |
| HTTP/SSE | Remote servers | Network auth required |
| Hosted gateway | Enterprise tool bus | Central policy enforcement |
Security model
Treat every MCP server like an internal API:
- Authenticate the host to the server
- Scope tools per user or tenant
- Audit every
tools/callwith arguments and result hash - Rate limit destructive operations
- Never expose raw SQL without read-only roles
Scaling tool catalogs
As tools grow past twenty, add:
-
Namespacing:
billing.get_invoicevscrm.get_invoice - Discovery tiers: Load core tools always; load extended tools on demand
- Schema registry: Version tool definitions; reject calls against stale schemas
MCP vs direct function calling
Provider function calling defines the model-facing schema. MCP standardizes server-side implementation. You can implement MCP servers behind OpenAI-compatible function routes so one tool implementation serves multiple agent hosts.
Extended Example: Multi-Server Host
A coding agent host connects to three MCP servers:
-
Filesystem server (stdio):
read_file,list_dirscoped to workspace root. -
Git server (HTTP):
diff,commitwith OAuth user token. -
Docs server (HTTP):
search_docsbacked by your RAG index.
The host merges tool catalogs at startup. When the model calls search_docs, the host routes to server 3. When it calls read_file, server 1. Auth and rate limits are per server, not global defaults.
Comparison: MCP vs Ad-Hoc Integrations
| Concern | Ad-hoc | MCP |
|---|---|---|
| Tool discovery | Hardcoded in app | Server advertisement |
| Schema versioning | Scattered | Central per server |
| Auth | Per integration | Per server policy |
| Reuse across hosts | Copy-paste | Same server binary |
| Testing | Mock each API | Mock MCP server |
Failure Handling
When tools/call fails:
- Return structured error to model (
timeout,permission_denied,not_found). - Increment failure counter; trip circuit breaker after N failures.
- Do not silently swallow errors; models loop on empty results.
Define idempotency keys for tools that mutate state.
Building Your First MCP Server
Minimal server responsibilities:
- Implement
tools/listreturning name, description, JSON Schema parameters. - Implement
tools/callexecuting the handler and returning text or structured content. - Validate inputs before side effects.
- Return errors as structured JSON, not stack traces to the model.
Start with read-only tools. Add writes after auth and audit paths exist.
Governance Model
Central platform team owns:
- Approved MCP server registry
- Security review checklist per server
- Shared client library in the agent host
Product teams own:
- Domain-specific tool implementations
- Business logic inside handlers
This mirrors API gateway governance for microservices.
Interop with OpenAI Function Calling
Map MCP tool schemas to provider function definitions at the host. When the provider returns a function call, translate to MCP tools/call. One MCP server can back multiple provider formats with a thin adapter layer.
Operations Runbook
Deploy: Version MCP servers independently from agent host. Pin server version in host config.
Rollback: If new tool schema breaks agents, revert server version; host rejects unknown tools gracefully.
Monitor: tools/call rate, error rate, p95 latency per tool, auth failure count.
Incident: On runaway tool loop, circuit-break the server at host level without redeploying the LLM.
Testing MCP Servers
Contract tests per tool:
- Valid args return expected shape
- Invalid args return structured error
- Auth missing returns permission_denied
- Timeout enforced at 30s default
Load test with parallel tools/list and tools/call matching peak agent traffic.
Enterprise Rollout Pattern
Phase 1: Read-only MCP servers (docs, search, metrics). Phase 2: Write tools with approval in staging. Phase 3: Production writes with audit and rate limits. Phase 4: Federated registry where teams publish servers to a central catalog with security sign-off. Skipping phases causes the same incidents as exposing raw admin APIs to junior scripts.
Document each tool with owner, on-call rotation, and deprecation policy. MCP without ownership becomes undeletable legacy surface area.
Reference Appendix: Production FAQ
How do I know this is working in production?
Instrument the layer this article describes before changing models or prompts. Compare p50 and p95 latency, error rate, and task-specific quality scores week over week. AI regressions are subtle: flat aggregate uptime can hide wrong answers.
What is the first config change to try?
Reduce variability before increasing capability. Lower temperature for factual paths, shrink retrieval top-K, tighten context budgets, add output validation. Complexity is not a substitute for measurement.
What belongs in an on-call runbook?
Symptom, dashboard link, rollback lever (model version, feature flag, index snapshot), owner team, and customer communication template. LLM incidents need content rollback, not only service restart.
How do I explain tradeoffs to product managers?
Use dollars and seconds: cost per successful task, p95 time to first token, accuracy on golden set. Avoid debating model intelligence; debate measurable user outcomes and failure tolerance.
When should we retrain, re-index, or rewrite prompts?
Re-index when documents change. Rewrite prompts when behavior spec changes. Retrain or fine-tune when prompt plus RAG cannot meet format or tone requirements after eval iteration. Default order: prompt, RAG, fine-tune.
What is the common rollback path?
Keep previous model version, previous index snapshot, and previous prompt template addressable by version id for at least seven days. Rollback should be one feature flag or deploy revert, not a fire drill.
How does this interact with the rest of the handbook?
This topic is one layer in a stack. Read prerequisites listed in frontmatter. When debugging end-to-end failures, walk the request path from ingress through retrieval, inference, and output validation before concluding the model is wrong.
Summary
MCP is infrastructure for agent tool access. Design a standardized tool interface layer before your integration count explodes. The model sees a uniform catalog. Your backend enforces auth, limits, and observability behind each server.
Further Reading
- Anthropic Model Context Protocol specification
- MCP SDK documentation (Python and TypeScript)
- Blog 004 for agent loops that consume MCP tools
Next in Series
Blog 004: AI Agents Explained: Loops, Guardrails, and Production Harnesses

Top comments (0)