🤖 AI Tools
· 4 min read

MCP Complete Developer Guide — Architecture, Servers, Clients, and Production (2026)


MCP (Model Context Protocol) is the standard for connecting AI applications to external tools and data. This guide covers everything: architecture, building servers, connecting clients, security, and production deployment.

If you’re new to MCP, start with our What is MCP? explainer.

Architecture

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  MCP Host    │     │  MCP Client │     │  MCP Server  │
│  (Claude,    │────▶│  (built into│────▶│  (your code) │
│   Cursor)    │     │   the host) │     │              │
└─────────────┘     └─────────────┘     └─────────────┘


                                        ┌─────────────┐
                                        │  Your tool,  │
                                        │  API, or DB  │
                                        └─────────────┘

Hosts are AI applications that users interact with. Claude Desktop, Cursor, VS Code, and Claude Code are all MCP hosts.

Clients are protocol handlers built into hosts. They manage connections to servers, handle message routing, and enforce security boundaries. One host can connect to multiple servers.

Servers are what you build. They expose capabilities (tools, resources, prompts) to any MCP-compatible host through a standardized interface.

The three primitives

Tools — actions the AI can take

server.tool("send_slack_message", {
  channel: z.string(),
  message: z.string()
}, async ({ channel, message }) => {
  await slack.chat.postMessage({ channel, text: message });
  return { content: [{ type: "text", text: `Sent to ${channel}` }] };
});

The AI decides WHEN to call a tool based on the user’s request. The host shows the user what tool is being called and asks for approval (unless in auto mode).

Resources — data the AI can read

server.resource("user_profile", "user://{userId}", async (uri) => {
  const user = await db.users.findById(uri.params.userId);
  return { contents: [{ uri, mimeType: "application/json", text: JSON.stringify(user) }] };
});

Resources are read-only data sources. The AI can browse and read them but can’t modify them through the resource interface.

Prompts — reusable templates

server.prompt("code_review", { language: z.string(), code: z.string() }, ({ language, code }) => ({
  messages: [{
    role: "user",
    content: `Review this ${language} code for bugs, security issues, and improvements:\n\n${code}`
  }]
}));

Prompts are pre-built templates that users can invoke. They standardize common workflows.

Transport layers

MCP supports two transport mechanisms:

stdio — Server runs as a subprocess. Host communicates via stdin/stdout. Best for local servers.

SSE (Server-Sent Events) — Server runs as an HTTP service. Host connects via HTTP. Best for remote/shared servers.

// stdio transport (local)
const server = new McpServer({ name: "my-server", version: "1.0.0" });
server.connect(new StdioServerTransport());

// SSE transport (remote)
server.connect(new SSEServerTransport("/messages", response));

Building your first MCP server

TypeScript

npm init -y
npm install @modelcontextprotocol/sdk zod
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({ name: "demo-server", version: "1.0.0" });

// Define a tool
server.tool("get_weather", { city: z.string() }, async ({ city }) => {
  const weather = await fetch(`https://wttr.in/${city}?format=j1`).then(r => r.json());
  return { content: [{ type: "text", text: `${city}: ${weather.current_condition[0].temp_C}°C` }] };
});

// Connect via stdio
const transport = new StdioServerTransport();
await server.connect(transport);

Python

pip install mcp
from mcp.server import Server
from mcp.server.stdio import stdio_server

server = Server("demo-server")

@server.tool()
async def get_weather(city: str) -> str:
    """Get current weather for a city."""
    import httpx
    resp = await httpx.AsyncClient().get(f"https://wttr.in/{city}?format=j1")
    data = resp.json()
    return f"{city}: {data['current_condition'][0]['temp_C']}°C"

async def main():
    async with stdio_server() as (read, write):
        await server.run(read, write)

import asyncio
asyncio.run(main())

See our detailed tutorials: Build an MCP Server in TypeScript and Build an MCP Server in Python.

Connecting to hosts

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["/path/to/your/server.js"]
    }
  }
}

Claude Code

claude mcp add my-server node /path/to/server.js

Cursor

Settings → MCP → Add Server → point to your server binary.

Security considerations

MCP servers have access to whatever you give them — databases, APIs, file systems. Security is critical:

  1. Principle of least privilege — Only expose what the AI needs
  2. Input validation — Validate all tool parameters with Zod/Pydantic
  3. Authentication — Use OAuth or API keys for remote servers
  4. Sandboxing — Run servers in containers for isolation
  5. Audit logging — Log every tool call for review

See our MCP Security Risks and MCP Security Checklist guides.

MCP in the ecosystem

MCP is one of three AI protocols gaining adoption:

ProtocolPurposeCreator
MCPAI ↔ Tools (vertical)Anthropic → Linux Foundation
A2AAgent ↔ Agent (horizontal)Google → Linux Foundation
ACPAgent communicationCommunity-driven

Most production systems use MCP for tool access and A2A for multi-agent coordination. See our protocol comparison.

Production checklist

  • Input validation on all tool parameters
  • Error handling with meaningful messages
  • Rate limiting for expensive operations
  • Authentication for remote servers
  • Logging for audit trails
  • Health checks for monitoring
  • Graceful shutdown handling
  • Documentation for each tool/resource

Related: What is MCP? · Build an MCP Server (TypeScript) · MCP Security Risks · MCP vs A2A vs ACP