MCP 使用指南

Model Context Protocol - 实战操作手册

从安装到部署的完整技术指南

📑 目录导航

快速索引

一、核心使用流程

步骤 1: 环境准备

系统要求

  • Node.js >= 18.0.0
  • Python >= 3.9 (可选,用于Python MCP服务器)
  • 操作系统: Linux / macOS / Windows

安装 MCP SDK

# Node.js 环境 npm install @modelcontextprotocol/sdk # Python 环境 pip install mcp # 验证安装 npm list @modelcontextprotocol/sdk python -c "import mcp; print(mcp.__version__)"
💡 提示: 建议使用 nvm 或 pyenv 管理多版本环境

基础服务器模板 (Node.js)

// server.js const { MCPServer } = require('@modelcontextprotocol/sdk'); const server = new MCPServer({ name: 'my-mcp-server', version: '1.0.0' }); // 注册工具 server.tool('get_weather', { description: '获取城市天气信息', parameters: { city: { type: 'string', required: true } } }, async ({ city }) => { return { temperature: 25, condition: 'sunny' }; }); // 启动服务器 server.listen(3000);

步骤 2: 创建 MCP 服务器

配置文件示例

{ "mcpServers": { "weather-service": { "command": "node", "args": ["server.js"], "env": { "API_KEY": "your-api-key" } } } }

步骤 3: 客户端集成

const { MCPClient } = require('@modelcontextprotocol/sdk'); const client = new MCPClient(); // 连接到服务器 await client.connect('stdio', { command: 'node', args: ['server.js'] }); // 调用工具 const result = await client.callTool('get_weather', { city: 'Beijing' }); console.log(result); // { temperature: 25, condition: 'sunny' }

步骤 4: 验证运行

测试命令

# 启动服务器 node server.js # 测试工具调用 curl -X POST http://localhost:3000/tools/get_weather \ -H "Content-Type: application/json" \ -d '{"city": "Beijing"}' # 查看日志 tail -f logs/mcp-server.log
📝 成功标志:
  • 服务器启动无错误
  • 工具调用返回预期结果
  • 日志显示正常连接信息

二、场景化配置模板

场景 1: 数据库连接

PostgreSQL 配置示例

