AI/ML Engineering

MCP 协议:AI 工具的 USB-C 时刻

深入解析 Model Context Protocol,Anthropic 推出的开放标准如何让 AI 应用像插 USB 一样连接数据源,并手把手教你构建第一个 MCP Server。

Ioodu · · Updated: Mar 15, 2026 · 20 min read
#MCP #AI Agent #Claude #Protocol #TypeScript

引言:AI 集成的痛点

过去两年,我们见证了 AI 应用的爆发。从 ChatGPT 到 Claude,从 Copilot 到 Cursor,AI 正在重塑软件开发的每一个环节。但一个根本问题始终困扰开发者:

如何让 AI 安全、标准化地访问我们的私有数据?

每个 SaaS 产品都有自己的 API,每个数据源都有不同的认证方式。我们要为 Slack、GitHub、Notion、数据库分别写适配器,维护成本极高。

这就像 1990 年代的电脑接口——每个设备都有独特的连接器,直到 USB 统一了这一切。

MCP:AI 的 USB-C 时刻

2024 年底,Anthropic 推出了 Model Context Protocol (MCP),一个开放标准,旨在解决 AI 与外部数据源集成的标准化问题。

什么是 MCP?

MCP 是一种客户端-服务器架构,让 AI 应用(客户端)能够通过统一协议连接到各种数据源(服务器)。

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   Claude App    │◄───►│  MCP Client     │◄───►│  MCP Servers    │
│   (Host)        │     │  (stdio/sse)    │     │  (Slack/GitHub/ │
│                 │     │                 │     │   Notion/DB)    │
└─────────────────┘     └─────────────────┘     └─────────────────┘

核心优势

  1. 标准化接口:一次实现,到处使用
  2. 类型安全:基于 JSON Schema 的强类型定义
  3. 双向通信:不仅 AI 可以读数据,还能执行操作
  4. 本地优先:敏感数据无需上传到云端
  5. 生态丰富:快速增长的社区服务器库

MCP 架构深度解析

协议层

MCP 基于 JSON-RPC 2.0,支持两种传输方式:

  • stdio:本地进程通信,适合桌面应用
  • SSE (Server-Sent Events):HTTP 流式通信,适合远程部署

核心能力

MCP 服务器可以暴露三种能力:

1. Resources(资源)

只读数据访问,类似 REST API 的 GET:

// 读取文件内容
{
  "uri": "file:///home/user/project/src/main.ts",
  "mimeType": "text/typescript",
  "text": "..."
}

2. Tools(工具)

可执行函数,AI 可以调用它们执行操作:

// Git 提交工具
{
  "name": "git_commit",
  "description": "提交更改到 Git 仓库",
  "inputSchema": {
    "type": "object",
    "properties": {
      "message": { "type": "string" }
    }
  }
}

3. Prompts(提示模板)

预定义的提示模板,标准化常见任务:

// 代码审查模板
{
  "name": "code_review",
  "description": "审查代码更改",
  "arguments": [
    { "name": "pr_number", "required": true }
  ]
}

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

让我们构建一个实用的 MCP Server:读取本地项目文件并执行 Git 操作。

项目初始化

mkdir mcp-git-server
cd mcp-git-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D @types/node typescript

Server 实现

创建 src/server.ts

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  ReadResourceRequestSchema,
  ListResourcesRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import { execSync } from "child_process";
import { readFileSync, existsSync } from "fs";
import { resolve } from "path";

// 工具定义
const GitCommitSchema = z.object({
  message: z.string().min(1),
  files: z.array(z.string()).optional(),
});

const ReadFileSchema = z.object({
  path: z.string(),
});

class GitMcpServer {
  private server: Server;

  constructor() {
    this.server = new Server(
      {
        name: "git-filesystem-server",
        version: "1.0.0",
      },
      {
        capabilities: {
          resources: {},
          tools: {},
        },
      }
    );

    this.setupHandlers();
  }

