Model Context Protocol (MCP) 技术分享

目录

什么是 MCP

Model Context Protocol (MCP) 是由 Anthropic 开发的开源标准协议,旨在为大模型应用提供安全、标准化的外部工具连接方式。

核心价值:统一工具调用标准,避免重复实现,提升开发效率。

背景与痛点

大模型应用开发面临的挑战

在 MCP 出现以前,每个大模型应用都要自己实现方法以获取外部数据。

graph TD
    subgraph "传统模式 - 重复实现"
        subgraph "自定义大模型应用"
            C1[Custom App] --> C2[重复实现天气API]
            C1 --> C3[重复实现数据库连接]
            C1 --> C4[重复实现文件系统]
        end
        
        subgraph "Claude 应用"
            B1[Claude App] --> B2[重复实现天气API]
            B1 --> B3[重复实现数据库连接]
            B1 --> B4[重复实现文件系统]
        end
        
        subgraph "OpenAI 应用"
            A1[OpenAI Chat App] --> A2[重复实现天气API]
            A1 --> A3[重复实现数据库连接]
            A1 --> A4[重复实现文件系统]
        end
    end
    
    style A2 fill:#ffcdd2
    style A3 fill:#ffcdd2
    style A4 fill:#ffcdd2
    style B2 fill:#ffcdd2
    style B3 fill:#ffcdd2
    style B4 fill:#ffcdd2
    style C2 fill:#ffcdd2
    style C3 fill:#ffcdd2
    style C4 fill:#ffcdd2

场景举例

假如你正在开发一个大模型聊天应用,当用户询问天气时,你希望能通过某些方法获取到真实的天气信息,再交给大模型来回答。

如果你选择了 OpenAI:

// OpenAI Function Call 示例

const functions = [
  {
    name: "get_weather",
    description: "获取指定城市的天气信息",
    parameters: {
      type: "object",
      properties: {
        city: { type: "string", description: "城市名称" }
      },
      required: ["city"]
    }
  }
  // 其它功能
  // {...}
];

// get_weather 功能实现函数
async function get_weather(city: string) {
  const response = await fetch(`https://api.weather.com/v1/current?key=${API_KEY}&q=${city}`);
  return response.json();
}

// 其它功能
// async function ...

// GPT 调用流程
const response = await openai.chat.completions.create({
  model: "gpt-4",
  messages: [{ role: "user", content: "上海今天天气怎么样?" }],
  functions: functions,
  function_call: "auto"
});

// 如果 GPT 决定调用函数
if (response.choices[0].message.function_call) {
  // get_weather
  const functionName = response.choices[0].message.function_call.name;
  // { city: '上海' }
  const functionArgs = JSON.parse(response.choices[0].message.function_call.arguments);
  
  // 手动分发调用对应的函数,获取结果
  let functionResult;
  switch (functionName) {
    case "get_weather":
      functionResult = await get_weather(functionArgs.city);
      break;
    // 需要为每个函数写 case...
  }

  // 后续再次进入 GPT 调用流程,把 functionResult 通过 messages 传递给大模型
}

假如另一个开发者 B 和你有同样的想法,那 get_weather 定义和函数实现就要由开发者 B 自己再实现一次。

假如另一个开发者 C 和你有同样的想法,但他选择了 Anthropic:

// Anthropic Tool Call 示例

const tools = [
  {
    name: "get_weather",
    description: "获取指定城市的天气信息",
    input_schema: {
      type: "object",
      properties: {
        city: {
          type: "string",
          description: "城市名称"
        }
      },
      required: ["city"]
    }
  }
];

// get_weather 功能实现函数
async function get_weather(city: string) {
  const response = await fetch(`https://api.weather.com/v1/current?key=${API_KEY}&q=${city}`);
  return response.json();
}

// Claude API 调用流程
const response = await anthropic.messages.create({
  model: "claude-3-5-sonnet-20241022",
  tools: tools,
  messages: [
    { role: "user", content: "上海今天天气怎么样?" }
  ]
});

