MCP协议开发实战:从零搭建AI Agent工具链

引言:为什么需要MCP协议?

  • AI Agent 生态的碎片化问题
  • Model Context Protocol (MCP) 的定位与核心价值
  • 本文目标:手把手教你构建一个基于 MCP 的 AI Agent 工具链

第一部分:MCP协议核心概念解析

1.1 MCP 是什么?

  • 协议定义:模型与工具/数据源之间的标准化通信接口
  • 核心组件:Server、Client、Resources、Tools、Prompts
  • 与 OpenAI Function Calling、LangChain Tools 的对比

1.2 MCP 的核心优势

  • 标准化:统一的工具发现、调用与数据访问接口
  • 可组合性:任意 Server 可与任意 Client 组合
  • 安全性:明确的权限控制与资源隔离
  • 开发友好:语言无关、框架轻量

1.3 MCP 协议工作流程全景图

#mermaid-svg-wBU1K9y58VTbV9h3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wBU1K9y58VTbV9h3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wBU1K9y58VTbV9h3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wBU1K9y58VTbV9h3 .error-icon{fill:#552222;}#mermaid-svg-wBU1K9y58VTbV9h3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wBU1K9y58VTbV9h3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wBU1K9y58VTbV9h3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wBU1K9y58VTbV9h3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wBU1K9y58VTbV9h3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wBU1K9y58VTbV9h3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wBU1K9y58VTbV9h3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wBU1K9y58VTbV9h3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wBU1K9y58VTbV9h3 .marker.cross{stroke:#333333;}#mermaid-svg-wBU1K9y58VTbV9h3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wBU1K9y58VTbV9h3 p{margin:0;}#mermaid-svg-wBU1K9y58VTbV9h3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wBU1K9y58VTbV9h3 .cluster-label text{fill:#333;}#mermaid-svg-wBU1K9y58VTbV9h3 .cluster-label span{color:#333;}#mermaid-svg-wBU1K9y58VTbV9h3 .cluster-label span p{background-color:transparent;}#mermaid-svg-wBU1K9y58VTbV9h3 .label text,#mermaid-svg-wBU1K9y58VTbV9h3 span{fill:#333;color:#333;}#mermaid-svg-wBU1K9y58VTbV9h3 .node rect,#mermaid-svg-wBU1K9y58VTbV9h3 .node circle,#mermaid-svg-wBU1K9y58VTbV9h3 .node ellipse,#mermaid-svg-wBU1K9y58VTbV9h3 .node polygon,#mermaid-svg-wBU1K9y58VTbV9h3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wBU1K9y58VTbV9h3 .rough-node .label text,#mermaid-svg-wBU1K9y58VTbV9h3 .node .label text,#mermaid-svg-wBU1K9y58VTbV9h3 .image-shape .label,#mermaid-svg-wBU1K9y58VTbV9h3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-wBU1K9y58VTbV9h3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wBU1K9y58VTbV9h3 .rough-node .label,#mermaid-svg-wBU1K9y58VTbV9h3 .node .label,#mermaid-svg-wBU1K9y58VTbV9h3 .image-shape .label,#mermaid-svg-wBU1K9y58VTbV9h3 .icon-shape .label{text-align:center;}#mermaid-svg-wBU1K9y58VTbV9h3 .node.clickable{cursor:pointer;}#mermaid-svg-wBU1K9y58VTbV9h3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wBU1K9y58VTbV9h3 .arrowheadPath{fill:#333333;}#mermaid-svg-wBU1K9y58VTbV9h3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wBU1K9y58VTbV9h3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wBU1K9y58VTbV9h3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wBU1K9y58VTbV9h3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wBU1K9y58VTbV9h3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wBU1K9y58VTbV9h3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wBU1K9y58VTbV9h3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wBU1K9y58VTbV9h3 .cluster text{fill:#333;}#mermaid-svg-wBU1K9y58VTbV9h3 .cluster span{color:#333;}#mermaid-svg-wBU1K9y58VTbV9h3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-wBU1K9y58VTbV9h3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wBU1K9y58VTbV9h3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-wBU1K9y58VTbV9h3 .icon-shape,#mermaid-svg-wBU1K9y58VTbV9h3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wBU1K9y58VTbV9h3 .icon-shape p,#mermaid-svg-wBU1K9y58VTbV9h3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wBU1K9y58VTbV9h3 .icon-shape .label rect,#mermaid-svg-wBU1K9y58VTbV9h3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wBU1K9y58VTbV9h3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wBU1K9y58VTbV9h3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wBU1K9y58VTbV9h3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-wBU1K9y58VTbV9h3 .client>*{fill:#e1f5fe!important;stroke:#01579b!important;}#mermaid-svg-wBU1K9y58VTbV9h3 .client span{fill:#e1f5fe!important;stroke:#01579b!important;}#mermaid-svg-wBU1K9y58VTbV9h3 .server>*{fill:#f3e5f5!important;stroke:#4a148c!important;}#mermaid-svg-wBU1K9y58VTbV9h3 .server span{fill:#f3e5f5!important;stroke:#4a148c!important;}#mermaid-svg-wBU1K9y58VTbV9h3 .tool>*{fill:#e8f5e8!important;stroke:#1b5e20!important;}#mermaid-svg-wBU1K9y58VTbV9h3 .tool span{fill:#e8f5e8!important;stroke:#1b5e20!important;}#mermaid-svg-wBU1K9y58VTbV9h3 .resource>*{fill:#fff3e0!important;stroke:#e65100!important;}#mermaid-svg-wBU1K9y58VTbV9h3 .resource span{fill:#fff3e0!important;stroke:#e65100!important;}#mermaid-svg-wBU1K9y58VTbV9h3 .prompt>*{fill:#fce4ec!important;stroke:#880e4f!important;}#mermaid-svg-wBU1K9y58VTbV9h3 .prompt span{fill:#fce4ec!important;stroke:#880e4f!important;}#mermaid-svg-wBU1K9y58VTbV9h3 .monitor>*{fill:#f1f8e9!important;stroke:#33691e!important;}#mermaid-svg-wBU1K9y58VTbV9h3 .monitor span{fill:#f1f8e9!important;stroke:#33691e!important;} 监控与调试
上下文管理层
数据源层
工具执行层
MCP 协议层
AI 应用层 (Client)
JSON-RPC over Stdio/SSE/HTTP
监控
记录
指标收集

  1. 用户请求
  2. 分析需求
  3. 发现能力
  4. 列出工具/资源
  5. 调用工具
  6. 执行工具
  7. 返回结果
  8. 返回响应
  9. 生成回答
  10. 返回用户
  11. 请求资源
  12. 读取资源
  13. 获取数据
  14. 返回数据
  15. 提供上下文
  16. 请求提示词
  17. 获取模板
  18. 注入上下文
  19. 返回模板
  20. 增强提示
  21. 实时调试
  22. 记录日志
  23. 收集指标
    AI 应用 (Client)
    AI 模型 (LLM)
    MCP Client SDK
    MCP Server
    协议处理引擎
    工具管理器 (Tools)
    资源管理器 (Resources)
    提示词管理器 (Prompts)
    天气查询 API
    文件系统操作
    数据库查询
    外部服务集成
    文件系统
    数据库
    API 服务
    实时数据流
    系统提示词
    用户上下文
    会话历史
    MCP Inspector
    日志系统
    性能监控