  private setupHandlers() {
    // 列出可用资源
    this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
      return {
        resources: [
          {
            uri: "file://README.md",
            name: "项目 README",
            mimeType: "text/markdown",
          },
        ],
      };
    });

    // 读取资源
    this.server.setRequestHandler(
      ReadResourceRequestSchema,
      async (request) => {
        const uri = request.params.uri;
        if (uri.startsWith("file://")) {
          const path = uri.replace("file://", "");
          if (existsSync(path)) {
            const content = readFileSync(path, "utf-8");
            return {
              contents: [
                {
                  uri,
                  mimeType: "text/plain",
                  text: content,
                },
              ],
            };
          }
        }
        throw new Error(`Resource not found: ${uri}`);
      }
    );

    // 列出可用工具
    this.server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: "git_status",
            description: "获取 Git 仓库当前状态",
            inputSchema: {
              type: "object",
              properties: {},
            },
          },
          {
            name: "git_commit",
            description: "提交更改到 Git 仓库",
            inputSchema: {
              type: "object",
              properties: {
                message: {
                  type: "string",
                  description: "提交信息",
                },
              },
              required: ["message"],
            },
          },
          {
            name: "read_file",
            description: "读取项目文件内容",
            inputSchema: {
              type: "object",
              properties: {
                path: {
                  type: "string",
                  description: "文件路径",
                },
              },
              required: ["path"],
            },
          },
        ],
      };
    });

    // 调用工具
    this.server.setRequestHandler(
      CallToolRequestSchema,
      async (request) => {
        const { name, arguments: args } = request.params;

        try {
          switch (name) {
            case "git_status": {
              const status = execSync("git status --short", {
                encoding: "utf-8",
              });
              return {
                content: [
                  {
                    type: "text",
                    text: status || "没有未提交的更改",
                  },
                ],
              };
            }

            case "git_commit": {
              const { message } = GitCommitSchema.parse(args);
              execSync('git add -A');
              execSync(`git commit -m "${message}"`);
              return {
                content: [
                  {
                    type: "text",
                    text: `✅ 成功提交: ${message}`,
                  },
                ],
              };
            }

            case "read_file": {
              const { path } = ReadFileSchema.parse(args);
              const fullPath = resolve(path);
              if (!existsSync(fullPath)) {
                throw new Error(`文件不存在: ${path}`);
              }
              const content = readFileSync(fullPath, "utf-8");
              return {
                content: [
                  {
                    type: "text",
                    text: content,
                  },
                ],
              };
            }

            default:
              throw new Error(`未知工具: ${name}`);
          }
        } catch (error) {
          return {
            content: [
              {
                type: "text",
                text: `❌ 错误: ${error.message}`,
              },
            ],
            isError: true,
          };
        }
      }
    );
  }

  async run() {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error("Git MCP Server 运行在 stdio 模式");
  }
}

// 启动服务器
const server = new GitMcpServer();
server.run().catch(console.error);

配置 Claude Desktop

编辑 ~/Library/Application Support/Claude/claude_desktop_config.json

{
  "mcpServers": {
    "git-filesystem": {
      "command": "node",
      "args": ["/path/to/mcp-git-server/dist/server.js"]
    }
  }
}

重启 Claude Desktop,你现在可以:

  • “帮我看看项目当前有哪些未提交的更改”
  • “读取 src/main.ts 文件内容”
  • “提交更改,信息是 ‘修复登录 bug‘“

生产环境考量

安全性

MCP Server 有强大的能力,必须谨慎使用:

// 1. 路径遍历防护
const sanitizePath = (inputPath: string): string => {
  const resolved = resolve(inputPath);
  const allowedRoot = resolve(process.env.PROJECT_ROOT || process.cwd());

  if (!resolved.startsWith(allowedRoot)) {
    throw new Error("访问被拒绝:超出允许目录");
  }
  return resolved;
};

// 2. 命令注入防护
const execSafe = (command: string, args: string[]): string => {
  // 验证参数,只允许白名单字符
  const validArg = /^[\w\-\/\.\s]+$/;
  for (const arg of args) {
    if (!validArg.test(arg)) {
      throw new Error("参数包含非法字符");
    }
  }
  return execSync(`${command} ${args.join(" ")}`, { encoding: "utf-8" });
};

错误处理

MCP 有标准化的错误响应:

{
  "jsonrpc": "2.0",
  "id": 123,
  "error": {
    "code": -32603,
    "message": "内部错误",
    "data": {
      "details": "数据库连接失败"
    }
  }
}

性能优化

  • 连接池:对数据库等资源使用连接池
  • 缓存:资源可以声明 annotations.ttl 实现客户端缓存
  • 流式传输:大文件使用 SSE 分块传输

MCP 生态系统现状

截至 2026 年初,MCP 生态已相当丰富:

官方服务器

  • Filesystem: 本地文件系统访问
  • SQLite: 数据库操作
  • Git: Git 仓库管理
  • Brave Search: 网络搜索

社区服务器

  • Slack: 消息读取和发送
  • Notion: 页面和数据库操作
  • GitHub: Issue、PR、代码管理
  • PostgreSQL: 数据库查询
  • Stripe: 支付数据访问

未来展望

MCP 正在快速演进,几个值得关注的方向:

  1. 认证标准化:OAuth 2.0 支持已在 roadmap
  2. 远程部署:更完善的云端托管方案
  3. 多模态:图像、音频等非文本资源支持
  4. Agent 编排:多个 MCP Server 协同工作的标准

总结

MCP 代表了 AI 集成的一个重要里程碑。就像 USB 统一了外设接口,MCP 有望统一 AI 与数据源的连接方式。

对于开发者来说,这意味着:

  • 更少样板代码:无需为每个数据源写适配器
  • 更好可维护性:标准化接口降低维护成本
  • 更强可移植性:一次实现,到处使用

对于用户来说,这意味着 AI 将能够:

  • 安全地访问你的所有数据
  • 在多个工具间无缝协作
  • 保持数据隐私(本地优先架构)

MCP 不是未来,而是现在。开始构建你的第一个 MCP Server 吧!


参考资源

本文示例代码已开源:github.com/yourusername/mcp-git-server

评论