最小配置
{ "mcpServers": { "postgres-db": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-postgres"], "env": { "POSTGRES_URL": "postgresql://user:pass@localhost:5432/db" } } } }
生产配置
{ "mcpServers": { "postgres-db": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-postgres"], "env": { "POSTGRES_URL": "postgresql://user:pass@localhost:5432/db", "MAX_CONNECTIONS": "20", "CONNECTION_TIMEOUT": "5000", "QUERY_TIMEOUT": "30000", "SSL_MODE": "require" } } } }

工具调用示例

// 查询数据 const result = await client.callTool('query', { sql: 'SELECT * FROM users WHERE age > $1', params: [18] }); // 错误处理 try { await client.callTool('query', { sql: 'INVALID SQL' }); } catch (error) { console.error('Query failed:', error.message); }

调试命令

# 测试数据库连接 psql $POSTGRES_URL -c "SELECT 1" # 查看活动连接 psql $POSTGRES_URL -c "SELECT * FROM pg_stat_activity"

场景 2: API 集成

第三方 API 配置

最小配置
{ "mcpServers": { "weather-api": { "command": "node", "args": ["api-server.js"], "env": { "API_KEY": "your-key", "API_URL": "https://api.weather.com" } } } }
生产配置
{ "mcpServers": { "weather-api": { "command": "node", "args": ["api-server.js"], "env": { "API_KEY": "your-key", "API_URL": "https://api.weather.com", "RATE_LIMIT": "100", "RATE_WINDOW": "60000", "RETRY_ATTEMPTS": "3", "RETRY_DELAY": "1000", "TIMEOUT": "5000", "CACHE_TTL": "300" } } } }

请求封装示例

server.tool('fetch_weather', { description: '获取天气数据', parameters: { city: { type: 'string', required: true } } }, async ({ city }) => { const response = await fetch(`${process.env.API_URL}/weather`, { method: 'GET', headers: { 'Authorization': `Bearer ${process.env.API_KEY}`, 'Content-Type': 'application/json' }, params: { city } }); return await response.json(); });

速率限制与重试

const rateLimit = require('express-rate-limit'); const limiter = rateLimit({ windowMs: parseInt(process.env.RATE_WINDOW), max: parseInt(process.env.RATE_LIMIT) }); // 重试机制 async function retryRequest(fn, attempts = 3) { for (let i = 0; i < attempts; i++) { try { return await fn(); } catch (error) { if (i === attempts - 1) throw error; await new Promise(r => setTimeout(r, 1000 * (i + 1))); } } }

场景 3: 本地工具链集成

文件系统操作配置

基础配置
{ "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem"], "env": { "ALLOWED_PATHS": "/home/user/documents,/tmp", "MAX_FILE_SIZE": "10485760", "ALLOWED_EXTENSIONS": ".txt,.md,.json" } } } }

工具调用示例

// 读取文件 const content = await client.callTool('read_file', { path: '/home/user/documents/data.json' }); // 写入文件 await client.callTool('write_file', { path: '/home/user/documents/output.txt', content: 'Hello, MCP!' }); // 列出目录 const files = await client.callTool('list_directory', { path: '/home/user/documents' });

Shell 命令暴露

server.tool('execute_command', { description: '执行系统命令', parameters: { command: { type: 'string', required: true } } }, async ({ command }) => { // 安全检查 const allowedCommands = ['ls', 'cat', 'grep']; const cmd = command.split(' ')[0]; if (!allowedCommands.includes(cmd)) { throw new Error('Command not allowed'); } const { exec } = require('child_process'); return new Promise((resolve, reject) => { exec(command, (error, stdout, stderr) => { if (error) reject(error); else resolve({ stdout, stderr }); }); }); });
⚠️ 安全提示: 始终验证和限制可执行的命令,避免命令注入攻击

场景 4: Claude Desktop 集成

配置文件路径

# macOS ~/Library/Application Support/Claude/claude_desktop_config.json # Windows %APPDATA%\Claude\claude_desktop_config.json # Linux ~/.config/Claude/claude_desktop_config.json

配置示例

{ "mcpServers": { "mytools": { "command": "node", "args": ["/path/to/server.js"], "env": { "API_KEY": "your-key" } }, "database": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-postgres"], "env": { "POSTGRES_URL": "postgresql://localhost:5432/mydb" } } } }
💡 提示: 配置后需要重启 Claude Desktop 才能生效

三、部署与运维

1. 本地开发环境

环境变量配置清单

# .env 文件 NODE_ENV=development MCP_PORT=3000 LOG_LEVEL=debug DB_URL=postgresql://localhost:5432/dev API_KEY=dev-key-123 CACHE_ENABLED=false

端口与网络设置

参数 默认值 说明
MCP_PORT 3000 服务监听端口
MCP_HOST 127.0.0.1 绑定地址
CORS_ORIGIN * 允许的跨域来源

日志配置

const winston = require('winston'); const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: winston.format.json(), transports: [ new winston.transports.File({ filename: 'error.log', level: 'error' }), new winston.transports.File({ filename: 'combined.log' }) ] });

2. 生产环境部署

环境变量配置清单

# .env.production NODE_ENV=production MCP_PORT=3000 LOG_LEVEL=warn DB_URL=postgresql://prod-host:5432/prod API_KEY=prod-key-secure CACHE_ENABLED=true REDIS_URL=redis://redis:6379 MAX_CONNECTIONS=100 REQUEST_TIMEOUT=30000

Docker 容器化配置

Dockerfile
FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . EXPOSE 3000 HEALTHCHECK --interval=30s --timeout=3s \ CMD node healthcheck.js CMD ["node", "server.js"]
docker-compose.yml
version: '3.8' services: mcp-server: build: . ports: - "3000:3000" environment: - NODE_ENV=production - DB_URL=postgresql://db:5432/prod restart: unless-stopped logging: driver: "json-file" options: max-size: "10m" max-file: "3"

健康检查端点

// healthcheck.js const http = require('http'); const options = { host: 'localhost', port: 3000, path: '/health', timeout: 2000 }; const request = http.request(options, (res) => { if (res.statusCode === 200) { process.exit(0); } else { process.exit(1); } }); request.on('error', () => process.exit(1)); request.end();

性能调优参数

参数 推荐值 说明
NODE_OPTIONS --max-old-space-size=4096 最大堆内存
UV_THREADPOOL_SIZE 128 线程池大小
MAX_CONNECTIONS 100 最大并发连接

3. 监控与日志

日志聚合配置

const winston = require('winston'); const { ElasticsearchTransport } = require('winston-elasticsearch'); const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), transports: [ // 文件日志 new winston.transports.File({ filename: 'error.log', level: 'error' }), new winston.transports.File({ filename: 'combined.log' }), // Elasticsearch (可选) new ElasticsearchTransport({ level: 'info', clientOpts: { node: 'http://elasticsearch:9200' } }) ] });

健康监控指标

server.tool('health', { description: '健康检查端点' }, async () => { return { status: 'healthy', uptime: process.uptime(), memory: process.memoryUsage(), timestamp: Date.now(), version: '1.0.0' }; }); // Prometheus 指标暴露 const client = require('prom-client'); const register = new client.Registry(); const httpRequestDuration = new client.Histogram({ name: 'mcp_request_duration_seconds', help: 'Duration of MCP requests in seconds', labelNames: ['tool', 'status'] }); register.registerMetric(httpRequestDuration);

四、最佳实践指南

1. 安全性最佳实践

环境变量管理

// ❌ 错误: 硬编码敏感信息 const apiKey = 'sk-1234567890abcdef'; // ✅ 正确: 使用环境变量 const apiKey = process.env.API_KEY; if (!apiKey) { throw new Error('API_KEY environment variable is required'); }

输入验证

server.tool('query_user', { description: '查询用户信息', parameters: { userId: { type: 'string', required: true, pattern: '^[0-9a-f]{24}$' // MongoDB ObjectId 格式 } } }, async ({ userId }) => { // 参数清理 const sanitizedId = userId.trim(); // 二次验证 if (!/^[0-9a-f]{24}$/.test(sanitizedId)) { throw new Error('Invalid user ID format'); } return await db.users.findById(sanitizedId); });

权限控制

const permissions = { 'read': ['read_file', 'list_directory'], 'write': ['write_file', 'delete_file'], 'admin': ['execute_command', 'system_info'] }; function checkPermission(toolName, userRole) { const allowedTools = permissions[userRole] || []; if (!allowedTools.includes(toolName)) { throw new Error(`Permission denied for tool: ${toolName}`); } }

2. 性能优化建议

连接池配置

const { Pool } = require('pg'); const pool = new Pool({ host: process.env.DB_HOST, port: 5432, database: process.env.DB_NAME, user: process.env.DB_USER, password: process.env.DB_PASSWORD, // 连接池配置 min: 5, // 最小连接数 max: 20, // 最大连接数 idleTimeoutMillis: 30000, // 空闲超时 connectionTimeoutMillis: 2000 });

缓存策略

const Redis = require('ioredis'); const redis = new Redis(process.env.REDIS_URL); server.tool('get_user', { description: '获取用户信息 (带缓存)' }, async ({ userId }) => { // 尝试从缓存获取 const cacheKey = `user:${userId}`; const cached = await redis.get(cacheKey); if (cached) { return JSON.parse(cached); } // 从数据库查询 const user = await db.users.findById(userId); // 写入缓存 (5分钟过期) await redis.setex(cacheKey, 300, JSON.stringify(user)); return user; });

批量操作优化

// ❌ 低效: 循环查询 for (const id of userIds) { const user = await db.users.findById(id); results.push(user); } // ✅ 高效: 批量查询 const users = await db.users.find({ _id: { $in: userIds } });

3. 错误处理模式

统一错误处理

class MCPError extends Error { constructor(code, message, details = {}) { super(message); this.code = code; this.details = details; } } server.tool('risky_operation', { description: '可能失败的操作' }, async (params) => { try { return await performOperation(params); } catch (error) { // 分类错误 if (error.code === 'ECONNREFUSED') { throw new MCPError( 'CONNECTION_ERROR', 'Unable to connect to backend service', { originalError: error.message } ); } if (error.name === 'ValidationError') { throw new MCPError( 'INVALID_INPUT', 'Input validation failed', { fields: error.errors } ); } // 未知错误 throw new MCPError( 'INTERNAL_ERROR', 'An unexpected error occurred', { originalError: error.message } ); } });

重试机制

async function withRetry(fn, options = {}) { const { maxAttempts = 3, delayMs = 1000, backoffMultiplier = 2, retryableErrors = ['ETIMEDOUT', 'ECONNRESET'] } = options; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (error) { // 判断是否可重试 const isRetryable = retryableErrors.includes(error.code); const isLastAttempt = attempt === maxAttempts; if (!isRetryable || isLastAttempt) { throw error; } // 指数退避 const delay = delayMs * Math.pow(backoffMultiplier, attempt - 1); await new Promise(resolve => setTimeout(resolve, delay)); } } } // 使用示例 const result = await withRetry( () => client.callTool('unstable_api', params), { maxAttempts: 3, delayMs: 1000 } );

优雅降级

server.tool('get_recommendations', { description: '获取推荐 (带降级)' }, async ({ userId }) => { try { // 尝试使用 AI 推荐 return await aiService.getRecommendations(userId); } catch (error) { logger.warn('AI service unavailable, falling back to rules-based'); // 降级到规则引擎 return await rulesEngine.getRecommendations(userId); } });

五、配套流程图

1. 配置加载流程图

读取配置文件 解析 JSON/TOML 验证配置项 验证失败 抛出错误 初始化服务器 加载工具 服务器就绪 监听端口 失败 成功 ⏱ ~50ms ⏱ ~20ms ⏱ ~30ms ⏱ ~100ms

2. 工具调用时序图

客户端 MCP 服务器 后端服务 1. callTool(name, params) 验证参数 2. 执行业务逻辑 处理请求 查询数据 3. 返回结果 格式化响应 4. 返回给客户端 发起请求 接收响应 ⏱ 总耗时: ~200ms • 网络延迟: ~50ms • 处理时间: ~150ms

3. 多场景部署拓扑图

开发环境 本地 MCP 服务器 端口: 3000 日志: DEBUG 缓存: 禁用 测试环境 Docker 容器 端口: 8080 日志: INFO 缓存: 启用 生产环境 K8s 集群 副本: 3 日志: WARN 缓存: Redis SQLite 数据库 本地文件 PostgreSQL 单实例 PostgreSQL 集群 主从复制 特性对比: ✓ 开发: 快速迭代, 详细日志 ✓ 测试: 接近生产, 自动化测试 ✓ 生产: 高可用, 性能优化

4. 错误排查决策树

MCP 服务器错误 服务器能启动吗? 检查配置文件 工具调用失败? 解决方案: 1. 验证 JSON 格式 2. 检查环境变量 3. 查看启动日志 检查工具实现 解决方案: 1. 验证参数类型 2. 添加错误处理 3. 检查权限设置 性能问题? 优化建议: 1. 启用缓存 2. 增加连接池 3. 优化查询 常见错误代码: • ECONNREFUSED: 服务器未启动或端口错误 • ETIMEDOUT: 网络超时或服务器响应慢 • EACCES: 权限不足 • INVALID_PARAMS: 参数验证失败 • TOOL_NOT_FOUND: 工具未注册

六、故障排查手册

常见问题速查表

问题 1: 服务器无法启动

错误信息 可能原因 解决方案
EADDRINUSE 端口已被占用 修改端口或关闭占用进程: lsof -i :3000
MODULE_NOT_FOUND 依赖未安装 运行 npm install
EACCES 权限不足 检查文件权限或使用正确的用户运行
Invalid JSON 配置文件格式错误 使用 JSON 校验工具检查语法

问题 2: 工具调用失败

# 检查服务器日志 tail -f logs/mcp-server.log # 测试工具是否注册 curl http://localhost:3000/tools # 使用调试模式启动 LOG_LEVEL=debug node server.js

问题 3: 性能问题

  • 响应慢: 检查数据库连接池配置,启用缓存
  • 内存泄漏: 使用 node --inspect server.js 进行内存分析
  • 高 CPU: 优化查询语句,减少计算密集型操作

问题 4: Claude Desktop 未识别服务器

检查清单:
  • ✓ 配置文件路径是否正确
  • ✓ JSON 格式是否有效 (使用 jq . config.json 验证)
  • ✓ 命令路径是否为绝对路径
  • ✓ 是否重启了 Claude Desktop
  • ✓ 查看 Claude 日志: ~/Library/Logs/Claude/

调试技巧

启用详细日志

# 设置环境变量 export DEBUG=mcp:* export LOG_LEVEL=debug # 启动服务器 node server.js 2>&1 | tee server.log

使用 MCP Inspector 工具

# 安装 inspector npm install -g @modelcontextprotocol/inspector # 启动 inspector mcp-inspector node server.js # 在浏览器打开 # http://localhost:5173

配置验证脚本

// validate-config.js const fs = require('fs'); function validateConfig(configPath) { try { const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); // 检查必需字段 if (!config.mcpServers) { throw new Error('Missing mcpServers field'); } // 验证每个服务器配置 for (const [name, server] of Object.entries(config.mcpServers)) { if (!server.command) { throw new Error(`Server ${name}: missing command`); } if (!Array.isArray(server.args)) { throw new Error(`Server ${name}: args must be an array`); } console.log(`✓ Server ${name} configuration valid`); } console.log('\n✓ All configurations valid!'); return true; } catch (error) { console.error(`✗ Validation failed: ${error.message}`); return false; } } // 使用示例 validateConfig('./mcp-config.json');

运行验证

node validate-config.js # 输出示例: # ✓ Server postgres-db configuration valid # ✓ Server weather-api configuration valid # ✓ All configurations valid!