图例说明:

  1. AI 应用层 (Client):用户与 AI 模型的交互入口

    • AI 应用:如 Claude Desktop、Cursor、Windsurf 等
    • AI 模型:大语言模型,负责理解用户意图
    • MCP Client SDK:处理与 MCP Server 的通信
  2. MCP 协议层:核心协议处理

    • MCP Server:协议服务端,管理工具、资源和提示词
    • 协议处理引擎:解析 JSON-RPC 请求,路由到对应处理器
    • 工具管理器:注册、发现和执行工具
    • 资源管理器:提供结构化数据访问
    • 提示词管理器:管理动态提示词模板
  3. 工具执行层:具体业务逻辑实现

    • 天气查询 API:调用第三方天气服务
    • 文件系统操作:读写本地文件
    • 数据库查询:访问结构化数据
    • 外部服务集成:连接其他 API 服务
  4. 数据源层:原始数据存储

    • 文件系统:文档、配置文件等
    • 数据库:用户数据、产品信息等
    • API 服务:第三方数据接口
    • 实时数据流:WebSocket、消息队列等
  5. 上下文管理层:提示词和会话管理

    • 系统提示词:预定义的指令模板
    • 用户上下文:当前会话的用户信息
    • 会话历史:对话记录和上下文
  6. 监控与调试:运维支持

    • MCP Inspector:协议调试工具
    • 日志系统:记录操作日志
    • 性能监控:收集性能指标

工作流程编号说明:

  • 1-10:主要工具调用流程
  • 11-15:资源访问流程
  • 16-20:提示词管理流程
  • 21-23:监控调试流程

协议优势体现:

  • 标准化:统一的 JSON-RPC 协议
  • 可组合性:任意 Client 可与任意 Server 组合
  • 安全性:明确的权限控制和资源隔离
  • 开发友好:语言无关,框架轻量

第二部分:开发环境与工具链搭建

2.1 环境准备

  • Node.js/Python 运行时选择
  • 安装 MCP SDK (@modelcontextprotocol/sdk)
  • 初始化项目结构

2.2 核心开发工具介绍

  • MCP Inspector:协议调试与监控
  • Server 开发模板 (TypeScript/Python)
  • Client 集成示例 (Claude Desktop, Cursor, Windsurf)
  • 模拟测试工具

第三部分:实战一:构建你的第一个 MCP Server

3.1 定义 Server 能力清单

  • 声明 Tools:天气查询、文件读写、数据库操作
  • 声明 Resources:项目文档、API 规格书
  • 声明 Prompts:代码生成系统提示

3.2 实现 Tool 处理逻辑

  • 天气查询 Tool 实现(调用公开 API)
  • 文件列表 Tool 实现(本地目录扫描)
  • 错误处理与日志记录

3.6 实战代码示例:文件系统 Resource 实现

以下示例展示如何实现一个文件系统 Resource,提供项目文档的读取能力:

typescript 复制代码
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  ListResourcesRequestSchema,
  ReadResourceRequestSchema,
  Resource,
} from "@modelcontextprotocol/sdk/types.js";
import fs from "fs/promises";
import path from "path";

const server = new Server(
  {
    name: "filesystem-resource-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      resources: {},
    },
  }
);

// 项目文档目录
const DOCS_DIR = path.join(process.cwd(), "docs");

// 定义可用的 Resources
const resources: Resource[] = [
  {
    uri: "file:///docs/README.md",
    name: "项目说明文档",
    description: "项目的 README 文件",
    mimeType: "text/markdown",
  },
  {
    uri: "file:///docs/API.md",
    name: "API 接口文档",
    description: "详细的 API 接口说明",
    mimeType: "text/markdown",
  },
  {
    uri: "file:///docs/ARCHITECTURE.md",
    name: "架构设计文档",
    description: "系统架构设计说明",
    mimeType: "text/markdown",
  },
];

// 注册 Resource 列表
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
  resources,
}));

// 处理 Resource 读取请求
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  const uri = request.params.uri;
  const resource = resources.find((r) => r.uri === uri);
  
  if (!resource) {
    throw new Error(`Resource 未找到: ${uri}`);
  }

  try {
    // 从 URI 中提取文件名
    const fileName = uri.replace("file:///docs/", "");
    const filePath = path.join(DOCS_DIR, fileName);
    
    // 读取文件内容
    const content = await fs.readFile(filePath, "utf-8");
    
    return {
      contents: [
        {
          uri,
          mimeType: resource.mimeType,
          text: content,
        },
      ],
    };
  } catch (error) {
    throw new Error(`读取文件失败: ${error instanceof Error ? error.message : String(error)}`);
  }
});

// 动态 Resource 示例:系统状态
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
  resources: [
    ...resources,
    {
      uri: "dynamic:///system/status",
      name: "系统状态",
      description: "当前服务器的运行状态",
      mimeType: "application/json",
    },
  ],
}));

