菜鸟AI - 让提示词生成更简单! 全站导航 全站导航
AI工具安装 新手教程 进阶教程 辅助资源 AI提示词 热点资讯 技术资讯 产业资讯 内容生成 模型技术 AI信息库

已有账号?

首页 > AI创作与模型 > MCP协议权威指南:自建Server与Agent集成实战
模型技术

MCP协议权威指南:自建Server与Agent集成实战

2026-05-29
阅读 0
热度 0
作者 菜鸟AI编辑部
摘要

摘要

MCP协议是AI工具标准化通信标准,采用Host-Client-Server三层架构,支持Tools、Resources、Prompts三

MCP 完整指南:从协议理解到自建 Server 再到 Agent 集成

用三天时间,从零开始理解了 MCP 协议,动手构建了一个文件系统 MCP Server,最终将其集成到 AI Agent 中,让 LLM 通过标准化协议操作文件系统。这篇笔记,就是这次完整探索的总结。

MCP 完整指南:从协议理解到自建 Server 再到 Agent 集成

一、MCP 是什么?为什么需要它?

1.1 一个真实的痛点

回想一下,我们之前学习 Tool Calling 时,工具定义直接写死在应用代码里。天气查询工具写在 Agent A 中,Agent B 也想用?对不起,复制粘贴一份吧。CatDesk 用了 10 个工具,Cursor 也想用?再实现一遍。

这就是 MCP 出现之前的现状——每个 AI 应用各自为政地实现工具调用,同样的能力被重复造轮子。

1.2 MCP 的类比

MCP(Model Context Protocol)就是 AI 工具的 USB 标准。

想想看 USB 出现之前:打印机用并口、鼠标用 PS/2、扫描仪用 SCSI,每种设备需要专门的接口。USB 出现后,一个接口标准统一了所有外设。

MCP 做的是同样的事:

之前:
┌────────┐    ┌──────┐
│ App A  │───→│工具 1│  (私有接口)
└────────┘    └──────┘
┌────────┐    ┌──────┐
│ App B  │───→│工具 1│  (又实现一遍)
└────────┘    └──────┘

现在:
┌────────┐         ┌────────────┐
│CatDesk │──MCP──→│MCP Server A│  任何 Host 都能用任何 Server
│(Host)  │──MCP──→│MCP Server B│
└────────┘         └────────────┘
┌────────┐         ┌────────────┐
│ Cursor │──MCP──→│MCP Server A│  同一个 Server,多个 Host 复用
└────────┘         └────────────┘

1.3 协议核心定位

MCP 是 Anthropic 于 2024 年底发布的开放协议。它不是另一个 AI 框架,而是一个通信标准——定义了 AI 应用如何发现、连接、调用外部工具和数据源。

关键词:标准化、可发现、可复用、跨平台。

二、三层架构:Host → Client → Server

MCP 的架构像一个三明治,每层各司其职:

┌─────────────────────────────────────────────────────────┐
│  Host(宿主应用)                                        │
│  ├── 用户面对的 AI 应用(CatDesk、Claude Desktop、Cursor)│
│  ├── 负责 UI、对话管理、LLM 调用                         │
│  └── 内部包含一个或多个 Client                           │
│                                                         │
│  Client(客户端)                                        │
│  ├── 协议适配层,负责和 Server 通信                       │
│  ├── 每个 Client 对应一个 Server 连接                     │
│  └── 管理会话生命周期(connect / close)                  │
│                                                         │
│  Server(服务端)                                        │
│  ├── 能力提供者,暴露 Tools / Resources / Prompts        │
│  ├── 独立进程运行,通过 Transport 通信                    │
│  └── 可以是本地进程(stdio)或远端服务(HTTP)            │
└─────────────────────────────────────────────────────────┘

类比理解:

  • Host = 你的电脑操作系统
  • Client = USB 驱动程序
  • Server = USB 设备(键盘、鼠标、U 盘)

Host 不需要知道 Server 的内部实现细节,它只要通过 Client 说"你有什么能力?"、"帮我执行这个操作"——就像你不需要知道键盘的电路设计,只要插上 USB 就能用。

三、三种能力:Tools、Resources、Prompts

MCP Server 可以暴露三种不同类型的能力,它们的定位和使用方式各不相同。

3.1 Tools(工具)——"做什么"

Tools 是 LLM 主动调用的操作,类似 Function Calling 中的 function。

