Model Context Protocol (MCP) is the answer to a problem every AI builder hit in 2024–2025: if you have five AI models and ten data sources, you end up writing fifty custom integrations. MCP defines a single protocol so that any MCP-compatible model talks to any MCP-compatible tool without bespoke glue.
What changed in 2026
- MCP is now the de-facto standard, not an Anthropic experiment. Claude, OpenAI's Assistants API, Cursor, Zed, and VS Code Copilot all support it.
- The spec stabilised at v1.0 with stable transports (stdio and SSE), capability negotiation, and a typed resource model.
- Public MCP server registries emerged. You can browse and install servers for GitHub, Postgres, Stripe, Notion, and hundreds more without writing any code.
- Security guidance matured. OAuth scopes and permission manifests are built into the spec; "any tool can do anything" is no longer the default.
Core concepts
MCP has three primitives every server exposes:
| Primitive |
Description |
Example |
| Resources |
Readable data (URI-addressed) |
file:///repo/src/main.py, db://orders/123 |
| Tools |
Callable functions with typed schemas |
search_docs(query), run_query(sql) |
| Prompts |
Reusable, parameterised prompt templates |
summarise_pr(pr_number) |
The client (your model or IDE) connects to a server, lists available primitives, and calls them via JSON-RPC 2.0.
How the transport works
MCP runs over two transports:
- stdio — server is a subprocess; client writes JSON-RPC to stdin, reads from stdout. Default for local servers.
- SSE (Server-Sent Events) — server runs as an HTTP endpoint; clients connect over the network. Used for hosted/shared servers.
// A tool call from client → server
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "search_docs",
"arguments": { "query": "rate limiting" }
}
}
The server responds with a result object (text, image, or embedded resource). That is the entire protocol at its core.
Writing a minimal MCP server
from mcp.server import Server
from mcp.server.stdio import stdio_server
import mcp.types as types
app = Server("my-docs-server")
@app.list_tools()
async def list_tools() -> list[types.Tool]:
return [
types.Tool(
name="search_docs",
description="Search project documentation",
inputSchema={
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
)
]
@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
if name == "search_docs":
results = do_search(arguments["query"])
return [types.TextContent(type="text", text=results)]
if __name__ == "__main__":
import asyncio
asyncio.run(stdio_server(app))
Any MCP-compatible client can now discover and call search_docs — no custom integration per model.
How to pick between MCP tools and raw function calling
| Concern |
MCP tool |
Raw function call |
| Portability across models |
Yes |
No (per-provider schema) |
| Discovery at runtime |
Yes |
No (hard-coded) |
| Hosting as a shared service |
Yes (SSE) |
No |
| Simplest for a single-model app |
Overkill |
Better |
| Ecosystem of ready-made servers |
Growing fast |
Sparse |
How to start
- Install the MCP SDK —
pip install mcp (Python) or npm install @modelcontextprotocol/sdk.
- Check the registry first — the tool you need (GitHub, Postgres, Slack) likely has a server already.
- Write your own server only for internal or proprietary data sources.
- Configure your client (Claude Desktop, Cursor, VS Code) to point at the server — usually a one-line config entry.
Common mistakes
Exposing too many tools at once. The model context fills with tool schemas. Expose only what the current session needs.
No input validation in the server. MCP does not enforce schemas end-to-end. Validate arguments in your handler before touching production systems.
Running with elevated permissions by default. Scope your server's permissions to the minimum required. Treat MCP servers like microservices, not root shells.
Forgetting transport selection. stdio is fine for local development; SSE is required for multi-user or hosted deployments.
What to skip
- Building your own protocol for model-tool communication. MCP is stable and widely adopted — inventing a bespoke solution adds maintenance with no benefit.
- Wrapping every internal API as an MCP server on day one. Start with the highest-value integration and learn the dev loop before scaling out.
FAQ
Is MCP only for Anthropic models?
No. The spec is open. OpenAI, Gemini wrappers, and open-source models via ollama all have MCP client support in 2026.
How is MCP different from OpenAI function calling?
Function calling is model-specific and defined inline in the API call. MCP is a separate, model-agnostic protocol with discovery, versioning, and shared hosting.
Can an MCP server have side effects?
Yes — tools can write, not just read. That is the point. Treat them with the same caution as any API with write access.
Is MCP production-ready?
Yes. v1.0 is stable and deployed in major commercial products. Check server maturity individually — the spec is solid, some community servers are not.
Where to go next