server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  if (request.params.uri === "dynamic:///system/status") {
    const status = {
      timestamp: new Date().toISOString(),
      uptime: process.uptime(),
      memory: process.memoryUsage(),
      platform: process.platform,
      nodeVersion: process.version,
    };
    
    return {
      contents: [
        {
          uri: request.params.uri,
          mimeType: "application/json",
          text: JSON.stringify(status, null, 2),
        },
      ],
    };
  }
  
  // 其他 Resource 处理逻辑...
});

// 启动 Server
async function main() {
  // 确保文档目录存在
  try {
    await fs.access(DOCS_DIR);
  } catch {
    await fs.mkdir(DOCS_DIR, { recursive: true });
    console.log(`创建文档目录: ${DOCS_DIR}`);
  }

  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("FileSystem Resource Server 已启动");
}

main().catch(console.error);

代码要点:

  1. 静态 Resource:预定义的文件资源列表
  2. 动态 Resource:实时生成的系统状态信息
  3. 错误处理:文件不存在时的友好错误提示
  4. MIME 类型:正确设置内容类型(text/markdown, application/json)
  5. 目录检查:自动创建不存在的文档目录

3.3 实现 Resource 数据提供

Resource 是 MCP 中用于提供结构化数据的关键组件。以下是一个完整的数据库 Resource 实现示例:

typescript 复制代码
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  ListResourcesRequestSchema,
  ReadResourceRequestSchema,
  Resource,
} from "@modelcontextprotocol/sdk/types.js";
import { Pool } from "pg";

const server = new Server(
  {
    name: "database-resource-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      resources: {},
    },
  }
);

// 数据库连接池
const pool = new Pool({
  host: process.env.DB_HOST || "localhost",
  port: parseInt(process.env.DB_PORT || "5432"),
  database: process.env.DB_NAME || "mcp_demo",
  user: process.env.DB_USER || "postgres",
  password: process.env.DB_PASSWORD || "password",
});

// 定义数据库 Resources
const resources: Resource[] = [
  {
    uri: "postgresql:///users",
    name: "用户数据表",
    description: "系统用户信息表",
    mimeType: "application/json",
  },
  {
    uri: "postgresql:///products",
    name: "产品目录",
    description: "产品信息表",
    mimeType: "application/json",
  },
  {
    uri: "postgresql:///orders",
    name: "订单记录",
    description: "用户订单历史",
    mimeType: "application/json",
  },
];

// 注册 Resource 列表
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
  resources,
}));

// 处理 Resource 读取请求
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  const uri = request.params.uri;
  
  try {
    let query = "";
    let tableName = "";
    
    // 根据 URI 确定查询的表
    if (uri.includes("users")) {
      tableName = "users";
      query = "SELECT id, username, email, created_at FROM users LIMIT 100";
    } else if (uri.includes("products")) {
      tableName = "products";
      query = "SELECT id, name, price, category, stock FROM products LIMIT 100";
    } else if (uri.includes("orders")) {
      tableName = "orders";
      query = "SELECT o.id, u.username, p.name, o.quantity, o.total_price, o.created_at FROM orders o JOIN users u ON o.user_id = u.id JOIN products p ON o.product_id = p.id LIMIT 50";
    } else {
      throw new Error(`不支持的 Resource URI: ${uri}`);
    }
    
    // 执行查询
    const result = await pool.query(query);
    
    // 格式化数据为表格
    const formattedData = {
      table: tableName,
      total: result.rowCount,
      data: result.rows,
      timestamp: new Date().toISOString(),
    };
    
    return {
      contents: [
        {
          uri,
          mimeType: "application/json",
          text: JSON.stringify(formattedData, null, 2),
        },
      ],
    };
  } catch (error) {
    console.error(`读取数据库 Resource 失败:`, error);
    throw new Error(`读取失败: ${error instanceof Error ? error.message : String(error)}`);
  }
});

// 动态 Resource:数据库统计信息
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
  resources: [
    ...resources,
    {
      uri: "postgresql:///statistics",
      name: "数据库统计",
      description: "数据库表统计信息",
      mimeType: "application/json",
    },
  ],
}));

server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  if (request.params.uri === "postgresql:///statistics") {
    try {
      // 获取所有表的统计信息
      const statsQuery = `
        SELECT 
          schemaname,
          tablename,
          tableowner,
          hasindexes,
          hasrules,
          hastriggers
        FROM pg_tables 
        WHERE schemaname = 'public'
        ORDER BY tablename;
      `;
      
      const statsResult = await pool.query(statsQuery);
      
      // 获取表行数统计
      const rowCountQuery = `
        SELECT 
          schemaname,
          relname as tablename,
          n_live_tup as row_count
        FROM pg_stat_user_tables
        ORDER BY n_live_tup DESC;
      `;
      
      const rowCountResult = await pool.query(rowCountQuery);
      
      const statistics = {
        timestamp: new Date().toISOString(),
        tables: statsResult.rows,
        row_counts: rowCountResult.rows,
        database_info: {
          name: process.env.DB_NAME || "mcp_demo",
          host: process.env.DB_HOST || "localhost",
          version: await pool.query("SELECT version()").then(r => r.rows[0].version),
        },
      };
      
      return {
        contents: [
          {
            uri: request.params.uri,
            mimeType: "application/json",
            text: JSON.stringify(statistics, null, 2),
          },
        ],
      };
    } catch (error) {
      console.error("获取数据库统计失败:", error);
      throw new Error(`统计信息获取失败: ${error instanceof Error ? error.message : String(error)}`);
    }
  }
  
  // 其他 Resource 处理逻辑...
});

// 启动 Server
async function main() {
  // 测试数据库连接
  try {
    await pool.query("SELECT 1");
    console.log("数据库连接成功");
  } catch (error) {
    console.error("数据库连接失败:", error);
    process.exit(1);
  }

  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Database Resource Server 已启动");
}

main().catch(console.error);

代码要点:

  1. 数据库集成:使用 PostgreSQL 作为数据源,展示如何连接关系型数据库
  2. 结构化数据:将数据库查询结果转换为 JSON 格式的 Resource
  3. 动态 Resource:实时生成数据库统计信息
  4. 错误处理:完善的数据库连接和查询错误处理
  5. 类型安全:使用 TypeScript 确保数据类型的正确性