server.registerTool(
  "calculate",
  {
    description: "执行数学计算",
    inputSchema: {
      expression: z.string().describe("数学表达式,如 '2 + 3 * 4'"),
    },
  },
  async ({ expression }) => {
    const result = Function(`"use strict"; return (${expression})`)();
    return {
      content: [{ type: "text", text: `${expression} = ${result}` }],
    };
  }
);

关键特征:有副作用(可能修改状态)、由 LLM 决定何时调用、参数用 Zod Schema 定义(自动生成 JSON Schema 给 LLM 看)。

3.2 Resources(资源)——"读什么"

Resources 是 LLM 被动读取的数据源,用来提供上下文。

server.registerResource(
  "workspace-info",
  "file://workspace/info",
  { description: "项目概要信息", mimeType: "application/json" },
  async () => {
    return {
      contents: [{ uri: "file://workspace/info", text: JSON.stringify(info) }],
    };
  }
);

关键特征:无副作用(只读)、Host 可以在对话开始时自动注入、也支持动态 URI 模板(按路径读取不同文件)。

Tools vs Resources 的核心区别:

维度ToolsResources
触发方式LLM 主动调用Host 主动注入或 LLM 读取
副作用有(写文件、发请求)无(只读)
类比REST API 端点文件系统
使用场景执行操作提供上下文

3.3 Prompts(提示模板)——"怎么问"

Prompts 是 Server 预定义的提示模板,Host 获取后可直接发送给 LLM。

server.registerPrompt(
  "code-review",
  {
    description: "代码审查提示",
    argsSchema: {
      filepath: z.string().describe("文件路径"),
      focus: z.string().optional().describe("审查重点"),
    },
  },
  async ({ filepath, focus }) => {
    return {
      messages: [{
        role: "user",
        content: { type: "text", text: `请审查 ${filepath}...` },
      }],
    };
  }
);

用户在 CatDesk 中输入 /code-review 就能触发预制的高质量 Prompt,比让 LLM 自己临时组织更可控、更一致。

四、传输层:进程间如何通信

MCP 的传输层目前支持两种方式:

stdio(标准输入/输出): Server 作为 Host 的子进程启动,通过 stdin/stdout 交换 JSON-RPC 消息。最简单,零网络配置,适合本地开发和桌面应用。

Streamable HTTP: Server 是一个独立的 HTTP 服务。适合远程部署、多用户共享、生产环境。

选择依据很简单:本地用 stdio,远程用 HTTP。就像选择 USB 线还是 Wi-Fi 连接外设。

五、动手构建:文件系统 MCP Server

理论讲完,来看实战。这个实现包含一个完整的文件系统 MCP Server,它能让 LLM 在指定目录下安全地操作文件。

5.1 整体架构

file-server/
├── index.ts       ← 入口:创建 Server、注册能力、启动传输
├── tools.ts       ← 5 个文件操作工具
└── resources.ts   ← 3 个数据资源

5.2 安全第一:路径穿越防护

文件系统操作最怕的就是路径穿越攻击。如果用户让 LLM 读取 ../../../etc/passwd,Server 不做防护就会泄露系统文件。

解决方案是一个 resolveSafePath 函数:

function resolveSafePath(userPath: string, allowedRoot: string): string | null {
  const resolved = path.resolve(allowedRoot, userPath);
  // 解析后的路径必须在允许的根目录内
  if (!resolved.startsWith(allowedRoot + path.sep) && resolved !== allowedRoot) {
    return null; // 拒绝!
  }
  return resolved;
}

原理:path.resolve 会把 ../../../etc/passwd 解析为绝对路径,然后检查这个绝对路径是否以 allowedRoot 开头。如果不是,说明路径"越狱"了,直接拒绝。

每个 Tool 在执行前都先调用这个函数,确保操作不会逃出沙箱。

5.3 五个文件操作工具

