What is the Model Context Protocol?
The Model Context Protocol (MCP) is an open standard introduced by Anthropic that provides a universal way to connect AI assistants with external systems. MCP creates a standardized interface between AI models and the tools, databases, and services they need to access.
MCP was donated to the Linux Foundation's Agentic AI Foundation, establishing it as an industry-wide standard adopted by OpenAI, Google DeepMind, and Microsoft.
Why MCP Matters
Before MCP, every AI integration required custom code:
- Each AI provider had different tool-calling formats
- Developers built one-off integrations for each service
- Context sharing between tools was inconsistent
- Security models varied across implementations
MCP solves these problems with a unified protocol that works across AI providers and tools.
Core Architecture
MCP follows a client-server architecture:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Claude │ │ MCP Server │ │ External │
│ Desktop │────▶│ (Your Code) │────▶│ Service │
│ (MCP Client) │◀────│ │◀────│ (API/DB) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
Components:
- MCP Client: Claude Desktop, Claude Code, or any MCP-compatible AI application
- MCP Server: Your integration code that exposes tools and resources
- Transport Layer: Communication channel (stdio, HTTP/SSE, WebSocket)
Setting Up MCP in Claude Desktop
Prerequisites
- Claude Desktop application (macOS or Windows)
- Node.js 18+ or Python 3.10+
- Basic understanding of JSON and async programming
Configuration File Location
Claude Desktop reads MCP configuration from:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
Windows:
%APPDATA%\Claude\claude_desktop_config.json
Basic Configuration Structure
{
"mcpServers": {
"server-name": {
"command": "node",
"args": ["/path/to/your/server.js"],
"env": {
"API_KEY": "your-api-key"
}
}
}
}
Building Your First MCP Server
Project Setup (TypeScript)
mkdir my-mcp-server
cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src/**/*"]
}
Minimal MCP Server
// src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
// Define tool input schemas
const GetWeatherSchema = z.object({
city: z.string().describe("City name to get weather for"),
units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
});
// Create server instance
const server = new Server(
{
name: "weather-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "get_weather",
description: "Complete guide to Model Context Protocol (MCP) servers for Claude. Learn to extend Claude with file access, databases, APIs, and custom integrations.",
inputSchema: {
type: "object",
properties: {
city: {
type: "string",
description: "Complete guide to Model Context Protocol (MCP) servers for Claude. Learn to extend Claude with file access, databases, APIs, and custom integrations.",
},
units: {
type: "string",
enum: ["celsius", "fahrenheit"],
default: "celsius",
},
},
required: ["city"],
},
},
],
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "get_weather") {
const args = GetWeatherSchema.parse(request.params.arguments);
const weather = await fetchWeather(args.city, args.units);
return {
content: [{ type: "text", text: JSON.stringify(weather, null, 2) }],
};
}
throw new Error(`Unknown tool: ${request.params.name}`);
});
async function fetchWeather(city: string, units: string) {
return {
city,
temperature: units === "celsius" ? 22 : 72,
units,
conditions: "Partly cloudy",
humidity: 65,
timestamp: new Date().toISOString(),
};
}
// Start server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Weather MCP server running on stdio");
}
main().catch(console.error);
MCP Server Capabilities
Tools
Tools are functions that Claude can call to perform actions:
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "create_github_issue",
description: "Complete guide to Model Context Protocol (MCP) servers for Claude. Learn to extend Claude with file access, databases, APIs, and custom integrations.",
inputSchema: {
type: "object",
properties: {
repo: { type: "string", description: "Complete guide to Model Context Protocol (MCP) servers for Claude. Learn to extend Claude with file access, databases, APIs, and custom integrations." },
title: { type: "string", description: "Complete guide to Model Context Protocol (MCP) servers for Claude. Learn to extend Claude with file access, databases, APIs, and custom integrations." },
body: { type: "string", description: "Complete guide to Model Context Protocol (MCP) servers for Claude. Learn to extend Claude with file access, databases, APIs, and custom integrations." },
},
required: ["repo", "title"],
},
},
],
}));
Resources
Resources expose data that Claude can read:
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: [
{
uri: "config://app/settings",
name: "Application Settings",
description: "Complete guide to Model Context Protocol (MCP) servers for Claude. Learn to extend Claude with file access, databases, APIs, and custom integrations.",
mimeType: "application/json",
},
],
}));
Prompts
Prompts are reusable templates that Claude can use:
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
prompts: [
{
name: "code_review",
description: "Complete guide to Model Context Protocol (MCP) servers for Claude. Learn to extend Claude with file access, databases, APIs, and custom integrations.",
arguments: [
{ name: "language", description: "Complete guide to Model Context Protocol (MCP) servers for Claude. Learn to extend Claude with file access, databases, APIs, and custom integrations.", required: true },
],
},
],
}));
Production Patterns
Database Integration Server
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "query_database") {
const { query, params } = request.params.arguments;
// Security: Only allow SELECT queries
if (!query.trim().toUpperCase().startsWith("SELECT")) {
throw new Error("Only SELECT queries are allowed");
}
const result = await pool.query(query, params);
return {
content: [{
type: "text",
text: JSON.stringify({ rows: result.rows, rowCount: result.rowCount }, null, 2),
}],
};
}
});
File System Server with Sandboxing
const SANDBOX_ROOT = process.env.SANDBOX_ROOT || "/tmp/claude-sandbox";
function resolveSafePath(requestedPath: string): string {
const resolved = path.resolve(SANDBOX_ROOT, requestedPath);
// Security: Prevent path traversal
if (!resolved.startsWith(SANDBOX_ROOT)) {
throw new Error("Path traversal attempt detected");
}
return resolved;
}
Security Best Practices
Input Validation
import { z } from "zod";
const StrictInputSchema = z.object({
query: z.string().max(1000).regex(/^[a-zA-Z0-9\s\-_]+$/),
limit: z.number().int().min(1).max(100).default(10),
});
Rate Limiting
import { RateLimiter } from "limiter";
const limiter = new RateLimiter({ tokensPerInterval: 100, interval: "minute" });
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const hasToken = await limiter.tryRemoveTokens(1);
if (!hasToken) {
throw new Error("Rate limit exceeded. Try again later.");
}
// Process request
});
Popular MCP Servers
| Server | Description |
@modelcontextprotocol/server-filesystem | File system access |
@modelcontextprotocol/server-github | GitHub integration |
@modelcontextprotocol/server-postgres | PostgreSQL queries |
@modelcontextprotocol/server-slack | Slack messaging |
Frequently Asked Questions
Can MCP servers access the internet?
Yes, MCP servers can make network requests. Security controls should be implemented within the server code.
Do MCP servers work with Claude.ai web interface?
MCP servers currently work with Claude Desktop and Claude Code only.
How do I debug MCP server issues?
Enable debug logging with DEBUG=mcp:* and use the MCP Inspector:
npx @modelcontextprotocol/inspector node /path/to/your/server.js
Can multiple MCP servers run simultaneously?
Yes, Claude Desktop can connect to multiple MCP servers concurrently.
MCP is an open standard maintained by the Agentic AI Foundation under the Linux Foundation.