3.4 启动与调试 Server

配置 mcp.json

创建 mcp.json 配置文件,定义 Server 的启动参数和传输方式:

json 复制代码
{
  "mcpServers": {
    "weather-server": {
      "command": "node",
      "args": ["dist/weather-server.js"],
      "env": {
        "NODE_ENV": "development",
        "LOG_LEVEL": "debug",
        "WEATHER_API_KEY": "${WEATHER_API_KEY}"
      }
    },
    "filesystem-server": {
      "command": "node",
      "args": ["dist/filesystem-server.js"],
      "env": {
        "DOCS_DIR": "./docs",
        "LOG_LEVEL": "info"
      }
    },
    "database-server": {
      "command": "node",
      "args": ["dist/database-server.js"],
      "env": {
        "DB_HOST": "localhost",
        "DB_PORT": "5432",
        "DB_NAME": "mcp_demo",
        "DB_USER": "postgres",
        "DB_PASSWORD": "${DB_PASSWORD}"
      }
    }
  }
}
启动脚本示例

创建 start-server.js 启动脚本,支持环境变量和配置管理:

typescript 复制代码
import { spawn } from "child_process";
import dotenv from "dotenv";
import fs from "fs/promises";
import path from "path";

// 加载环境变量
dotenv.config();

// 读取 mcp.json 配置
async function loadConfig() {
  try {
    const configPath = path.join(process.cwd(), "mcp.json");
    const configData = await fs.readFile(configPath, "utf-8");
    return JSON.parse(configData);
  } catch (error) {
    console.error("读取 mcp.json 失败:", error);
    process.exit(1);
  }
}

// 启动单个 Server
function startServer(serverName: string, config: any) {
  const serverConfig = config.mcpServers[serverName];
  if (!serverConfig) {
    console.error(`未找到 Server 配置: ${serverName}`);
    return null;
  }

  // 替换环境变量
  const env = { ...process.env };
  Object.entries(serverConfig.env || {}).forEach(([key, value]) => {
    if (typeof value === "string" && value.startsWith("${") && value.endsWith("}")) {
      const envVar = value.slice(2, -1);
      env[key] = process.env[envVar] || "";
    } else {
      env[key] = String(value);
    }
  });

  console.log(`启动 Server: ${serverName}`);
  console.log(`命令: ${serverConfig.command} ${serverConfig.args.join(" ")}`);
  
  const serverProcess = spawn(serverConfig.command, serverConfig.args, {
    stdio: ["pipe", "pipe", "pipe"],
    env,
  });

  // 输出处理
  serverProcess.stdout?.on("data", (data) => {
    console.log(`[${serverName} stdout] ${data.toString().trim()}`);
  });

  serverProcess.stderr?.on("data", (data) => {
    console.error(`[${serverName} stderr] ${data.toString().trim()}`);
  });

  serverProcess.on("close", (code) => {
    console.log(`Server ${serverName} 退出,代码: ${code}`);
  });

  serverProcess.on("error", (error) => {
    console.error(`启动 Server ${serverName} 失败:`, error);
  });

  return serverProcess;
}

// 使用 MCP Inspector 调试
async function startWithInspector(serverName: string, config: any) {
  const serverConfig = config.mcpServers[serverName];
  if (!serverConfig) {
    console.error(`未找到 Server 配置: ${serverName}`);
    return;
  }

  console.log(`使用 MCP Inspector 调试 ${serverName}...`);
  
  // 启动 Inspector(假设已全局安装 @modelcontextprotocol/inspector)
  const inspectorProcess = spawn("npx", [
    "@modelcontextprotocol/inspector",
    serverConfig.command,
    ...serverConfig.args
  ], {
    stdio: "inherit",
    env: { ...process.env, ...serverConfig.env },
  });

  inspectorProcess.on("close", (code) => {
    console.log(`Inspector 退出,代码: ${code}`);
  });
}

// 主函数
async function main() {
  const config = await loadConfig();
  const args = process.argv.slice(2);
  
  if (args.length === 0) {
    console.log("用法: node start-server.js <server-name> [--inspector]");
    console.log("可用 Server:", Object.keys(config.mcpServers).join(", "));
    process.exit(1);
  }

  const serverName = args[0];
  const useInspector = args.includes("--inspector");

  if (useInspector) {
    await startWithInspector(serverName, config);
  } else {
    startServer(serverName, config);
  }
}

main().catch(console.error);
常见启动问题排查

问题 1:端口冲突

bash 复制代码
# 检查端口占用
lsof -i :3000
# 或
netstat -tulpn | grep :3000

# 解决方案:修改端口或终止占用进程
export PORT=3001

问题 2:环境变量未设置

bash 复制代码
# 创建 .env 文件
echo "WEATHER_API_KEY=your_api_key_here" > .env
echo "DB_PASSWORD=your_db_password" >> .env

# 或在启动时设置
WEATHER_API_KEY=xxx DB_PASSWORD=yyy node dist/server.js

问题 3:依赖缺失

bash 复制代码
# 安装依赖
npm install

# 检查 TypeScript 编译
npx tsc --version

# 重新构建
npm run build

问题 4:权限问题

bash 复制代码
# 检查文件权限
ls -la dist/

# 添加执行权限
chmod +x dist/server.js

# 检查 Node.js 版本
node --version

问题 5:协议验证失败

bash 复制代码
# 使用 MCP Inspector 验证
npx @modelcontextprotocol/inspector node dist/server.js

# 查看详细日志
export DEBUG=mcp:* node dist/server.js
调试技巧
  1. 启用详细日志 :设置 LOG_LEVEL=debug 环境变量
  2. 使用 Inspector:实时查看协议通信
  3. 单元测试:为 Tools 和 Resources 编写测试
  4. 逐步启动:先启动单个 Server 测试,再集成多个
  5. 监控资源 :使用 top 或 htop 监控进程资源使用

3.5 实战代码示例:天气查询 Tool 实现

下面是一个完整的 TypeScript 示例,展示如何实现一个天气查询 Tool:

