The Model Context Protocol (MCP) is an open standard that enables seamless integration between AI applications and external tools. It provides a unified way for AI models to interact with databases, APIs, and local services through a standardized protocol.
Claude, VS Code, etc.
Protocol Handler
Tool Provider
DBs, APIs, Files
JSON-RPC 2.0 based communication for reliable message passing between clients and servers.
Automatic discovery and registration of available tools and their capabilities.
Built-in authentication, authorization, and sandboxing for safe tool execution.
Efficient handling of files, databases, and API connections with proper lifecycle management.
MCP servers expose tools and resources to AI applications. They handle requests and execute actions on behalf of the AI.
// Basic MCP Server Structure (TypeScript)
import { Server } from '@modelcontextprotocol/sdk';
class MyMCPServer {
private server: Server;
constructor() {
this.server = new Server({
name: "my-tools-server",
version: "1.0.0",
capabilities: {
tools: true,
resources: true,
prompts: true
}
});
this.registerTools();
this.registerResources();
}
private registerTools() {
// Register a tool for web searching
this.server.registerTool({
name: "web_search",
description: "Search the web for information",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "Search query"
},
limit: {
type: "number",
description: "Number of results",
default: 5
}
},
required: ["query"]
},
handler: async (params) => {
const results = await this.performWebSearch(params.query, params.limit);
return {
results: results
};
}
});
// Register a database query tool
this.server.registerTool({
name: "query_database",
description: "Execute SQL queries on the database",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "SQL query to execute"
},
database: {
type: "string",
description: "Database name",
default: "main"
}
},
required: ["query"]
},
handler: async (params) => {
return await this.executeSQLQuery(params.query, params.database);
}
});
}
private registerResources() {
// Register file resources
this.server.registerResource({
uri: "file:///workspace",
name: "Workspace Files",
description: "Access to project files",
mimeType: "text/plain",
handler: async (uri) => {
return await this.readFile(uri);
}
});
}
async start(port: number = 3000) {
await this.server.listen(port);
console.log(`MCP Server running on port ${port}`);
}
}
// Start the server
const server = new MyMCPServer();
server.start();
Clients connect to MCP servers and invoke their tools. They handle the protocol communication and response processing.
// MCP Client Implementation
import { Client } from '@modelcontextprotocol/sdk';
class MCPClient {
private client: Client;
async connect(serverUrl: string) {
this.client = new Client();
await this.client.connect(serverUrl);
// Discover available tools
const tools = await this.client.listTools();
console.log("Available tools:", tools);
// Discover available resources
const resources = await this.client.listResources();
console.log("Available resources:", resources);
}
async callTool(toolName: string, params: any) {
try {
const result = await this.client.callTool({
name: toolName,
arguments: params
});
return result;
} catch (error) {
console.error(`Tool execution failed: ${error}`);
throw error;
}
}
async readResource(uri: string) {
try {
const content = await this.client.readResource(uri);
return content;
} catch (error) {
console.error(`Resource read failed: ${error}`);
throw error;
}
}
}
// Usage example
const client = new MCPClient();
await client.connect("ws://localhost:3000");
// Use web search tool
const searchResults = await client.callTool("web_search", {
query: "latest AI developments",
limit: 3
});
// Query database
const dbResults = await client.callTool("query_database", {
query: "SELECT * FROM users WHERE active = true"
});
# Initialize project
mkdir my-mcp-server
cd my-mcp-server
npm init -y
# Install MCP SDK
npm install @modelcontextprotocol/sdk
# Install development dependencies
npm install --save-dev typescript @types/node tsx
# Create TypeScript config
cat > tsconfig.json << EOF
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "./dist"
}
}
EOF
// src/server.ts
import { Server, Tool, Resource } from '@modelcontextprotocol/sdk';
import * as fs from 'fs/promises';
import * as path from 'path';
class FileSystemMCPServer {
private server: Server;
private rootPath: string;
constructor(rootPath: string = process.cwd()) {
this.rootPath = rootPath;
this.server = new Server({
name: "filesystem-server",
version: "1.0.0",
description: "MCP server for file system operations"
});
this.setupTools();
this.setupResources();
}
private setupTools() {
// List files tool
this.server.registerTool({
name: "list_files",
description: "List files in a directory",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "Directory path"
}
},
required: ["path"]
},
handler: async ({ path: dirPath }) => {
const fullPath = path.join(this.rootPath, dirPath);
const files = await fs.readdir(fullPath);
const fileInfo = await Promise.all(
files.map(async (file) => {
const filePath = path.join(fullPath, file);
const stat = await fs.stat(filePath);
return {
name: file,
type: stat.isDirectory() ? "directory" : "file",
size: stat.size,
modified: stat.mtime
};
})
);
return { files: fileInfo };
}
});
// Read file tool
this.server.registerTool({
name: "read_file",
description: "Read contents of a file",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "File path"
}
},
required: ["path"]
},
handler: async ({ path: filePath }) => {
const fullPath = path.join(this.rootPath, filePath);
const content = await fs.readFile(fullPath, 'utf-8');
return { content };
}
});
// Write file tool
this.server.registerTool({
name: "write_file",
description: "Write content to a file",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "File path"
},
content: {
type: "string",
description: "File content"
}
},
required: ["path", "content"]
},
handler: async ({ path: filePath, content }) => {
const fullPath = path.join(this.rootPath, filePath);
await fs.writeFile(fullPath, content, 'utf-8');
return { success: true, path: filePath };
}
});
}
private setupResources() {
// Register workspace as a resource
this.server.registerResource({
uri: `file://${this.rootPath}`,
name: "Workspace",
description: "The workspace root directory",
mimeType: "inode/directory"
});
}
async start() {
const port = process.env.MCP_PORT || 3000;
await this.server.listen(port);
console.log(`File System MCP Server running on port ${port}`);
}
}
// Start server
const server = new FileSystemMCPServer();
server.start().catch(console.error);
# Claude Desktop configuration (~/Library/Application Support/Claude/claude_desktop_config.json)
{
"mcpServers": {
"filesystem": {
"command": "node",
"args": ["/path/to/your/mcp-server/dist/server.js"],
"env": {
"MCP_PORT": "3000"
}
},
"database": {
"command": "python",
"args": ["/path/to/database-server.py"],
"env": {
"DATABASE_URL": "postgresql://localhost/mydb"
}
}
}
}
| Capability | Description | Use Cases |
|---|---|---|
| Tools | Execute functions and actions | API calls, calculations, data processing |
| Resources | Access and manage data | Files, databases, remote content |
| Prompts | Reusable prompt templates | Common queries, structured outputs |
| Sampling | LLM text generation | Content creation, completions |
| Roots | Project root directories | Workspace management, file navigation |
// Implementing authentication in MCP server
class SecureMCPServer {
private server: Server;
private validTokens: Set;
constructor() {
this.validTokens = new Set(process.env.VALID_TOKENS?.split(',') || []);
this.server = new Server({
name: "secure-server",
version: "1.0.0",
authenticate: async (token: string) => {
// Validate token
if (!this.validTokens.has(token)) {
throw new Error("Invalid authentication token");
}
return true;
}
});
}
// Rate limiting implementation
private rateLimiter = new Map();
private checkRateLimit(clientId: string): boolean {
const now = Date.now();
const windowMs = 60000; // 1 minute window
const maxRequests = 100;
if (!this.rateLimiter.has(clientId)) {
this.rateLimiter.set(clientId, []);
}
const requests = this.rateLimiter.get(clientId)!;
const recentRequests = requests.filter(time => now - time < windowMs);
if (recentRequests.length >= maxRequests) {
return false;
}
recentRequests.push(now);
this.rateLimiter.set(clientId, recentRequests);
return true;
}
}
// Streaming large resources
this.server.registerResource({
uri: "stream://large-file",
name: "Large Dataset",
description: "Stream large dataset in chunks",
handler: async function* (uri: string) {
const chunkSize = 1024 * 1024; // 1MB chunks
const fileStream = fs.createReadStream('large-file.dat', {
highWaterMark: chunkSize
});
for await (const chunk of fileStream) {
yield {
data: chunk.toString('base64'),
encoding: 'base64',
done: false
};
}
yield { done: true };
}
});
// Comprehensive error handling
this.server.registerTool({
name: "safe_operation",
description: "Operation with proper error handling",
handler: async (params) => {
try {
// Validate input
if (!params.input || typeof params.input !== 'string') {
return {
error: {
code: "INVALID_INPUT",
message: "Input must be a non-empty string"
}
};
}
// Perform operation
const result = await this.performOperation(params.input);
return {
success: true,
result: result
};
} catch (error) {
// Log error for debugging
console.error('Operation failed:', error);
// Return structured error
return {
error: {
code: error.code || "OPERATION_FAILED",
message: error.message || "An unexpected error occurred",
details: process.env.NODE_ENV === 'development' ? error.stack : undefined
}
};
}
}
});
Native integration with Claude Desktop app for local tool access.
Use MCP servers in VS Code with Cline and Continue extensions.
Integrate MCP servers with web-based AI applications.
Build your own MCP clients for specific use cases.