The Complete MCP Server Handbook for Developers (April 2026 Edition)
The Model Context Protocol (MCP) is the USB-C for AI: a single open standard that connects AI applications to tools, data sources, and workflows. Originated by Anthropic in late 2024 and now an open, community-maintained standard, MCP is supported across a wide range of clients (Claude Desktop and Claude Code, ChatGPT, VS Code, Cursor, and others). The specification covers two transports (local stdio and remote Streamable HTTP, which supersedes the older HTTP+SSE transport), server-side tools, resources, and prompts, and an OAuth 2.1-based authorization flow for remote servers. The public server ecosystem is large and growing fast, spanning official Anthropic servers, vendor servers, and community projects.
If you do not already use Claude, you can try Claude free for a week and follow along with every example in this handbook. The guide covers MCP server development end-to-end, from your first server to production deployment with authentication.
TL;DR:
| What you'll learn | Section |
|---|---|
| MCP architecture and how it differs from REST/GraphQL | §1–2 |
| Build your first server in TypeScript | §3 |
| Build your first server in Python | §4 |
| Connect to Claude Desktop and Claude Code | §5–6 |
| OAuth 2.1 security and production auth | §7 |
| Top 20 production MCP servers | §8 |
| MCP for web scraping | §9 |
| Enterprise deployment patterns | §10 |
Prerequisites:
- Node.js 18+ or Python 3.10+
- Claude Desktop or Claude Code installed
- Basic understanding of APIs and JSON
What MCP is (and isn't)
MCP is a JSON-RPC 2.0 protocol that defines how AI hosts (Claude, Cursor, VS Code) communicate with tool servers. It replaces ad-hoc function calling implementations with a standardized contract.
┌─────────────────┐ JSON-RPC ┌─────────────────┐
│ MCP Host │◄────────────────────►│ MCP Server │
│ (Claude, │ tools/list │ (your code) │
│ Cursor, etc.) │ tools/call │ │
│ │ resources/read │ Exposes: │
│ │ prompts/list │ - Tools │
│ │ │ - Resources │
│ │ │ - Prompts │
└─────────────────┘ └─────────────────┘
MCP vs REST vs LangChain tools
| MCP | REST API | LangChain tools | |
|---|---|---|---|
| Discovery | Automatic (tools/list) | Manual (OpenAPI spec) | Hardcoded in code |
| Transport | stdio, Streamable HTTP | HTTP | In-process |
| Auth | OAuth 2.1 (spec-native) | Varies (API keys, JWT) | App-level |
| Multi-model | Same server works with Claude, Cursor, Copilot | Requires per-client integration | LangChain only |
| Ecosystem | Large, fast-growing server catalog | Billions of APIs | Thousands of tools |
| Stateful sessions | Built-in (session tokens) | Stateless by default | Framework-managed |
When to use MCP: You want your tool to work across multiple AI hosts (Claude Desktop, Claude Code, Cursor, VS Code Copilot) without building separate integrations for each.
When to use REST: You need high-throughput, low-latency API access for non-AI clients, or your tool is consumed by traditional web/mobile apps.
The 2026 spec landscape
MCP has matured well beyond simple local tool calling. The areas below matter most when you build a production server. Always confirm the exact shapes against the current official spec for your installed SDK version, since the protocol is actively evolving.
Streamable HTTP transport
Streamable HTTP supersedes the older HTTP+Server-Sent Events (SSE) transport. A single HTTP endpoint handles both request-response and streaming via Server-Sent Events:
POST /mcp → Request (JSON-RPC)
← Response (JSON-RPC or SSE stream)
Advantages over stdio: works across networks, supports Docker/Kubernetes deployments, enables cloud-hosted MCP servers.
Async, long-running operations
Most real MCP work (web scraping, data processing, multi-step jobs) takes longer than a single synchronous response. The common pattern is to accept the request, return quickly with a task or job identifier, and let the client poll or subscribe for completion rather than blocking the connection. A request might look like:
{
"method": "tools/call",
"params": {
"name": "web-scrape",
"arguments": { "url": "https://example.com", "depth": 3 }
}
}
Check the current spec and your SDK for the exact long-running-task and progress-notification APIs, since these have changed over time.
Server-initiated notifications
MCP supports server-to-client notifications, which lets a server tell the client about progress or state changes during a call instead of only replying once at the end. This is what makes streaming progress updates and reactive workflows possible: Claude can react to what the server reports, not just to the initial prompt.
OAuth 2.1 authorization
For remote (HTTP) servers, MCP defines an authorization flow based on OAuth 2.1 with PKCE. A server can require authorization before exposing its tools, and gate sensitive operations behind scoped permissions. Local stdio servers typically rely on the host process and local credentials instead.
Build your first MCP server in TypeScript
A minimal MCP server that exposes a single calculator tool:
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
Create src/index.ts:
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: "calculator",
version: "1.0.0",
description: "A simple calculator MCP server",
});
// Define a tool
server.tool(
"calculate",
"Perform basic arithmetic",
{
expression: z.string().describe("Math expression like '2 + 3 * 4'"),
},
async ({ expression }) => {
// WARNING: eval-style execution is used for simplicity. Never do this in production.
const result = Function(`"use strict"; return (${expression})`)();
return {
content: [{ type: "text", text: `Result: ${result}` }],
};
}
);
// Define a resource
server.resource(
"help",
"calculator://help",
async (uri) => ({
contents: [{
uri: uri.href,
mimeType: "text/plain",
text: "Supported operations: +, -, *, /, **, %, ()",
}],
})
);
// Start the server
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Calculator MCP server running on stdio");
Build and test:
# Recommended: use a tsconfig.json for multi-file projects
# npx tsc (with tsconfig.json in root)
# Or for quick single-file compile:
npx tsc src/index.ts --outDir dist --esModuleInterop --moduleResolution node
node dist/index.js
Expected output:
Calculator MCP server running on stdio
For a Streamable HTTP transport version (production deployments):
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";
const app = express();
app.use(express.json());
app.post("/mcp", async (req, res) => {
const transport = new StreamableHTTPServerTransport("/mcp");
await server.connect(transport);
await transport.handleRequest(req, res);
});
app.listen(3001, () => {
console.log("MCP server listening on http://localhost:3001/mcp");
});
Production note: The snippet above is illustrative only. Real Streamable HTTP deployments need a GET handler for optional SSE streams, session IDs (e.g.
MCP-Session-Id),Accept/ protocol version headers, andOriginvalidation per the current MCP transport spec. Match your code to the TypeScript SDK examples for your installed SDK version.
For the complete TypeScript walkthrough, see How to Build an MCP Server in TypeScript.
Build your first MCP server in Python
pip install mcp
Create server.py:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather", description="Weather data server")
@mcp.tool()
async def get_weather(city: str) -> str:
"""Get current weather for a city.
Args:
city: City name (e.g., 'London', 'Tokyo')
"""
# Replace with real API call in production
return f"Weather in {city}: 22°C, partly cloudy"
@mcp.resource("weather://cities")
async def list_cities() -> str:
"""List supported cities."""
return "London, Tokyo, New York, Berlin, Sydney"
if __name__ == "__main__":
mcp.run(transport="stdio")
Run:
python server.py
For HTTP transport:
python server.py --transport streamable-http --port 3001
Connect to Claude Desktop
Edit claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"calculator": {
"command": "node",
"args": ["/path/to/dist/index.js"]
},
"weather": {
"command": "python",
"args": ["/path/to/server.py"]
}
}
}
Restart Claude Desktop after every config change. Verify servers loaded by clicking the tools icon in the chat input. Your tools should appear there.
Connect to Claude Code
Claude Code loads MCP servers from its global config or project-level .mcp.json:
# Add a server globally
claude mcp add calculator -- node /path/to/dist/index.js
# Or add to project .mcp.json
cat > .mcp.json << 'EOF'
{
"mcpServers": {
"calculator": {
"command": "node",
"args": ["./dist/index.js"]
}
}
}
EOF
Then use it in a Claude Code session:
> Use the calculator tool to compute 2^10 + 15 * 3
Security deep dive: OAuth 2.1, Server-Side Request Forgery (SSRF) prevention, and least privilege
OAuth 2.1 authentication
The MCP spec includes a native auth flow. Server implementation with TypeScript SDK:
// ILLUSTRATIVE ONLY. The OAuth constructor options and requiredScopes
// parameter shown here are not part of the stable @modelcontextprotocol/sdk
// API as of this writing. Verify against the current SDK source at
// https://github.com/modelcontextprotocol/typescript-sdk before using in production.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const server = new McpServer({
name: "secure-server",
version: "1.0.0",
auth: {
type: "oauth2",
authorizationUrl: "https://auth.example.com/authorize",
tokenUrl: "https://auth.example.com/token",
scopes: ["read:data", "write:data"],
pkce: true, // Required by OAuth 2.1
},
});
// Tools can require specific scopes
server.tool(
"read-data",
"Read sensitive data",
{ query: z.string() },
async ({ query }, { auth }) => {
// auth.scopes contains granted scopes
if (!auth?.scopes.includes("read:data")) {
throw new Error("Insufficient permissions");
}
// ... handle request
},
{ requiredScopes: ["read:data"] }
);
SSRF prevention
MCP servers that accept URLs from AI clients must validate inputs:
function isAllowedUrl(url: string): boolean {
const parsed = new URL(url);
// Block internal networks
const blocked = ["localhost", "127.0.0.1", "0.0.0.0", "169.254.169.254"];
if (blocked.includes(parsed.hostname)) return false;
// Block private IP ranges
if (parsed.hostname.match(/^(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)/)) return false;
// Allow only HTTPS
if (parsed.protocol !== "https:") return false;
return true;
}
Least-privilege scoping
Production MCP servers should expose the minimum viable toolset:
| Principle | Implementation |
|---|---|
| Read-only by default | Separate read and write tools; require explicit opt-in for mutations |
| Scoped permissions | Use OAuth scopes to gate destructive operations |
| Rate limiting | Implement per-session rate limits to prevent runaway agent loops |
| Audit logging | Log every tool call with timestamps, inputs, and outputs |
| Input validation | Validate all parameters with Zod/Pydantic before processing |
Top 20 production MCP servers
Curated from production deployments. Sources: MCP registry, GitHub, vendor documentation.
Web Data
| Server | Maintainer | What it does | Install |
|---|---|---|---|
| Apify | Apify | 30,000+ web scraping Actors | npx -y @apify/actors-mcp-server |
| Firecrawl | Firecrawl | URL → Markdown conversion | npx -y firecrawl-mcp |
| Bright Data | Bright Data | Anti-bot web scraping | npx -y @brightdata/mcp |
| Brave Search | Brave | Web search with AI summaries | npx -y @modelcontextprotocol/server-brave-search |
| Jina Reader | Jina AI | URL → clean text | npx -y mcp-jinaai-reader, or hosted https://mcp.jina.ai/sse (Jina MCP) |
Developer Productivity
| Server | Maintainer | What it does | Install |
|---|---|---|---|
| GitHub | Anthropic (official) | Repos, issues, PRs, files | npx -y @modelcontextprotocol/server-github |
| Filesystem | Anthropic (official) | Local file read/write/search | npx -y @modelcontextprotocol/server-filesystem |
| PostgreSQL | Anthropic (official) | Database queries | npx -y @modelcontextprotocol/server-postgres |
| SQLite | Anthropic (official) | Embedded database | npx -y @modelcontextprotocol/server-sqlite |
| Git | Anthropic (official) | Git operations | npx -y @modelcontextprotocol/server-git |
Communication
| Server | Maintainer | What it does | Install |
|---|---|---|---|
| Slack | Anthropic (official) | Channels, messages, search | npx -y @modelcontextprotocol/server-slack |
| Gmail | Community | Email read/write | npx -y @gongrzhe/server-gmail-autoauth-mcp (OAuth; run package auth flow per README) |
| Google Drive | Community | File management | npx -y @piotr-agier/google-drive-mcp (set GOOGLE_DRIVE_OAUTH_CREDENTIALS; see npm README) |
Business & CRM
| Server | Maintainer | What it does | Install |
|---|---|---|---|
| HubSpot | HubSpot (official) | CRM contacts, deals, companies | npx -y @hubspot/mcp-server |
| Notion | Notion (official npm) | Pages, databases, wikis | npx -y @notionhq/notion-mcp-server, or remote https://mcp.notion.com/mcp in clients that support HTTP MCP |
| Google Sheets | Community | Spreadsheet read/write | npx -y mcp-gsheets@latest (needs GOOGLE_PROJECT_ID + GOOGLE_APPLICATION_CREDENTIALS) |
| Stripe | Stripe (official) | Payments, customers, invoices | npx -y @stripe/mcp -- --api-key=sk_live_... (see Stripe MCP docs) |
Orchestration
| Server | Maintainer | What it does | Install |
|---|---|---|---|
| Puppeteer | Anthropic (official) | Browser automation | npx -y @modelcontextprotocol/server-puppeteer |
| n8n | Community ecosystem | Expose n8n to MCP clients | npx -y n8n-mcp (verify README for env vars; not the same as the self-hosted n8n UI) |
| Make.com | Make | Visual automation | Via Make MCP connector |
For web-scraping-specific MCP servers, see MCP Servers for Web Scraping. For business-focused servers, see Top 10 MCP Servers for Marketing and Business.
MCP for web scraping
MCP servers transform AI assistants into autonomous web scrapers. Three approaches:
Approach 1: Apify MCP (structured extraction from 30,000+ Actors)
{
"mcpServers": {
"apify": {
"command": "npx",
"args": ["-y", "@apify/actors-mcp-server"],
"env": { "APIFY_TOKEN": "your_token" }
}
}
}
Then ask Claude: "Use Apify to scrape the top 50 coffee shops from Google Maps in Austin, TX and return as a table."
Approach 2: Firecrawl MCP (URL → Markdown for any page)
{
"mcpServers": {
"firecrawl": {
"command": "npx",
"args": ["-y", "firecrawl-mcp"],
"env": { "FIRECRAWL_API_KEY": "your_key" }
}
}
}
Then ask Claude: "Use Firecrawl to read the pricing page at https://competitor.com/pricing and summarize the plans."
Approach 3: Bright Data MCP (anti-bot bypass for protected sites)
{
"mcpServers": {
"brightdata": {
"command": "npx",
"args": ["-y", "@brightdata/mcp"],
"env": {
"API_TOKEN": "your_token",
"WEB_UNLOCKER_ZONE": "your_zone"
}
}
}
}
For detailed comparisons, see AI Agent Web Tools Comparison 2026 and Apify MCP Server Setup.
Enterprise deployment patterns
Multi-agent coordination
MCP enables agent-to-agent communication where one agent's output becomes another's input:
┌──────────────┐ MCP ┌──────────────┐ MCP ┌──────────────┐
│ Research │────────────►│ Analysis │────────────►│ Report │
│ Agent │ │ Agent │ │ Agent │
│ (Apify MCP) │ │ (DB MCP) │ │ (Slack MCP) │
└──────────────┘ └──────────────┘ └──────────────┘
Production checklist
| Concern | Solution |
|---|---|
| High availability | Deploy MCP servers behind a load balancer with health checks |
| Observability | Structured logging for every tool call; export to Datadog/Grafana |
| Secret management | Use Vault or cloud secret managers; never env vars in config files |
| Version pinning | Pin MCP SDK versions; test upgrades in staging |
| Rate limiting | Implement per-client quotas to prevent runaway agent loops |
| Network isolation | Run MCP servers in private VPCs; whitelist outbound domains |
Common mistakes
| Mistake | Why it's bad | Fix |
|---|---|---|
| Exposing write APIs without auth | Any AI client can mutate your data | Start read-only; add OAuth 2.1 for write operations |
| Missing SSRF protection | AI can be tricked into hitting internal services | Validate and allowlist all URLs |
| Loading 10+ MCP servers | Context pollution; Claude gets confused about which tool to use | Limit to 4–5 active servers; use claude mcp list (Claude Code) and the MCP server directory to pick tools deliberately |
| Not restarting after config changes | Claude Desktop loads MCP configs at startup only | Always restart after editing claude_desktop_config.json |
| Hardcoding API keys in config | Security risk in shared repos | Use environment variables or secret managers |
| Blocking operations in tool handlers | Hangs the MCP connection; client times out | Use async operations; return task IDs for long-running work |
MCP is an open standard, originated by Anthropic in late 2024 and now community-maintained, that defines how AI applications (like Claude, ChatGPT, Cursor, and VS Code) communicate with external tools and data sources. Think of it as USB-C for AI: one protocol that connects any compatible AI model to any tool, replacing custom one-off integrations.
The public ecosystem is large and growing quickly, spanning official Anthropic servers (GitHub, Filesystem, PostgreSQL), vendor servers (Apify, Firecrawl, Stripe, HubSpot), and many community-built servers. Rather than chasing a headcount, browse the registry and directory at modelcontextprotocol.io to find current, maintained servers for your use case.
Yes. MCP is model-agnostic. ChatGPT, Cursor, VS Code, and other AI tools support MCP. The protocol is standardized, so any server works with any compatible client. Tool-calling quality does vary by model: current frontier models (for example Claude Sonnet 4.6 and Claude Opus 4.7) tend to handle multi-tool MCP setups most reliably.
The MCP specification includes OAuth 2.1 with PKCE for authentication, scoped tool permissions, and session management. The protocol itself is production-ready. Security depends on implementation: validate inputs, prevent SSRF, use least-privilege scoping, and audit every tool call.
Function calling is model-specific (OpenAI functions, Claude tool use, Gemini function declarations). MCP is a protocol that sits between the model and the tool, providing standardized discovery, invocation, authentication, and streaming. One MCP server serves all compatible AI clients.
Use stdio for local development and Claude Desktop (the simplest setup, where the server runs as a local subprocess). Use Streamable HTTP for production deployments where the MCP server runs on a remote machine, in Docker, or needs to serve multiple clients simultaneously.
Yes. The standard async pattern is: the server accepts the request, returns quickly with a task or job ID, and the client polls or subscribes for completion instead of blocking. This is essential for web scraping, data processing, and any operation that takes more than a few seconds. Check the current spec and your SDK for the exact long-running-task API.
Apify MCP for structured extraction from specific platforms (Google Maps, Amazon, LinkedIn). Firecrawl MCP for converting any URL to clean Markdown. Bright Data MCP for sites with heavy anti-bot protection. See our MCP servers for web scraping guide for detailed comparisons.
Check the MCP logs at ~/Library/Logs/Claude/mcp-*.log (macOS). Common issues: wrong command path, missing environment variables, port conflicts for HTTP servers, and forgetting to restart Claude Desktop after config changes.
Yes. MCP is an open standard with open-source SDKs, and many vendors (Apify, Firecrawl, Stripe, HubSpot) already ship commercial MCP servers. The protocol is designed for ecosystem growth, so building and distributing your own MCP servers is encouraged. Check the license of each SDK and reference server you build on.
MCP is the infrastructure layer that makes AI agents useful beyond chat. The protocol is mature (OAuth 2.1, Streamable HTTP, async job patterns), the ecosystem is deep (official, vendor, and community servers), and it is an open standard with broad client support. Build your first server today, connect it to Claude, and start giving your AI tools access to real data and real systems.
For web scraping MCP servers, browse the Apify Store and connect via @apify/actors-mcp-server. For URL-to-Markdown conversion, get a Firecrawl API key. For visual automation orchestration, sign up on Make.com.