typescript 复制代码
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  Tool,
} from "@modelcontextprotocol/sdk/types.js";

// 创建 MCP Server
const server = new Server(
  {
    name: "weather-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// 定义天气查询 Tool
const weatherTool: Tool = {
  name: "get_weather",
  description: "获取指定城市的当前天气信息",
  inputSchema: {
    type: "object",
    properties: {
      city: {
        type: "string",
        description: "城市名称,例如:Beijing、Shanghai",
      },
      unit: {
        type: "string",
        enum: ["celsius", "fahrenheit"],
        description: "温度单位,默认摄氏度",
        default: "celsius",
      },
    },
    required: ["city"],
  },
};

// 注册 Tool 列表
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [weatherTool],
}));

// 处理 Tool 调用
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "get_weather") {
    const { city, unit = "celsius" } = request.params.arguments as {
      city: string;
      unit?: string;
    };

    // 模拟调用天气 API(实际项目中替换为真实 API 调用)
    const mockWeatherData = {
      city,
      temperature: unit === "celsius" ? "25°C" : "77°F",
      condition: "晴朗",
      humidity: "65%",
      windSpeed: "12 km/h",
      updatedAt: new Date().toISOString(),
    };

    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(mockWeatherData, null, 2),
        },
      ],
    };
  }

  throw new Error(`未知的 Tool: ${request.params.name}`);
});

// 启动 Server
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Weather MCP Server 已启动,通过 stdio 通信");
}

main().catch((error) => {
  console.error("Server 启动失败:", error);
  process.exit(1);
});

关键点说明:

  1. Tool 定义:使用 JSON Schema 定义输入参数,确保类型安全
  2. 错误处理:对未知 Tool 抛出明确错误
  3. 模拟数据:实际开发中替换为真实天气 API(如 OpenWeatherMap)
  4. 启动方式:使用 stdio 传输,便于与各种 Client 集成

第四部分:实战二:将 Server 集成到 AI 应用 (Client)

4.1 集成到 Claude Desktop

  • 配置 Claude Desktop 的 claude_desktop_config.json
  • 验证工具调用与资源读取

4.2 集成到 Cursor / Windsurf

  • 配置 IDE 的 MCP 设置
  • 体验在编码中直接调用自定义工具

4.3 构建一个简单的自定义 Client

以下是一个完整的自定义 MCP Client 示例,可以连接任意 MCP Server 并调用其工具:

typescript 复制代码
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
import { spawn } from "child_process";
import readline from "readline";

class MCPClient {
  private client: Client;
  private transport: StdioClientTransport;
  private serverProcess: ReturnType<typeof spawn>;

  constructor(serverCommand: string, serverArgs: string[] = []) {
    this.client = new Client(
      {
        name: "custom-mcp-client",
        version: "1.0.0",
      },
      {
        capabilities: {},
      }
    );

    // 启动 Server 进程
    this.serverProcess = spawn(serverCommand, serverArgs, {
      stdio: ["pipe", "pipe", "pipe"],
    });

    // 创建传输层
    this.transport = new StdioClientTransport(
      this.serverProcess.stdout!,
      this.serverProcess.stdin!
    );

    // 错误处理
    this.serverProcess.stderr?.on("data", (data) => {
      console.error(`[Server Error] ${data.toString()}`);
    });

    this.serverProcess.on("close", (code) => {
      console.log(`Server 进程退出,代码: ${code}`);
    });
  }

  async connect(): Promise<void> {
    await this.client.connect(this.transport);
    console.log("✅ 已连接到 MCP Server");
  }

  async listTools(): Promise<any[]> {
    try {
      const result = await this.client.request({
        method: "tools/list",
        params: {},
      });
      return result.tools || [];
    } catch (error) {
      console.error("获取工具列表失败:", error);
      return [];
    }
  }

  async listResources(): Promise<any[]> {
    try {
      const result = await this.client.request({
        method: "resources/list",
        params: {},
      });
      return result.resources || [];
    } catch (error) {
      console.error("获取资源列表失败:", error);
      return [];
    }
  }

  async callTool(toolName: string, arguments_: Record<string, any>): Promise<any> {
    try {
      const result = await this.client.request({
        method: "tools/call",
        params: {
          name: toolName,
          arguments: arguments_,
        },
      });
      return result;
    } catch (error) {
      console.error(`调用工具 ${toolName} 失败:`, error);
      throw error;
    }
  }

  async readResource(uri: string): Promise<string> {
    try {
      const result = await this.client.request({
        method: "resources/read",
        params: { uri },
      });
      // 假设返回的是文本内容
      return result.contents?.[0]?.text || "";
    } catch (error) {
      console.error(`读取资源 ${uri} 失败:`, error);
      throw error;
    }
  }

  async disconnect(): Promise<void> {
    await this.client.close();
    this.serverProcess.kill();
    console.log("已断开连接并停止 Server 进程");
  }
}

// 使用示例
async function main() {
  // 创建 Client 并连接到天气查询 Server
  const client = new MCPClient("node", ["weather-server.js"]);
  
  try {
    // 连接 Server
    await client.connect();
    
    // 列出可用工具
    const tools = await client.listTools();
    console.log("可用工具:", tools.map(t => t.name).join(", "));
    
    // 列出可用资源
    const resources = await client.listResources();
    console.log("可用资源:", resources.map(r => r.name).join(", "));
    
    // 调用天气查询工具
    if (tools.some(t => t.name === "get_weather")) {
      const weatherResult = await client.callTool("get_weather", {
        city: "Beijing",
        unit: "celsius"
      });
      console.log("天气查询结果:", weatherResult);
    }
    
    // 读取资源(如果有)
    if (resources.length > 0) {
      const resourceContent = await client.readResource(resources[0].uri);
      console.log("资源内容预览:", resourceContent.substring(0, 200) + "...");
    }
    
    // 交互式工具调用示例
    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout
    });
    
    rl.question("请输入要查询的城市: ", async (city) => {
      try {
        const result = await client.callTool("get_weather", { city });
        console.log(`\n${city} 的天气信息:`);
        console.log(JSON.stringify(result, null, 2));
      } catch (error) {
        console.error("查询失败:", error);
      } finally {
        rl.close();
        await client.disconnect();
      }
    });
    
  } catch (error) {
    console.error("Client 运行失败:", error);
    await client.disconnect();
  }
}