// 处理 Claude 的工具调用
for (const content of response.content) {
  if (content.type === "tool_use") {
    const toolName = content.name;
    const toolInput = content.input;
    
    // 手动分发调用对应的函数,获取结果
    let toolResult;
    switch (toolName) {
      case "get_weather":
        toolResult = await get_weather(toolInput.city);
        break;
      // 需要为每个工具写 case...
    }

    // 后续再次进入 Claude 调用流程,把 functionResult 通过 messages 传递给大模型

Function Call / Tool Call 流程总结:

可以发现大部分流程基本都是一样的,但是每个应用都要重复实现 get_weather 函数功能。

sequenceDiagram
    participant User as 用户
    participant AI as 大模型应用
    participant Func as 函数实现
    participant API as 外部 API
    
    User->>AI: "上海今天天气怎么样?"
    AI->>AI: 分析需要调用 get_weather 函数
    Note over AI: 每个应用都要自己定义实现函数功能
    AI->>Func: 调用 get_weather()
    Func->>API: HTTP 请求 /api/getWeather
    API->>Func: 返回 API 数据
    Func->>AI: 格式化后的数据
    AI->>User: "今日上海天气如下: ..."

问题小结

MCP 解决方案

统一架构

MCP 三个架构要素:

MCP 采用经典 C/S 架构:MCP Server 提供工具实现,大模型应用通过 MCP Client 连接获取工具。

graph TD
    subgraph "MCP 统一架构模式"
        subgraph "大模型应用"
            A1[OpenAI App]
            A2[Claude App]
            A3[Gemini App]
            A4[Custom AI App]
            A5[New AI App]
        end
        
        subgraph "MCP Client"
            B1[统一 MCP 协议]
        end
        
        subgraph "MCP Server"
            C1[天气 MCP 服务器]
            C2[ModelWhale MCP 服务器]
            C3[GitHub MCP 服务器]
            C4[数据库 MCP 服务器]
            C5[文件系统 MCP 服务器]
        end
        
        A1 --> B1
        A2 --> B1
        A3 --> B1
        A4 --> B1
        A5 --> B1
        
        B1 --> C1
        B1 --> C2
        B1 --> C3
        B1 --> C4
        B1 --> C5
    end
    
    style B1 fill:#c8e6c9
    style C1 fill:#e3f2fd
    style C2 fill:#e3f2fd
    style C3 fill:#e3f2fd
    style C4 fill:#e3f2fd
    style C5 fill:#e3f2fd

统一通信消息协议

MCP Client 和 MCP Server 间约定使用 JSON-RPC 2.0 协议进行结构化通信。JSON-RPC 2.0 是一种轻量级的远程过程调用(RPC)协议,使用 JSON 作为编码格式。该协议设计简单,不依赖于特定的传输协议(HTTP/TCP/进程/管道等等)。

sequenceDiagram
    participant AI as 大模型应用(MCP Client)
    participant MCP as MCP Server
    
    Note over AI,MCP: JSON-RPC 2.0 协议交换
    
    AI->>MCP: {"jsonrpc":"2.0","method":"initialize","params":{...},"id":1}
    MCP->>AI: {"jsonrpc":"2.0","result":{"capabilities":{...}},"id":1}
    
    AI->>MCP: {"jsonrpc":"2.0","method":"tools/list","id":2}
    MCP->>AI: {"jsonrpc":"2.0","result":{"tools":[...]},"id":2}
    
    AI->>MCP: {"jsonrpc":"2.0","method":"tools/call","params":{"name":"get-weather","arguments":{...}},"id":3}
    MCP->>AI: {"jsonrpc":"2.0","result":{"content":[...]},"id":3}

统一传输协议

graph TD
    subgraph "MCP 传输层统一标准"
        A[MCP JSON-RPC 2.0 协议]
        
        A --> B1[Stdio Transport]
        A --> B2[SSE Transport]
        A --> B3[StreamableHTTP Transport⭐️]
        
        B1 --> C1[本地应用<br/>命令行工具<br/>桌面应用]
        B2 --> C2[Web 应用<br/>实时流式需求]
        B3 --> C3[现代化 Web 应用<br/>兼容流式需求和 JSON 返回]
    end
    
    style A fill:#4caf50
    style B1 fill:#e3f2fd
    style B2 fill:#e3f2fd
    style B3 fill:#e3f2fd

MCP Client 简单示例

核心优势:所有大模型应用共享统一的连接和调用方式。

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';

// 🎯 统一的 MCP 基础类
class BaseMCPApp {
  protected mcpClient: Client;
  
  async initialize() {
    this.mcpClient = new Client({ name: 'ai-app', version: '1.0.0' });
    const transport = new StreamableHTTPClientTransport('https://api.example.com/mcp');
    await this.mcpClient.connect(transport);
  }
  
  // 统一工具调用接口 - 所有平台复用
  async callTool(toolName: string, args: any) {
    return await this.mcpClient.callTool(toolName, args);
  }
  
  async getTools() {
    const { tools } = await this.mcpClient.listTools();
    return tools;
  }
}

// 🤖 OpenAI 应用实现
class OpenAIMCPApp extends BaseMCPApp {
  async processMessage(userMessage: string) {
    const tools = await this.getTools();
    
    // 只需转换格式,无需实现工具逻辑
    const openaiTools = tools.map(tool => ({
      name: tool.name,
      description: tool.description,
      parameters: tool.inputSchema
    }));
    
    const response = await openai.chat.completions.create({
      model: "gpt-4",
      messages: [{ role: "user", content: userMessage }],
      functions: openaiTools
    });
    
    if (response.choices[0].message.function_call) {
      const { name, arguments: args } = response.choices[0].message.function_call;
      // 统一调用方式
      const result = await this.callTool(name, JSON.parse(args));
      return result.content[0].text;
    }
  }
}

// 🎭 Claude 应用实现
class ClaudeMCPApp extends BaseMCPApp {
  async processMessage(userMessage: string) {
    const tools = await this.getTools();
    
    // 只需转换格式,无需实现工具逻辑
    const claudeTools = tools.map(tool => ({
      name: tool.name,
      description: tool.description,
      input_schema: tool.inputSchema
    }));
    
    const response = await anthropic.messages.create({
      model: "claude-3-5-sonnet-20241022",
      tools: claudeTools,
      messages: [{ role: "user", content: userMessage }]
    });
    
    for (const content of response.content) {
      if (content.type === "tool_use") {
        // 统一调用方式
        const result = await this.callTool(content.name, content.input);
        return result.content[0].text;
      }
    }
  }
}

MCP Server 简单示例

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import express from 'express';
import { z } from 'zod';

const server = new McpServer({
  name: 'modelwhale-mcp-server',
  version: '1.0.0'
});

// 注册工具:获取项目列表
server.tool(
  'get-lab-list',
  '获取我的项目列表',
  {
    page: z.number().min(1).optional().default(1).describe('页码'),
    perPage: z.number().min(1).optional().default(10).describe('每页返回的项目数量')
  },
  async ({ page, perPage }) => {
    const params = new URLSearchParams({
      page: `${page}`,
      perPage: `${perPage}`,
    });

    const response = await fetch(`${MODELWHALE_BASE_URL}/api/user/labs?${params}`);
    const data = await response.json();

    return {
      content: data.data.map((v) => ({
        type: 'text',
        text: [
          `项目名称: ${v.Title}`,
          `项目描述: ${v.Description || ''}`,
          `更新时间: ${v.UpdateDate}`,
          `项目 ID: ${v._id}`
        ].join('\n'),
      })),
    };
  }
);

const app = express();
app.use(express.json());
app.all('/mcp', async (req, res) => {
  // 创建并连接 MCP Server
  const transport = new StreamableHTTPServerTransport({
    // ...
  });
  await server.connect(transport);
  // 处理请求
  await transport.handleRequest(req, res, req.body);
});

关键收益

大模型与 MCP 的完整调用流程

sequenceDiagram
    participant User as 用户
    participant AI as 大模型应用/MCP Client
    participant MCP as MCP Server
    participant API as 外部API/数据源
    
    Note over User,API: 1. 连接建立阶段
    AI->>MCP: initialize (协议版本、能力交换)
    MCP->>AI: initialized (服务器信息、支持的能力)
    AI->>MCP: tools/list (请求可用工具列表)
    MCP->>AI: 返回工具列表 (工具名称、描述、参数schema)
    
    Note over User,API: 2. 用户交互阶段
    User->>AI: "显示我的项目列表"
    AI->>AI: 分析用户意图,选择合适的工具
    
    Note over User,API: 3. 工具调用阶段
    AI->>MCP: tools/call (name: "get-lab-list", arguments: {})
    MCP->>MCP: 参数验证、权限检查
    MCP->>API: HTTP请求 /api/user/labs
    API->>MCP: 返回项目数据
    MCP->>MCP: 数据格式化、安全过滤
    MCP->>AI: 返回格式化的结果
    AI->>AI: 整合结果到对话上下文
    AI->>User: "您有以下项目:项目A、项目B..."
    
    Note over User,API: 4. 链式调用示例
    User->>AI: "分析一下我最近一个项目的 Notebook"
    AI->>MCP: tools/call (name: "get-lab-list", arguments: {})
    MCP->>API: HTTP请求 /api/user/labs
    API->>MCP: 返回项目列表数据
    MCP->>AI: 返回格式化的结果
    AI->>AI: 从上下文提取项目ID
    AI->>MCP: tools/call (name: "get-notebooks-from-lab", arguments: {"id": "xxx"})
    MCP->>API: HTTP请求 /api/notebooks?Lab=xxx
    API->>MCP: 返回 Notebook 数据
    MCP->>AI: 返回格式化的 Notebook 数据
    AI->>AI: 从上下文提取 Notebook ID
    AI->>MCP: tools/call (name: "get-notebook-ipynb", arguments: {"id": "xxx"})
    MCP->>API: HTTP请求 /api/notebooks/xxx/file
    API->>MCP: 返回 Notebook ipynb
    MCP->>AI: 返回格式化的 Notebook ipynb
    AI->>AI: 整合结果到对话上下文
    AI->>User: "该 Notebook 主要实现了..."

MCP 优势对比

1. 解决重复实现问题

传统方式:各自为政

graph TD
    subgraph "传统模式 - 重复实现"
        subgraph "OpenAI 应用"
            A1[OpenAI Chat App] --> A2[自建天气API]
            A1 --> A3[自建数据库连接]
            A1 --> A4[自建文件系统]
        end
        
        subgraph "Claude 应用"
            B1[Claude App] --> B2[重复实现天气API]
            B1 --> B3[重复实现数据库连接]
            B1 --> B4[重复实现文件系统]
        end
        
        subgraph "Gemini 应用"
            C1[Gemini App] --> C2[又一次实现天气API]
            C1 --> C3[又一次实现数据库连接]
            C1 --> C4[又一次实现文件系统]
        end
        
        subgraph "自定义 AI 应用"
            D1[Custom AI App] --> D2[再次实现天气API]
            D1 --> D3[再次实现数据库连接]
            D1 --> D4[再次实现文件系统]
        end
    end
    
    style A2 fill:#ffcdd2
    style A3 fill:#ffcdd2
    style A4 fill:#ffcdd2
    style B2 fill:#ffcdd2
    style B3 fill:#ffcdd2
    style B4 fill:#ffcdd2
    style C2 fill:#ffcdd2
    style C3 fill:#ffcdd2
    style C4 fill:#ffcdd2
    style D2 fill:#ffcdd2
    style D3 fill:#ffcdd2
    style D4 fill:#ffcdd2

MCP 方式:统一复用

graph TD
    subgraph "MCP 模式 - 统一实现"
        subgraph "AI 应用层"
            A1[OpenAI App]
            A2[Claude App]
            A3[Gemini App]
            A4[Custom AI App]
            A5[New AI App]
        end
        
        subgraph "MCP 协议层"
            B1[统一 MCP 协议]
        end
        
        subgraph "MCP 服务器层"
            C1[天气 MCP 服务器]
            C2[数据库 MCP 服务器]
            C3[文件系统 MCP 服务器]
            C4[ModelWhale MCP 服务器]
            C5[GitHub MCP 服务器]
        end
        
        A1 --> B1
        A2 --> B1
        A3 --> B1
        A4 --> B1
        A5 --> B1
        
        B1 --> C1
        B1 --> C2
        B1 --> C3
        B1 --> C4
        B1 --> C5
    end
    
    style B1 fill:#c8e6c9
    style C1 fill:#e3f2fd
    style C2 fill:#e3f2fd
    style C3 fill:#e3f2fd
    style C4 fill:#e3f2fd
    style C5 fill:#e3f2fd

2. 维护成本对比

flowchart TD
    subgraph "传统方式维护噩梦"
        A[API 变更/扩展] --> B{需要更新所有应用}
        B --> C[更新应用 A]
        B --> D[更新应用 B]
        B --> E[更新应用 C]
        B --> F[更新应用 D]
        
        C --> G[测试应用 A]
        D --> H[测试应用 B]
        E --> I[测试应用 C]
        F --> J[测试应用 D]
        
        G --> K[部署应用 A]
        H --> L[部署应用 B]
        I --> M[部署应用 C]
        J --> N[部署应用 D]
        
        style A fill:#ffcdd2
        style C fill:#ffcdd2
        style D fill:#ffcdd2
        style E fill:#ffcdd2
        style F fill:#ffcdd2
    end

    subgraph "MCP 方式简化维护"
        O[API 变更/扩展] --> P[更新 MCP 服务器]
        P --> Q[测试 MCP 服务器]
        Q --> R[部署 MCP 服务器]
        R --> S[所有应用自动获得更新]
        
        style O fill:#c8e6c9
        style P fill:#c8e6c9
        style Q fill:#c8e6c9
        style R fill:#c8e6c9
        style S fill:#c8e6c9
    end

4. 标准化优势

graph LR
    subgraph "传统方式 - 各自标准"
        A1[OpenAI Function Call] --> A2["{'name': 'get_weather', 'parameters': {...}}"]
        B1[Claude Tool Call] --> B2["{'name': 'get_weather', 'input_schema': {...}}"]
        C1[Gemini Function Call] --> C2["{'name': 'get_weather', 'schema': {...}}"]
    end
    
    subgraph "MCP 方式 - 统一标准"
        D1[所有 AI 应用] --> D2[MCP JSON-RPC 2.0]
        D2 --> D3["{'jsonrpc': '2.0', 'method': 'tools/call', 'params': {...}}"]
    end
    
    style A2 fill:#ffcdd2
    style B2 fill:#ffcdd2
    style C2 fill:#ffcdd2
    style D2 fill:#c8e6c9
    style D3 fill:#c8e6c9

5. 安全性提升

graph TD
    subgraph "传统方式安全风险"
        A1[AI 应用] --> A2[直接数据库连接]
        A1 --> A3[API 密钥硬编码]
        A1 --> A4[客户端执行敏感操作]
        
        A2 --> A5[SQL 注入风险]
        A3 --> A6[密钥泄露风险]
        A4 --> A7[权限失控风险]
        
        style A5 fill:#ffcdd2
        style A6 fill:#ffcdd2
        style A7 fill:#ffcdd2
    end
    
    subgraph "MCP 安全边界"
        B1[AI 应用] --> B2[MCP 协议]
        B2 --> B3[MCP 服务器]
        B3 --> B4[权限检查]
        B3 --> B5[参数验证]
        B3 --> B6[审计日志]
        
        B4 --> B7[受控的数据访问]
        B5 --> B8[安全的操作执行]
        B6 --> B9[完整的操作追踪]
        
        style B7 fill:#c8e6c9
        style B8 fill:#c8e6c9
        style B9 fill:#c8e6c9
    end

MCP 高级用法

权限分级控制

不同用户或应用可以有不同的工具访问权限:

async function checkPermission(toolName: string, userId: string) {
  const userRole = await getUserRole(userId);
  const requiredPermission = TOOL_PERMISSIONS[toolName];
  return hasPermission(userRole, requiredPermission);
}
server.tool(
  'admin-operation',
  '管理员操作',
  { action: z.string() },
  async ({ action }, context) => {
    const userId = context.userId;
    if (!await checkPermission('admin-operation', userId)) {
      throw new Error('权限不足');
    }
    return await executeAdminAction(action);
  }
);

缓存优化

对频繁调用的工具结果进行缓存:

const cache = new Map();

server.tool(
  'expensive-computation',
  '昂贵的计算操作',
  { input: z.string() },
  async ({ input }) => {
    const cacheKey = `compute_${hash(input)}`;
    if (cache.has(cacheKey)) {
      return cache.get(cacheKey);
    }
    const result = await performExpensiveComputation(input);
    cache.set(cacheKey, result);
    return result;
  }
);

流式处理

对于大量数据或长时间运行的任务,支持流式响应:

server.tool(
  'analyze-large-dataset',
  '分析大型数据集',
  { datasetId: z.string() },
  async function* ({ datasetId }) {
    const chunks = await getDatasetChunks(datasetId);
    
    for (const chunk of chunks) {
      const result = await processChunk(chunk);
      yield {
        content: [{
          type: 'text',
          text: `处理进度: ${result.progress}%\n结果: ${result.summary}`
        }]
      };
    }
  }
);

资源管理

除了工具调用,MCP 还支持资源管理,允许大模型访问文件、数据库记录等。

// 注册资源
server.resource(
  'file:///projects/{projectId}/files',
  '项目文件列表',
  async ({ projectId }) => {
    const files = await getProjectFiles(projectId);
    return {
      contents: files.map(file => ({
        uri: `file://${file.path}`,
        mimeType: 'text/plain',
        text: file.content
      }))
    };
  }
);

// 客户端读取资源
const resources = await mcpClient.readResource('file:///projects/123/files');

总结

MCP 正成为 AI 应用生态的重要基础设施,让开发者专注于 AI 应用的核心逻辑,而不必为每个外部数据读取重复实现代码。

MCP 的核心价值

适用场景


参考资料: