第十章:MCP 协议实现
🔌 本章详细介绍 MiniClaw 如何实现 MCP(Model Context Protocol)协议。
10.1 MCP 协议概述
10.1.1 什么是 MCP?
MCP(Model Context Protocol)是 Anthropic 开发的开放协议,用于连接 AI 模型与外部工具和数据源。
┌─────────────────────────────────────────────────────────────────────┐
│ MCP 协议概述 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ MCP 架构 │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ MCP Host │ │ MCP Server │ │ │
│ │ │ (Claude等) │ ◄─────► │ (MiniClaw) │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ ▼ ▼ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ AI 模型 │ │ 工具/资源 │ │ │
│ │ │ (Claude等) │ │ (本地数据) │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ MCP 核心概念: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ • Resources → 可读取的数据源 │ │
│ │ • Tools → 可执行的函数 │ │
│ │ • Prompts → 预定义的提示词模板 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.1.2 MCP 通信方式
┌─────────────────────────────────────────────────────────────────────┐
│ MCP 通信方式 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Stdio 传输(MiniClaw 使用的方式) │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ MCP Host (Claude Code) │ │
│ │ │ │ │
│ │ │ stdin/stdout │ │
│ │ │ (JSON-RPC 消息) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ MCP Server (MiniClaw) │ │
│ │ │ │ │
│ │ │ 文件系统 │ │
│ │ ▼ │ │
│ │ ~/.miniclaw/ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 消息格式:JSON-RPC 2.0 │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ { │ │
│ │ "jsonrpc": "2.0", │ │
│ │ "id": 1, │ │
│ │ "method": "tools/call", │ │
│ │ "params": { │ │
│ │ "name": "miniclaw_note", │ │
│ │ "arguments": { "content": "..." } │ │
│ │ } │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.2 服务器初始化
10.2.1 服务器配置
┌─────────────────────────────────────────────────────────────────────┐
│ 服务器配置 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ import { Server } from '@modelcontextprotocol/sdk/server/index.js';│
│ import { StdioServerTransport } from '@modelcontextprotocol/sdk... │
│ │
│ // 创建服务器实例 │
│ const server = new Server( │
│ { │
│ name: "miniclaw", │
│ version: "0.5.0", │
│ }, │
│ { │
│ capabilities: { │
│ resources: {}, // 支持资源读取 │
│ tools: {}, // 支持工具调用 │
│ prompts: {}, // 支持提示词 │
│ }, │
│ } │
│ ); │
│ │
│ // 创建传输层 │
│ const transport = new StdioServerTransport(); │
│ │
│ // 连接服务器 │
│ await server.connect(transport); │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.2.2 能力声明
┌─────────────────────────────────────────────────────────────────────┐
│ 能力声明 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ capabilities: { │ │
│ │ resources: {}, // 声明支持资源功能 │ │
│ │ tools: {}, // 声明支持工具功能 │ │
│ │ prompts: {}, // 声明支持提示词功能 │ │
│ │ } │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 能力说明: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ resources: {} │ │
│ │ ├── ListResourcesRequestSchema → 列出可用资源 │ │
│ │ └── ReadResourceRequestSchema → 读取资源内容 │ │
│ │ │ │
│ │ tools: {} │ │
│ │ ├── ListToolsRequestSchema → 列出可用工具 │ │
│ │ └── CallToolRequestSchema → 调用工具 │ │
│ │ │ │
│ │ prompts: {} │ │
│ │ ├── ListPromptsRequestSchema → 列出可用提示词 │ │
│ │ └── GetPromptRequestSchema → 获取提示词内容 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.3 资源实现
10.3.1 资源列表
┌─────────────────────────────────────────────────────────────────────┐
│ 资源列表实现 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ server.setRequestHandler(ListResourcesRequestSchema, async () => { │
│ const skills = await kernel.skillCache.getAll(); │
│ │
│ const resources = [ │
│ { │
│ uri: "miniclaw://context", │
│ name: "Agent Context", │
│ description: "Agent 人格核心,身份类问题必须先读取", │
│ mimeType: "text/markdown", │
│ }, │
│ { │
│ uri: "miniclaw://skills", │
│ name: "Skills Index", │
│ description: "所有已加载的技能概览", │
│ mimeType: "text/markdown", │
│ }, │
│ ]; │
│ │
│ // 添加技能资源 │
│ for (const [skillName] of skills) { │
│ resources.push({ │
│ uri: `miniclaw://skill/${skillName}/SKILL.md`, │
│ name: `Skill: ${skillName}`, │
│ mimeType: "text/markdown", │
│ }); │
│ } │
│ │
│ return { resources }; │
│ }); │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.3.2 资源读取
┌─────────────────────────────────────────────────────────────────────┐
│ 资源读取实现 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ server.setRequestHandler(ReadResourceRequestSchema, async (req) => {│
│ const uri = req.params.uri; │
│ │
│ // 核心上下文资源 │
│ if (uri === "miniclaw://context") { │
│ const content = await kernel.boot({ type: "full" }); │
│ return { │
│ contents: [{ │
│ uri, │
│ mimeType: "text/markdown", │
│ text: content, │
│ }] │
│ }; │
│ } │
│ │
│ // 技能索引资源 │
│ if (uri === "miniclaw://skills") { │
│ const skills = await kernel.skillCache.getAll(); │
│ const content = generateSkillsIndex(skills); │
│ return { │
│ contents: [{ │
│ uri, │
│ mimeType: "text/markdown", │
│ text: content, │
│ }] │
│ }; │
│ } │
│ │
│ // 技能文件资源 │
│ const skillMatch = uri.match(/^miniclaw:\/\/skill\/(.+)\/(.+)$/);│
│ if (skillMatch) { │
│ const [, skillName, fileName] = skillMatch; │
│ const content = await kernel.getSkillContent(skillName, fileName);│
│ return { │
│ contents: [{ │
│ uri, │
│ mimeType: "text/markdown", │
│ text: content, │
│ }] │
│ }; │
│ } │
│ │
│ throw new Error(`Unknown resource: ${uri}`); │
│ }); │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.4 工具实现
10.4.1 工具列表
┌─────────────────────────────────────────────────────────────────────┐
│ 工具列表实现 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ server.setRequestHandler(ListToolsRequestSchema, async () => { │
│ return { │
│ tools: [ │
│ { │
│ name: "miniclaw_update", │
│ description: "更新核心文件,实现自我进化", │
│ inputSchema: { │
│ type: "object", │
│ properties: { │
│ file: { │
│ type: "string", │
│ enum: ["AGENTS.md", "SOUL.md", ...], │
│ }, │
│ content: { type: "string" }, │
│ mode: { type: "string", enum: ["append", "replace"] }, │
│ }, │
│ required: ["file", "content"], │
│ }, │
│ }, │
│ { │
│ name: "miniclaw_note", │
│ description: "日志速记,追加今日日志", │
│ inputSchema: { │
│ type: "object", │
│ properties: { │
│ content: { type: "string" }, │
│ }, │
│ required: ["content"], │
│ }, │
│ }, │
│ // ... 更多工具 │
│ ], │
│ }; │
│ }); │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.4.2 工具调用
┌─────────────────────────────────────────────────────────────────────┐
│ 工具调用实现 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ server.setRequestHandler(CallToolRequestSchema, async (req) => { │
│ const { name, arguments: args } = req.params; │
│ │
│ // 记录工具调用统计 │
│ kernel.trackTool(name); │
│ │
│ try { │
│ switch (name) { │
│ case "miniclaw_update": { │
│ const { file, content, mode } = UpdateSchema.parse(args); │
│ const result = await kernel.updateFile(file, content, mode);│
│ return { │
│ content: [{ │
│ type: "text", │
│ text: result, │
│ }] │
│ }; │
│ } │
│ │
│ case "miniclaw_note": { │
│ const { content } = NoteSchema.parse(args); │
│ const result = await kernel.appendDailyLog(content); │
│ return { │
│ content: [{ │
│ type: "text", │
│ text: result, │
│ }] │
│ }; │
│ } │
│ │
│ case "miniclaw_exec": { │
│ const { command } = ExecSchema.parse(args); │
│ const result = await kernel.executeCommand(command); │
│ return { │
│ content: [{ │
│ type: "text", │
│ text: result, │
│ }] │
│ }; │
│ } │
│ │
│ // ... 更多工具处理 │
│ │
│ default: │
│ throw new Error(`Unknown tool: ${name}`); │
│ } │
│ } catch (error) { │
│ return { │
│ content: [{ │
│ type: "text", │
│ text: `Error: ${error.message}`, │
│ }], │
│ isError: true, │
│ }; │
│ } │
│ }); │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.5 提示词实现
10.5.1 提示词列表
┌─────────────────────────────────────────────────────────────────────┐
│ 提示词列表实现 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ server.setRequestHandler(ListPromptsRequestSchema, async () => { │
│ const skills = await kernel.skillCache.getAll(); │
│ │
│ const prompts = [ │
│ { │
│ name: "miniclaw_wakeup", │
│ description: "创世协议,新会话的默认入口", │
│ }, │
│ { │
│ name: "miniclaw_think", │
│ description: "思考检查,脉搏检测", │
│ }, │
│ { │
│ name: "miniclaw_growup", │
│ description: "成长协议,记忆蒸馏", │
│ }, │
│ { │
│ name: "miniclaw_recall", │
│ description: "回忆协议,查看已记住的内容", │
│ }, │
│ { │
│ name: "miniclaw_briefing", │
│ description: "每日简报,早间工作概览", │
│ }, │
│ ]; │
│ │
│ // 添加技能提示词 │
│ for (const [skillName, skill] of skills) { │
│ if (skill.prompts) { │
│ for (const prompt of skill.prompts) { │
│ prompts.push({ │
│ name: `skill_${skillName}_${prompt.name}`, │
│ description: prompt.description, │
│ }); │
│ } │
│ } │
│ } │
│ │
│ return { prompts }; │
│ }); │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.5.2 提示词获取
┌─────────────────────────────────────────────────────────────────────┐
│ 提示词获取实现 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ server.setRequestHandler(GetPromptRequestSchema, async (req) => { │
│ const { name } = req.params; │
│ │
│ // 记录提示词使用统计 │
│ kernel.trackPrompt(name); │
│ │
│ switch (name) { │
│ case "miniclaw_wakeup": │
│ return { │
│ messages: [{ │
│ role: "user", │
│ content: { │
│ type: "text", │
│ text: generateWakeupPrompt(), │
│ }, │
│ }] │
│ }; │
│ │
│ case "miniclaw_growup": │
│ return { │
│ messages: [{ │
│ role: "user", │
│ content: { │
│ type: "text", │
│ text: generateGrowupPrompt(), │
│ }, │
│ }] │
│ }; │
│ │
│ // ... 更多提示词处理 │
│ │
│ default: │
│ // 检查是否为技能提示词 │
│ const skillMatch = name.match(/^skill_(.+)_(.+)$/); │
│ if (skillMatch) { │
│ const [, skillName, promptName] = skillMatch; │
│ const content = await kernel.getSkillPrompt(skillName, promptName);│
│ return { │
│ messages: [{ │
│ role: "user", │
│ content: { │
│ type: "text", │
│ text: content, │
│ }, │
│ }] │
│ }; │
│ } │
│ │
│ throw new Error(`Unknown prompt: ${name}`); │
│ } │
│ }); │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.6 MCP 配置示例
10.6.1 Claude Code 配置
┌─────────────────────────────────────────────────────────────────────┐
│ Claude Code 配置 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ // claude_desktop_config.json 或 MCP 客户端配置 │
│ │
│ { │
│ "mcpServers": { │
│ "miniclaw": { │
│ "command": "npx", │
│ "args": ["-y", "github:8421bit/miniclaw"], │
│ "env": { │
│ "MINICLAW_TOKEN_BUDGET": "12000" │
│ } │
│ } │
│ } │
│ } │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.6.2 配置参数说明
┌─────────────────────────────────────────────────────────────────────┐
│ 配置参数说明 │
├─────────────────┬───────────────────────────────────────────────────┤
│ 参数 │ 说明 │
├─────────────────┼───────────────────────────────────────────────────┤
│ command │ 执行命令,使用 npx 运行 │
├─────────────────┼───────────────────────────────────────────────────┤
│ args │ 命令参数,-y 自动确认,github:... 指定仓库 │
├─────────────────┼───────────────────────────────────────────────────┤
│ env │ 环境变量配置 │
├─────────────────┼───────────────────────────────────────────────────┤
│ MINICLAW_ │ Token 预算配置,默认 8000 │
│ TOKEN_BUDGET │ │
└─────────────────┴───────────────────────────────────────────────────┘
10.7 MCP 消息流程
10.7.1 初始化流程
┌─────────────────────────────────────────────────────────────────────┐
│ 初始化流程 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ MCP Host MCP Server │
│ (Claude Code) (MiniClaw) │
│ │ │ │
│ │ ────── initialize ────────────────► │ │
│ │ {protocolVersion: "2024..."} │ │
│ │ │ │
│ │ ◄───── InitializeResult ─────────── │ │
│ │ {capabilities: {...}} │ │
│ │ │ │
│ │ ────── initialized ────────────────► │ │
│ │ (notification) │ │
│ │ │ │
│ │ │ │
│ │ 初始化完成 │ │
│ │ │ │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.7.2 工具调用流程
┌─────────────────────────────────────────────────────────────────────┐
│ 工具调用流程 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ MCP Host MCP Server │
│ (Claude Code) (MiniClaw) │
│ │ │ │
│ │ ────── tools/list ────────────────► │ │
│ │ │ │
│ │ ◄───── ListToolsResult ──────────── │ │
│ │ {tools: [...]} │ │
│ │ │ │
│ │ ────── tools/call ────────────────► │ │
│ │ {name: "miniclaw_note", │ │
│ │ arguments: {...}} │ │
│ │ │ │
│ │ [执行工具] │ │
│ │ │ │
│ │ ◄───── CallToolResult ───────────── │ │
│ │ {content: [...]} │ │
│ │ │ │
│ │
└─────────────────────────────────────────────────────────────────────┘
10.7.3 资源读取流程
┌─────────────────────────────────────────────────────────────────────┐
│ 资源读取流程 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ MCP Host MCP Server │
│ (Claude Code) (MiniClaw) │
│ │ │ │
│ │ ────── resources/list ────────────► │ │
│ │ │ │
│ │ ◄───── ListResourcesResult ─────── │ │
│ │ {resources: [...]} │ │
│ │ │ │
│ │ ────── resources/read ────────────► │ │
│ │ {uri: "miniclaw://context"} │ │
│ │ │ │
│ │ [编译上下文]│ │
│ │ │ │
│ │ ◄───── ReadResourceResult ──────── │ │
│ │ {contents: [...]} │ │
│ │ │ │
│ │
└─────────────────────────────────────────────────────────────────────┘
本章小结
┌─────────────────────────────────────────────────────────────────────┐
│ 第十章 核心要点 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 🔌 MCP 协议 │
│ • Model Context Protocol,连接 AI 模型与外部工具 │
│ • 使用 Stdio 传输,JSON-RPC 2.0 消息格式 │
│ │
│ 📋 三大核心能力 │
│ • Resources → 可读取的数据源 │
│ • Tools → 可执行的函数 │
│ • Prompts → 预定义的提示词模板 │
│ │
│ 🛠️ 服务器实现 │
│ • @modelcontextprotocol/sdk │
│ • Server 实例 + StdioServerTransport │
│ │
│ 📝 请求处理器 │
│ • ListResourcesRequestSchema / ReadResourceRequestSchema │
│ • ListToolsRequestSchema / CallToolRequestSchema │
│ • ListPromptsRequestSchema / GetPromptRequestSchema │
│ │
│ ⚙️ 配置示例 │
│ • npx -y github:8421bit/miniclaw │
│ • MINICLAW_TOKEN_BUDGET 环境变量 │
│ │
└─────────────────────────────────────────────────────────────────────┘
项目分析报告完成!