// 启动 Client
if (require.main === module) {
  main().catch(console.error);
}

代码要点:

  1. 完整的 MCP Client 实现:封装了连接、工具调用、资源读取等核心功能
  2. 错误处理:每个操作都有 try-catch 包装,提供友好的错误提示
  3. 交互式界面:支持命令行交互,方便测试和演示
  4. 类型安全:使用 TypeScript 确保类型正确性
  5. 进程管理:自动启动和停止 Server 进程,简化测试流程

使用方式:

bash 复制代码
# 安装依赖
npm install @modelcontextprotocol/sdk

# 编译 TypeScript
npx tsc client.ts --outDir dist --module commonjs --target es2020

# 运行 Client
node dist/client.js

这个自定义 Client 可以:

  • 连接任何实现了 MCP 协议的 Server
  • 动态发现 Server 提供的工具和资源
  • 调用工具并处理结果
  • 读取资源内容
  • 提供简单的命令行交互界面

5.1 性能优化

性能优化是构建生产级 MCP Server 的关键环节。以下从缓存策略、并行处理、资源管理三个维度提供优化方案。

缓存策略对比
策略类型 适用场景 优点 缺点 实现复杂度
内存缓存 高频读取、数据量小、变化不频繁 访问速度快、实现简单 内存占用高、重启丢失数据 低
Redis 缓存 分布式环境、多实例共享 支持分布式、持久化、高可用 需要额外基础设施、网络延迟 中
CDN 缓存 静态资源、全球分发 全球加速、减轻源站压力 不适合动态数据、配置复杂 高
数据库查询缓存 复杂查询、结果集稳定 减少数据库压力、提升响应速度 数据一致性维护复杂 中
HTTP 缓存 API 响应、客户端缓存 减少网络传输、客户端复用 需要客户端支持、缓存失效策略 低
缓存实现示例
typescript 复制代码
import { LRUCache } from "lru-cache";
import Redis from "ioredis";

// 内存缓存实现
class MemoryCache {
  private cache: LRUCache<string, any>;
  
  constructor(maxSize: number = 100, ttl: number = 5 * 60 * 1000) {
    this.cache = new LRUCache({
      max: maxSize,
      ttl: ttl,
      updateAgeOnGet: true,
    });
  }
  
  async getOrLoad(key: string, loader: () => Promise<any>): Promise<any> {
    const cached = this.cache.get(key);
    if (cached !== undefined) {
      console.log(`内存缓存命中: ${key}`);
      return cached;
    }
    
    const data = await loader();
    this.cache.set(key, data);
    return data;
  }
  
  invalidate(key: string): void {
    this.cache.delete(key);
  }
}

// Redis 缓存实现
class RedisCache {
  private redis: Redis;
  private prefix: string;
  
  constructor(redisUrl: string, prefix: string = "mcp:") {
    this.redis = new Redis(redisUrl);
    this.prefix = prefix;
  }
  
  async getOrLoad(key: string, loader: () => Promise<any>, ttl: number = 300): Promise<any> {
    const cacheKey = `${this.prefix}${key}`;
    
    // 尝试从 Redis 获取
    const cached = await this.redis.get(cacheKey);
    if (cached) {
      console.log(`Redis 缓存命中: ${key}`);
      return JSON.parse(cached);
    }
    
    // 加载数据并缓存
    const data = await loader();
    await this.redis.setex(cacheKey, ttl, JSON.stringify(data));
    return data;
  }
  
  async invalidate(key: string): Promise<void> {
    await this.redis.del(`${this.prefix}${key}`);
  }
}

// 分层缓存策略:内存 + Redis
class LayeredCache {
  private memoryCache: MemoryCache;
  private redisCache: RedisCache;
  
  constructor(redisUrl?: string) {
    this.memoryCache = new MemoryCache(1000, 60 * 1000); // 1分钟内存缓存
    this.redisCache = redisUrl ? new RedisCache(redisUrl) : null;
  }
  
  async getOrLoad(key: string, loader: () => Promise<any>): Promise<any> {
    // 1. 尝试内存缓存
    try {
      const memoryData = await this.memoryCache.getOrLoad(key, async () => {
        // 2. 尝试 Redis 缓存
        if (this.redisCache) {
          return this.redisCache.getOrLoad(key, loader, 10 * 60); // 10分钟Redis缓存
        }
        // 3. 最终从源加载
        return loader();
      });
      return memoryData;
    } catch (error) {
      console.error(`缓存获取失败 ${key}:`, error);
      return loader(); // 降级到直接加载
    }
  }
}
并行处理优化
typescript 复制代码
// 并行工具调用示例
import { CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";

// 定义工具执行器
class ParallelToolExecutor {
  private maxConcurrent: number;
  private activeTasks: Set<Promise<any>>;
  
  constructor(maxConcurrent: number = 5) {
    this.maxConcurrent = maxConcurrent;
    this.activeTasks = new Set();
  }
  
  async executeTools(toolCalls: Array<{name: string, args: any}>): Promise<any[]> {
    const results: any[] = [];
    const batches = this.chunkArray(toolCalls, this.maxConcurrent);
    
    for (const batch of batches) {
      const batchPromises = batch.map(({name, args}) => 
        this.executeTool(name, args).finally(() => {
          this.activeTasks.delete(Promise.resolve());
        })
      );
      
      const batchResults = await Promise.allSettled(batchPromises);
      results.push(...batchResults.map(result => 
        result.status === 'fulfilled' ? result.value : { error: result.reason }
      ));
    }
    
    return results;
  }
  
  private async executeTool(name: string, args: any): Promise<any> {
    // 模拟工具执行
    await new Promise(resolve => setTimeout(resolve, Math.random() * 1000));
    return { tool: name, result: `执行 ${name} 成功`, args };
  }
  
  private chunkArray<T>(array: T[], size: number): T[][] {
    const chunks: T[][] = [];
    for (let i = 0; i < array.length; i += size) {
      chunks.push(array.slice(i, i + size));
    }
    return chunks;
  }
}

// 在 Server 中使用并行执行器
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;
  
  // 如果是批量工具调用请求
  if (name === "batch_execute") {
    const toolCalls = args.tools as Array<{name: string, args: any}>;
    const executor = new ParallelToolExecutor(3); // 最大并发3
    const results = await executor.executeTools(toolCalls);
    
    return {
      content: [{
        type: "text",
        text: JSON.stringify({ results }, null, 2),
      }],
    };
  }
  
  // 单个工具调用
  // ... 原有处理逻辑
});
性能监控指标
typescript 复制代码
// 性能监控装饰器
function measurePerformance(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  
  descriptor.value = async function(...args: any[]) {
    const startTime = performance.now();
    const startMemory = process.memoryUsage().heapUsed;
    
    try {
      const result = await originalMethod.apply(this, args);
      const endTime = performance.now();
      const endMemory = process.memoryUsage().heapUsed;
      
      const duration = endTime - startTime;
      const memoryUsed = endMemory - startMemory;
      
      console.log(`[性能监控] ${propertyKey} - 耗时: ${duration.toFixed(2)}ms, 内存变化: ${(memoryUsed / 1024 / 1024).toFixed(2)}MB`);
      
      // 可以发送到监控系统
      if (duration > 1000) {
        console.warn(`[性能警告] ${propertyKey} 执行时间过长: ${duration.toFixed(2)}ms`);
      }
      
      return result;
    } catch (error) {
      const endTime = performance.now();
      console.error(`[性能监控] ${propertyKey} - 执行失败, 耗时: ${(endTime - startTime).toFixed(2)}ms`, error);
      throw error;
    }
  };
  
  return descriptor;
}