Server 暴露了 5 个 Tools:

  • read_file:读取文件内容,带编码支持和大小限制(1MB)
  • write_file:写入文件,自动创建中间目录
  • list_directory:列出目录结构,支持递归和深度限制
  • search_files:按 glob 模式搜索文件(如 *.ts
  • get_file_info:获取文件元信息(大小、时间、权限)

每个工具都有完善的错误处理——不是直接抛异常,而是返回 isError: true + 友好错误信息。这让 LLM 有机会"看到"错误并自行调整策略,而不是整个流程崩溃。

5.4 动态资源模板

除了静态资源(项目信息、依赖列表),还实现了一个动态 URI 模板:

server.registerResource(
  "file-content",
  new ResourceTemplate("file://workspace/content/{+filepath}", { ... }),
  ...
);

{+filepath} 是 URI Template 语法,+ 表示可以匹配路径分隔符。这意味着 会自动提取 filepath = "src/index.ts" 并读取对应文件。

六、MCP Client 封装:桥接 MCP 与 AI SDK

Server 建好了,怎么让 Agent 用起来?关键挑战是格式转换——MCP Tools 用 JSON Schema 描述参数,AI SDK 用 Zod Schema。

6.1 McpClientManager 设计

const manager = new McpClientManager();
// 连接到 Server(自动发现能力)
await manager.connectToServer("file-server", {
  command: "npx",
  args: ["tsx", "file-server/index.ts", projectRoot],
});
// 一键获取 AI SDK 格式的 tools
const tools = manager.getAISDKTools();
// 直接传给 generateText
const result = await generateText({ model, tools, ... });

6.2 JSON Schema → Zod 的转换策略

完美转换 JSON Schema 到 Zod 是个大工程(类型嵌套、$ref、allOf/anyOf...)。实际中采用"松散验证 + 透传"策略:

private jsonSchemaToZod(schema: Record<string, any>): z.ZodObject<any> {
  const properties = schema.properties || {};
  const required = new Set(schema.required || []);
  const shape: Record<string, z.ZodTypeAny> = {};  
  for (const [key, prop] of Object.entries(properties)) {
    switch (prop.type) {
      case "string": shape[key] = z.string(); break;
      case "number": shape[key] = z.number(); break;
      case "boolean": shape[key] = z.boolean(); break;
      default: shape[key] = z.any();
    }
    if (prop.description) shape[key] = shape[key].describe(prop.description);
    if (!required.has(key)) shape[key] = shape[key].optional();
  }
  return z.object(shape);
}

处理常见类型就够了。边界 case 交给 MCP Server 端做最终验证——它本来就会校验参数合法性。

6.3 多 Server 连接

McpClientManager 支持同时连接多个 Server。当有多个 Server 时,Tool 名称自动加 Server 名作前缀避免冲突:

// 连接多个 Server
await manager.connectToServer("file-server", { ... });
await manager.connectToServer("db-server", { ... });
// 获取的 tools 会是:file-server__read_file、db-server__query 等

这意味着一个 Agent 可以同时拥有文件操作、数据库查询、API 调用等多种能力——来自不同 Server,通过统一协议串联。

七、完整集成:LLM 通过 MCP 操作文件系统

最终成果——让 LLM 通过 MCP 协议自主操作文件:

async function runAgent(userQuery: string) {
  const mcpManager = new McpClientManager({ verbose: true });
  
  // 1. 连接 MCP Server
  await mcpManager.connectToServer("file-server", {
    command: "npx",
    args: ["tsx", "file-server/index.ts", projectRoot],
  });
  
  // 2. 读取初始上下文(Resource)
  const workspaceInfo = await mcpManager.readResource("file-server", "file://workspace/info");
  
  // 3. 获取 AI SDK 格式的 Tools
  const tools = mcpManager.getAISDKTools();
  
  // 4. 执行 Agent 循环
  const result = await generateText({
    model: deepseek("deepseek-chat"),
    system: `你是文件系统助手。工作目录信息:${workspaceInfo}`,
    prompt: userQuery,
    tools,
    maxSteps: 10,
  });
}

用户说"帮我看看项目有哪些 TypeScript 文件,然后读取 package.json",Agent 会自动:

  1. 调用 search_files({ pattern: "*.ts" }) 搜索所有 TS 文件
  2. 调用 read_file({ path: "package.json" }) 读取配置
  3. 综合信息给出总结

整个过程中,Agent 的工具调用通过 MCP 协议传递给独立运行的 Server 进程,Server 执行后返回结果,Agent 继续推理。工具的实现完全解耦,可以替换、升级、跨应用复用。

八、用 MCP Inspector 调试

MCP 官方提供了一个可视化调试工具——Inspector,相当于 MCP 世界的 Postman。

npx @modelcontextprotocol/inspector npx tsx file-server/index.ts .
# 浏览器打开 

Inspector 能做什么:

  • 查看 Server 暴露的所有 Tools、Resources、Prompts
  • 手动填参数调用 Tool 查看返回
  • 查看完整的 JSON-RPC 通信日志(底层消息收发)
  • 验证参数校验是否生效、错误处理是否正确

开发流程建议:先用 Inspector 验证 Server 每个能力是否正常,确认后再写 Client 代码集成。

九、协议层面的理解

透过 Inspector 的 Logs 面板,可以看到 MCP 通信遵循 JSON-RPC 2.0 格式:

连接建立后的消息流:
1. ClientServer: initialize(协商能力)
2. ServerClient: initialize result(声明支持的能力)
3. ClientServer: initialized(握手完成)
4. ClientServer: tools/list(发现工具)
5. ServerClient: tools result(返回工具列表)
6. ClientServer: tools/call(调用工具)
7. ServerClient: result(返回结果)
...
N. Client → Server: close(断开连接)

对应到代码:

await client.connect(transport);           // 步骤 1-3 内部完成
const tools = await client.listTools();    // 步骤 4-5
const result = await client.callTool({     // 步骤 6-7
  name: "calculate",
  arguments: { expression: "1+1" },
});

十、MCP vs Function Calling:本质区别

很多人第一反应是"MCP 不就是换了个形式的 Function Calling 吗?"。表面看确实类似——都是给 LLM 提供可调用的工具。但本质上它们解决的问题层次不同:

维度Function CallingMCP
定义方式代码中硬编码Server 独立声明
发现方式开发者手动配置Client 自动 listTools
复用性应用内复用跨 Host 通用
运行方式同进程独立进程/服务
生态各家私有统一标准
更新升级需重新部署应用只更新 Server

Function Calling 是"教一个 App 用工具"的技术;MCP 是"让所有 App 共享同一套工具"的协议标准。前者是实现细节,后者是生态基础设施。

十一、关键实践经验

11.1 Server 设计原则

安全沙箱化:Server 的操作范围必须被约束。文件 Server 限制在指定目录、数据库 Server 限制在指定 Schema、API Server 限制在指定域名。永远假设调用方(LLM)可能传入恶意参数。

错误信息给 LLM 看:Tool 的错误返回不是给开发者看的 stack trace,而是给 LLM 看的可理解文本。LLM 看到"文件不存在"可以决定换个路径;看到"ja va.io.FileNotFoundException at line 42"则无所适从。

粒度适中:一个 Tool 做一件事。不要把"读文件+解析+转换+写回"打包成一个 Tool——LLM 需要细粒度的操作来组合完成复杂任务。

11.2 性能考量

stdio 传输的性能瓶颈在于进程启动。每次连接都 spawn 一个子进程,冷启动有几百毫秒开销。解决方案:

  • 复用连接(一次 connect,多次 callTool)
  • 对于频繁使用的 Server,保持长连接
  • 生产环境考虑 Streamable HTTP,Server 常驻运行

11.3 TypeScript 全链路类型安全

MCP SDK + Zod 的组合让整个链路都有类型保护:

// Server 端:Zod 定义参数
inputSchema: { path: z.string(), recursive: z.boolean().optional() }// 自动推导 execute 函数的参数类型
async ({ path, recursive }) => { ... }
// path: string, recursive: boolean | undefined
// Client 端:callTool 的参数也有类型提示
await client.callTool({ name: "list_directory", arguments: { path: "src" } });

十二、MCP 生态现状与未来

当前生态

  • Host 支持:Claude Desktop、CatDesk、Cursor、Continue、Zed 等已原生支持 MCP
  • 官方 Server:GitHub、Slack、Google Drive、PostgreSQL、Puppeteer 等
  • 社区 Server:数百个社区贡献的 Server(文件系统、Docker、Kubernetes、Notion...)
  • SDK:TypeScript、Python、Ja va、Go 等多语言 SDK

发展趋势

MCP 正在从"可选的高级特性"变为"Agent 生态的基础设施"。几个观察:

  • 越来越多 AI IDE 把 MCP 作为扩展机制(类似 VS Code 的 Extension API)
  • Server 市场/注册中心开始出现(类似 npm registry)
  • 身份认证和权限控制正在标准化(OAuth 2.0 集成)
  • 远程 Server 的发现和部署工具链在完善

总结

三天的 MCP 学习,最大的收获不是"又学了一个新协议",而是理解了一个思维转变:

从"给我的 Agent 写工具" → "为整个 AI 生态建设可复用的能力模块"。

当你写一个 MCP Server 时,你不只是在为当前项目服务——你在为任何支持 MCP 的 Host 提供能力。今天写的文件系统 Server,明天可以被 Claude Desktop 直接使用,后天可以被同事的 Agent 项目复用。

这就是标准化的力量。USB 改变了硬件生态,MCP 正在改变 AI 工具生态。

来源:互联网

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

同类文章推荐

相关文章推荐

更多