// 在工具处理函数上使用
class WeatherService {
  @measurePerformance
  async getWeather(city: string): Promise<any> {
    // 模拟 API 调用
    await new Promise(resolve => setTimeout(resolve, 500));
    return { city, temperature: "25°C", condition: "晴朗" };
  }
}
资源懒加载策略
typescript 复制代码
// 懒加载管理器
class LazyResourceManager {
  private loadedResources: Map<string, any> = new Map();
  private loadingPromises: Map<string, Promise<any>> = new Map();
  
  async getResource(uri: string, loader: () => Promise<any>): Promise<any> {
    // 检查是否已加载
    if (this.loadedResources.has(uri)) {
      return this.loadedResources.get(uri);
    }
    
    // 检查是否正在加载
    if (this.loadingPromises.has(uri)) {
      return this.loadingPromises.get(uri);
    }
    
    // 开始加载
    const loadPromise = loader().then(data => {
      this.loadedResources.set(uri, data);
      this.loadingPromises.delete(uri);
      return data;
    }).catch(error => {
      this.loadingPromises.delete(uri);
      throw error;
    });
    
    this.loadingPromises.set(uri, loadPromise);
    return loadPromise;
  }
  
  preloadResources(uris: string[], loader: (uri: string) => Promise<any>): void {
    uris.forEach(uri => {
      if (!this.loadedResources.has(uri) && !this.loadingPromises.has(uri)) {
        this.getResource(uri, () => loader(uri)).catch(console.error);
      }
    });
  }
  
  clearCache(): void {
    this.loadedResources.clear();
    this.loadingPromises.clear();
  }
}

// 使用示例
const resourceManager = new LazyResourceManager();

server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  const uri = request.params.uri;
  
  const data = await resourceManager.getResource(uri, async () => {
    // 实际加载资源的逻辑
    console.log(`懒加载资源: ${uri}`);
    await new Promise(resolve => setTimeout(resolve, 1000)); // 模拟耗时操作
    
    return {
      content: `资源内容: ${uri}`,
      loadedAt: new Date().toISOString(),
    };
  });
  
  return {
    contents: [{
      uri,
      mimeType: "application/json",
      text: JSON.stringify(data, null, 2),
    }],
  };
});

// 预热常用资源
resourceManager.preloadResources([
  "resource:///common/config",
  "resource:///system/status",
], async (uri) => {
  // 预热加载逻辑
  return { uri, preloaded: true, timestamp: new Date().toISOString() };
});
性能优化最佳实践
  1. 缓存策略选择

    • 根据数据访问频率选择缓存层级
    • 设置合理的 TTL(生存时间)
    • 实现缓存穿透保护
  2. 并发控制

    • 限制最大并发数,防止资源耗尽
    • 使用连接池管理数据库连接
    • 实现请求队列和限流
  3. 监控与告警

    • 监控响应时间、错误率、吞吐量
    • 设置性能阈值告警
    • 定期进行性能压测
  4. 资源管理

    • 及时释放不再使用的资源
    • 使用连接池复用资源
    • 监控内存泄漏
  5. 代码优化

    • 避免不必要的 JSON 序列化/反序列化
    • 使用流式处理大文件
    • 优化数据库查询语句

第五部分:高级主题与最佳实践

5.2 安全加固

  • 权限模型设计(工具黑白名单)
  • 输入验证与沙箱执行

5.3 可观测性与监控

  • 集成 OpenTelemetry
  • 关键指标收集(调用量、延迟、错误率)

5.4 部署与运维

  • 容器化部署 (Docker)
  • 配置管理(环境变量、密钥管理)
  • 版本升级与回滚策略

5.5 部署配置示例:Docker + 环境变量管理

Dockerfile 配置示例
dockerfile 复制代码
# 使用 Node.js 20 作为基础镜像
FROM node:20-alpine AS builder

# 设置工作目录
WORKDIR /app

# 复制 package 文件
COPY package*.json ./
COPY tsconfig.json ./

# 安装依赖
RUN npm ci --only=production

# 复制源代码
COPY src/ ./src/

# 构建 TypeScript
RUN npm run build

# 生产阶段
FROM node:20-alpine

WORKDIR /app

# 复制构建产物和依赖
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist

# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S mcp -u 1001

# 切换用户
USER mcp

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3000/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1) })"

# 暴露端口(如果使用 HTTP 传输)
EXPOSE 3000

# 启动命令
CMD ["node", "dist/index.js"]
docker-compose.yml 配置示例
yaml 复制代码
version: '3.8'

services:
  mcp-server:
    build: .
    container_name: mcp-weather-server
    restart: unless-stopped
    environment:
      - NODE_ENV=production
      - LOG_LEVEL=info
      - WEATHER_API_KEY=${WEATHER_API_KEY}
      - REDIS_URL=${REDIS_URL:-redis://redis:6379}
      - PORT=3000
    ports:
      - "3000:3000"
    volumes:
      - ./config:/app/config:ro
      - ./logs:/app/logs
    healthcheck:
      test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1) })"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    networks:
      - mcp-network

  redis:
    image: redis:7-alpine
    container_name: mcp-redis
    restart: unless-stopped
    command: redis-server --appendonly yes
    volumes:
      - redis-data:/data
    networks:
      - mcp-network

networks:
  mcp-network:
    driver: bridge

volumes:
  redis-data:
环境变量配置 (.env.example)
env 复制代码
# 应用配置
NODE_ENV=production
LOG_LEVEL=info
PORT=3000

# 第三方服务
WEATHER_API_KEY=your_openweathermap_api_key_here
REDIS_URL=redis://redis:6379

# 安全配置
API_RATE_LIMIT=100
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173

# MCP 特定配置
MCP_SERVER_NAME=weather-server
MCP_SERVER_VERSION=1.0.0
MCP_MAX_CONNECTIONS=10
Kubernetes Deployment 示例片段
yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mcp-weather-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mcp-weather-server
  template:
    metadata:
      labels:
        app: mcp-weather-server
    spec:
      containers:
      - name: server
        image: your-registry/mcp-weather-server:latest
        ports:
        - containerPort: 3000
        envFrom:
        - configMapRef:
            name: mcp-server-config
        - secretRef:
            name: mcp-server-secrets
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5

部署最佳实践:

  1. 配置分离:敏感信息(API Key)通过 Secret 管理
  2. 健康检查:确保服务可用性
  3. 资源限制:防止内存泄漏影响主机
  4. 日志收集:挂载 volume 持久化日志
  5. 多环境:区分 dev/staging/production 配置

第六部分:生态与未来展望

6.1 现有生态概览

  • 官方与社区 Server 列表
  • 主流 Client 支持情况

6.2 扩展协议:自定义传输与认证

  • 实现 SSE (Server-Sent Events) 以外的传输层
  • 添加 OAuth 等认证机制

6.3 MCP 在 AI Agent 架构中的位置

  • 与编排框架(LangGraph, CrewAI)的结合
  • 构建企业级 Agent 工具平台

术语对照表

英文术语 中文翻译 说明
Model Context Protocol (MCP) 模型上下文协议 Anthropic 提出的标准化协议,用于连接 AI 模型与外部工具/数据
Server 服务器 提供 Tools、Resources、Prompts 等能力的服务端组件
Client 客户端 连接 MCP Server 的 AI 应用(如 Claude Desktop、Cursor)
Tool 工具 可被 AI 模型调用的函数,用于执行特定操作
Resource 资源 可被 AI 模型读取的结构化数据源
Prompt 提示词模板 预定义的提示词模板,可动态注入上下文
Transport 传输层 Server 与 Client 之间的通信方式(stdio、SSE、HTTP)
Inspector 检查器 用于调试和监控 MCP 协议通信的工具
Capabilities 能力声明 Server 声明支持的功能集合
Schema 模式/架构 定义数据结构(如 Tool 的输入参数格式)
Stdio 标准输入输出 通过进程的标准输入输出进行通信
SSE (Server-Sent Events) 服务器发送事件 一种 HTTP 长连接通信协议
OpenTelemetry 开放遥测 用于收集应用指标、日志和追踪的开源框架
OAuth 开放授权 行业标准的授权协议
JSON-RPC JSON 远程过程调用 MCP 底层使用的通信协议
Sandbox 沙箱 隔离的执行环境,增强安全性
Orchestration 编排 协调多个 AI Agent 或工具的工作流程

常见缩写:

  • MCP: Model Context Protocol
  • API: Application Programming Interface
  • SDK: Software Development Kit
  • CLI: Command Line Interface
  • IDE: Integrated Development Environment
  • HTTP: Hypertext Transfer Protocol
  • JSON: JavaScript Object Notation
  • RPC: Remote Procedure Call
  • SSE: Server-Sent Events
  • OTel: OpenTelemetry

相关技术栈:

  • TypeScript/JavaScript: MCP SDK 主要语言
  • Python: 另一种常用的 MCP 开发语言
  • Docker: 容器化部署
  • Kubernetes: 容器编排
  • Redis: 缓存和数据存储
  • PostgreSQL: 关系型数据库
  • OpenAI API: 大模型接口(可与 MCP 结合使用)
  • LangChain: AI 应用开发框架(与 MCP 互补)

总结与下一步

  • 回顾从零搭建的关键步骤
  • 项目源码仓库与参考链接
  • 鼓励读者动手实践并反馈
相关推荐
Sayai1 小时前
ComfyUI+混元视频实战:12G 显存跑 13G 模型,5 分钟出片(国产开源,附模型与工作流)
人工智能·aigc·音视频·comfyui·hunyuanvideo·混元视频
燧机科技SuiJi1 小时前
山体坍塌落石滑坡泥石流监测系统 落石泥石流监控摄像机
大数据·人工智能·深度学习·yolo
国科安芯1 小时前
立方星与微纳卫星综合电子微型化趋势下的抗辐射MCU选型综述
人工智能·单片机·嵌入式硬件·mcu·risc-v·抗辐射
诸神缄默不语2 小时前
小春学习日刊 2026年第4期:2026.10.16
人工智能
draracle2 小时前
为什么 AI 无法胜任系统架构
人工智能·系统架构
未来和明天2 小时前
iLeadE-3403边缘计算网关10.4 TOPS数据采集、视频接入与外设扩展等多元化应用需求
人工智能·边缘计算
youngfengying3 小时前
集成学习及置信度
人工智能·机器学习
火山引擎开发者社区3 小时前
1000次专业数据集调用,这次我们免费送!
人工智能