尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

从AI助手到协作者:MCP协议与mcp-run实战指南

从AI助手到协作者:MCP协议与mcp-run实战指南 1. 从“AI 助手”到“AI 协作者”为什么我们需要 MCP最近在折腾 AI 应用开发特别是想让大模型比如 Claude、GPTs能更深入地操作我本地的工具和数据。我发现一个挺普遍的问题这些 AI 助手虽然能说会道但一涉及到具体操作比如读取我某个特定格式的日志文件、调用一个内部 API、或者操作一个非标准数据库就显得有点“隔靴搔痒”。你不得不把文件内容复制粘贴给它或者手动执行命令再把结果喂回去。这个过程不仅繁琐而且割裂完全不是想象中的“智能副驾”该有的样子。问题的核心在于“能力边界”。大模型本身是一个强大的推理和文本生成引擎但它并不自带“手”和“眼睛”。它需要一套标准化的、安全的“接口”来与外部世界交互。这就是Model Context Protocol出现的背景。你可以把它理解为一套“插件”协议它定义了一套标准让任何外部工具比如你的文件系统、数据库、API都能以一种模型能理解的方式将自己“能做什么”、“怎么调用”告诉给 AI。而 AI 则通过这个协议获得调用这些工具的能力。这样一来AI 就不再只是一个被动的问答机器而变成了一个能主动使用工具的“协作者”。比如你可以告诉 Claude“帮我分析一下今天/var/log/app/目录下所有错误日志的趋势。” 它可以通过 MCP 协议调用一个“文件读取”工具来获取日志内容再调用一个“数据分析”工具进行处理最后把分析结果用图表或总结的形式呈现给你。整个过程是自动、连贯的。而mcp-run就是进入 MCP 世界的一把非常友好的“钥匙”。它不是一个庞大的框架而是一个轻量级的命令行工具核心功能就是让你能快速地把一个简单的脚本或程序“包装”成一个符合 MCP 协议的工具并立刻提供给 AI 使用。它降低了为 AI 构建工具的门槛让你不必从零开始处理复杂的协议通信和生命周期管理可以专注于工具本身的逻辑。接下来我就带你从零开始亲手打造一个属于自己的 MCP 工具体验一下让 AI 真正“动手”的感觉。2. 理解 MCP 的核心构件工具、资源与协议在动手写代码之前我们得先搞清楚 MCP 这套协议里到底有哪些“乐高积木”。理解了这些基本概念后面写起工具来才能得心应手知道每一行代码是在为什么服务。MCP 协议主要围绕三个核心概念展开服务器、工具和资源。我们开发的mcp-run工具本质上就是在创建一个实现了 MCP 协议的服务器。服务器是能力的提供方。它像一个后台服务持续运行等待 AI 客户端比如 Claude Desktop的连接。一旦连接建立服务器就会向客户端“广告”自己有哪些工具和资源可用。工具是 AI 可以主动调用的“函数”。这是最常用、最直观的交互方式。一个工具通常包括name: 工具的唯一标识符AI 通过这个名字来调用它。description: 工具功能的自然语言描述。这部分极其重要它直接决定了 AI 是否能理解并在合适的场景下使用这个工具。描述要清晰、具体说明输入、输出和用途。inputSchema: 定义调用这个工具时需要提供的参数通常是一个 JSON Schema。这告诉 AI 需要提供什么样的数据。例如一个“查询天气”的工具它的name可能是get_weatherdescription是“根据城市名称查询当前天气状况”inputSchema则要求一个名为city的字符串参数。资源则是 AI 可以被动“读取”或“订阅”的内容。它更像是一个数据源或一个可观察的对象。资源由统一资源标识符来定位AI 客户端可以请求读取某个 URI 对应的资源内容。这对于提供静态或动态数据如系统状态、监控指标、文档内容非常有用。mcp-run的巧妙之处在于它为我们隐藏了建立服务器、维护连接、序列化消息这些底层复杂性。我们只需要按照它的约定编写一个简单的脚本这个脚本能接收 JSON 格式的调用请求并返回 JSON 格式的结果。mcp-run会负责将这个脚本“提升”为一个全功能的 MCP 服务器。我们的工作重心可以完全放在工具的业务逻辑实现上。3. 实战编写一个“系统信息查询”工具理论说得再多不如动手写一个。我们来实现一个非常实用的小工具get_system_info。它的功能是让 AI 能够查询服务器或本地电脑的基本系统信息比如操作系统、主机名、CPU 核心数、内存总量等。这在 AI 协助进行系统运维、故障排查时非常有用。首先你需要确保安装了mcp-run。它通常是一个 NPM 包可以通过npm全局安装npm install -g modelcontextprotocol/server-mcp-run安装完成后我们就可以开始编写工具脚本了。mcp-run支持多种脚本语言这里我们用最通用的 Python 来举例。创建一个名为system_info_tool.py的文件。#!/usr/bin/env python3 import json import sys import platform import os import psutil def get_system_info(): 收集系统信息 info { “操作系统”: platform.system(), “操作系统版本”: platform.version(), “主机名”: platform.node(), “处理器架构”: platform.machine(), “Python 版本”: platform.python_version(), “CPU 逻辑核心数”: psutil.cpu_count(logicalTrue), “CPU 物理核心数”: psutil.cpu_count(logicalFalse), “总内存 (GB)”: round(psutil.virtual_memory().total / (1024**3), 2), “可用内存 (GB)”: round(psutil.virtual_memory().available / (1024**3), 2), “当前工作目录”: os.getcwd(), } return info def main(): # mcp-run 会通过 stdin 发送 JSON-RPC 请求 request json.loads(sys.stdin.read()) # 请求中包含了调用的方法名和参数 method request.get(“method”) params request.get(“params”, {}) if method “tools/call”: # 提取工具名和调用参数 tool_name params.get(“name”) call_args params.get(“arguments”, {}) if tool_name “get_system_info”: # 执行我们的工具逻辑 try: result get_system_info() # 构建成功的响应 response { “jsonrpc”: “2.0”, “id”: request[“id”], “result”: { “content”: [ { “type”: “text”, “text”: json.dumps(result, indent2, ensure_asciiFalse) } ] } } except Exception as e: # 构建错误的响应 response { “jsonrpc”: “2.0”, “id”: request[“id”], “error”: { “code”: -32000, “message”: f“执行工具时出错: {str(e)}” } } # 将响应输出到 stdout print(json.dumps(response)) return # 对于未知的请求返回方法未找到错误 error_response { “jsonrpc”: “2.0”, “id”: request.get(“id”), “error”: { “code”: -32601, “message”: “Method not found” } } print(json.dumps(error_response)) if __name__ “__main__”: main()这个脚本的核心逻辑很清晰从标准输入读取一个 JSON-RPC 格式的请求。判断请求是否是调用工具。如果工具名是get_system_info则执行get_system_info()函数收集数据。将结果按照 MCP 协议要求的格式包装通过标准输出返回。注意这个脚本依赖psutil库来获取详细的系统信息。你需要先通过pip install psutil安装它。但是只有脚本还不够。mcp-run需要一份“清单”来知道你这个脚本提供了哪些工具。我们需要创建一个名为mcp.json的配置文件和脚本放在同一目录下。{ “mcpServers”: { “system-info”: { “command”: “python3”, “args”: [“/绝对路径/到/你的/system_info_tool.py”], “env”: { “PYTHONPATH”: “.” } } } }这个配置文件告诉mcp-run这里有一个叫system-info的服务器你可以通过执行python3 /path/to/script.py这个命令来启动它。mcp-run在启动时会向这个脚本发送一个特殊的initialize请求脚本需要在这个请求的响应中声明自己提供的工具列表。因此我们需要修改一下脚本让它能响应初始化请求并公布工具信息。让我们更新system_info_tool.py增加对initialize请求的处理#!/usr/bin/env python3 import json import sys import platform import os import psutil # ... get_system_info 函数保持不变 ... def main(): request json.loads(sys.stdin.read()) method request.get(“method”) params request.get(“params”, {}) if method “initialize”: # 响应初始化请求声明本服务器提供的工具 response { “jsonrpc”: “2.0”, “id”: request[“id”], “result”: { “protocolVersion”: “2024-11-05”, “capabilities”: { “tools”: { “listChanged”: None } }, “serverInfo”: { “name”: “System Info Server”, “version”: “0.1.0” } } } print(json.dumps(response)) # 紧接着客户端会请求工具列表我们需要在下一个请求中处理 return elif method “tools/list”: # 提供工具列表 tools_list [ { “name”: “get_system_info”, “description”: “获取当前系统的基本信息包括操作系统、主机名、CPU核心数、内存总量和使用情况、当前工作目录等。适用于快速系统状态检查。”, “inputSchema”: { “type”: “object”, “properties”: {}, # 这个工具不需要输入参数 “additionalProperties”: False } } ] response { “jsonrpc”: “2.0”, “id”: request[“id”], “result”: { “tools”: tools_list } } print(json.dumps(response)) return elif method “tools/call”: # ... 之前处理工具调用的代码保持不变 ... pass else: # ... 处理未知方法的代码保持不变 ... pass if __name__ “__main__”: main()现在我们的工具脚本就完整了。它能够在启动时告诉客户端“我支持 MCP 协议”。当客户端问“你有什么工具”时返回get_system_info工具的详细定义。当客户端调用get_system_info时执行逻辑并返回系统信息。4. 连接 AI 客户端让 Claude 使用你的工具工具写好了服务器也能跑了下一步就是让它被 AI 使用。这里以Claude Desktop应用为例它是目前集成 MCP 客户端最方便的平台之一。首先我们需要找到 Claude Desktop 的配置目录。它的位置因操作系统而异macOS:~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:%APPDATA%\Claude\claude_desktop_config.jsonLinux:~/.config/Claude/claude_desktop_config.json如果这个文件不存在就创建一个。然后我们需要将之前写的mcp.json配置文件的内容“融合”到 Claude 的配置中。更准确地说是把我们本地mcp.json里定义的服务器配置添加到 Claude 配置的mcpServers部分。假设我们的项目目录是/Users/yourname/projects/mcp-system-info那么mcp.json的完整路径就是/Users/yourname/projects/mcp-system-info/mcp.json。编辑claude_desktop_config.json文件内容如下{ “mcpServers”: { “system-info”: { “command”: “npx”, “args”: [ “-y”, “modelcontextprotocol/server-mcp-run”, “/Users/yourname/projects/mcp-system-info/mcp.json” ] } } }这里配置的含义是Claude Desktop 启动时会执行命令npx -y modelcontextprotocol/server-mcp-run /path/to/your/mcp.json。npx -y会确保运行所需的mcp-run服务器包。mcp-run会根据我们提供的配置文件启动我们定义的 Python 脚本服务器。配置完成后重启 Claude Desktop 应用。这是关键一步新的配置只在应用启动时加载。重启后打开 Claude Desktop你可以尝试问它“你现在可以使用哪些工具” 或者 “请调用 get_system_info 工具查看一下我的系统信息。” 如果一切配置正确Claude 应该会回复它已连接到一个服务器并列出可用的工具包括我们的get_system_info然后执行调用将系统信息以格式化的 JSON 文本返回给你。这个过程可能遇到几个常见问题Claude 说找不到工具检查配置文件路径是否正确尤其是 Windows 下的路径分隔符和转义。确认mcp.json中的args路径是脚本的绝对路径。执行出错打开 Claude Desktop 的应用日志通常可以在应用设置中找到或通过命令行启动查看里面会有mcp-run和你的脚本输出的详细错误信息比如 Python 依赖缺失 (psutil)、脚本语法错误等。连接失败确保mcp-run命令能正常执行。可以在终端手动运行配置中的命令看是否能启动服务器而无报错。当看到 Claude 成功返回你的系统信息时那种感觉是非常奇妙的——你亲手赋予了一个 AI 模型感知你本地环境的能力。5. 进阶技巧设计更复杂、更实用的工具掌握了基础工具的开发流程后我们可以设计一些更复杂、更贴近实际需求的工具。工具的设计好坏直接决定了 AI 使用的效率和准确性。这里分享几个设计原则和进阶案例。原则一工具描述是给 AI 看的“说明书”工具的description字段不是摆设它是 AI 决定是否、何时以及如何调用该工具的主要依据。描述应该明确功能用一句话说清这个工具是干什么的。定义输入说明需要哪些参数每个参数是什么。说明输出告诉 AI 会得到什么格式的数据。提示用途建议在什么场景下使用。例如一个文件查找工具的描述可以这样写“在指定目录及其子目录中根据文件名或扩展名搜索文件。需要提供directory搜索起始目录和pattern支持通配符的文件名匹配模式如*.log参数。返回一个包含文件路径和基本信息的列表。适用于快速定位项目中的特定文件。”原则二输入模式要“AI友好”AI 擅长处理自然语言和结构化数据。设计输入模式时优先使用string、number、boolean等基本类型。对于复杂参数使用object并定义清晰的properties。善用enum枚举类型来限定可选值减少 AI 的猜测。在description里为每个参数提供清晰的解释。案例一个简单的数据库查询工具假设我们有一个 SQLite 数据库app.db里面有一张users表。我们想让 AI 能安全地查询用户数据。# db_query_tool.py (部分核心代码) import sqlite3 import json import sys from pathlib import Path DB_PATH Path.home() / “my_app” / “app.db” def query_users(**kwargs): # 安全提示永远不要让 AI 直接拼接 SQL 字符串 # 这里我们只允许查询特定的“视图”或者使用参数化查询。 allowed_queries { “get_all”: “SELECT id, username, email FROM users LIMIT 50”, “get_by_id”: “SELECT id, username, email FROM users WHERE id ?”, “search_by_name”: “SELECT id, username, email FROM users WHERE username LIKE ?” } query_type kwargs.get(“query_type”, “get_all”) conn sqlite3.connect(DB_PATH) conn.row_factory sqlite3.Row # 方便转为字典 cursor conn.cursor() if query_type “get_by_id”: user_id kwargs.get(“user_id”) cursor.execute(allowed_queries[“get_by_id”], (user_id,)) elif query_type “search_by_name”: name_pattern f“%{kwargs.get(‘name_pattern’, ‘’)}%” cursor.execute(allowed_queries[“search_by_name”], (name_pattern,)) else: cursor.execute(allowed_queries[“get_all”]) results [dict(row) for row in cursor.fetchall()] conn.close() return results # 在 tools/list 响应中这个工具的定义如下 tools_list [ { “name”: “query_user_db”, “description”: “安全地查询用户数据库。提供查询类型和必要参数。查询类型query_type可选‘get_all’获取前50个用户‘get_by_id’根据ID查询需提供user_id‘search_by_name’根据用户名模糊搜索需提供name_pattern。返回用户ID、用户名和邮箱的列表。”, “inputSchema”: { “type”: “object”, “properties”: { “query_type”: { “type”: “string”, “enum”: [“get_all”, “get_by_id”, “search_by_name”], “description”: “要执行的查询类型” }, “user_id”: { “type”: “integer”, “description”: “当 query_type 为 ‘get_by_id’ 时必须提供” }, “name_pattern”: { “type”: “string”, “description”: “当 query_type 为 ‘search_by_name’ 时提供用于模糊匹配用户名” } }, “required”: [“query_type”], “additionalProperties”: False } } ]这个设计通过enum严格限制了 AI 可以执行的查询类型并通过参数化查询彻底避免了 SQL 注入风险既赋予了 AI 数据访问能力又保证了安全性。原则三错误处理与友好反馈工具执行可能会失败文件不存在、网络错误、参数无效。在返回错误时除了标准的错误代码尽量在message字段中提供对 AI和最终用户友好的、可操作的错误信息。例如不要只返回“查询失败”而是返回“数据库连接失败请检查DB_PATH配置的文件是否存在”。6. 调试、优化与生产化考量开发过程中调试是必不可少的。由于工具运行在mcp-run和 AI 客户端背后直接看日志是最有效的方法。调试方法查看 Claude Desktop 日志如前所述这是最直接的错误来源。独立测试脚本在终端直接模拟mcp-run的调用。创建一个test_request.json文件内容模拟一个工具调用请求{ “jsonrpc”: “2.0”, “id”: 1, “method”: “tools/call”, “params”: { “name”: “get_system_info”, “arguments”: {} } }然后通过管道传递给脚本cat test_request.json | python3 system_info_tool.py观察脚本的输出是否符合 MCP 响应格式。这能帮你快速定位脚本逻辑的错误。手动运行 mcp-run在终端执行配置中的完整命令观察其启动和初始化过程是否有报错。性能与稳定性优化避免长时间运行mcp-run默认可能为每个会话启动一个脚本进程。如果你的工具初始化很慢例如加载大模型考虑在脚本内实现简单的请求循环或者探索 MCP 服务器的“常驻”模式配置避免频繁启停。资源管理像数据库连接、网络会话这类资源要注意在工具函数内妥善获取和释放防止资源泄漏。超时处理在脚本中为可能长时间运行的操作设置超时并向客户端返回明确的超时错误避免请求挂起。生产化部署当你想在团队或多台机器上共享工具时mcp.json中的绝对路径就成了问题。有几种解决思路环境变量在mcp.json的args中使用环境变量如“args”: [“${WORKSPACE}/tools/my_tool.py”]然后在启动 Claude 前设置该环境变量。包装脚本不直接调用 Python 脚本而是调用一个包装器脚本Shell 或 Python在这个包装器脚本内部计算绝对路径再调用真正的工具脚本。标准化安装将你的工具脚本打包成一个真正的 NPM 包或 Python 包并提供一个统一的启动命令。这样在mcp.json中只需要配置“command”: “your-tool-cli”即可。这是最整洁、最易于分发的方式。7. 超越 mcp-run探索更强大的 MCP 开发模式mcp-run是快速入门的绝佳工具但它本质上是一个“胶水”层将脚本粘合到 MCP 协议上。当你需要开发更复杂、功能更全面的 MCP 服务器时直接使用官方的 SDK 是更专业的选择。使用官方 SDK 的优势类型安全与开发体验SDK 提供了完整的类型定义和高级 API处理协议握手、请求路由、错误处理等底层细节让你更专注于工具逻辑。更丰富的协议特性可以更方便地实现资源、提示模板、采样等高级 MCP 特性。更好的生命周期管理SDK 通常支持更优雅的启动、停止和重启逻辑。例如使用TypeScript/Node.js SDK重写我们的系统信息工具import { Server } from “modelcontextprotocol/sdk/server/index.js”; import { StdioServerTransport } from “modelcontextprotocol/sdk/server/stdio.js”; import { CallToolRequestSchema, ListToolsRequestSchema } from “modelcontextprotocol/sdk/types.js”; import os from ‘os’; import psutil from ‘psutil’; // 假设有类似库 const server new Server( { name: “system-info-server”, version: “0.2.0”, }, { capabilities: { tools: {}, }, } ); // 定义工具 server.setRequestHandler(ListToolsRequestSchema, async () { return { tools: [ { name: “get_system_info”, description: “获取当前系统的基本信息...”, inputSchema: { type: “object”, properties: {}, additionalProperties: false, }, }, ], }; }); // 处理工具调用 server.setRequestHandler(CallToolRequestSchema, async (request) { if (request.params.name “get_system_info”) { const info { platform: os.platform(), hostname: os.hostname(), cpus: os.cpus().length, totalMem: os.totalmem(), freeMem: os.freemem(), // ... 使用 psutil 获取更多信息 }; return { content: [ { type: “text”, text: JSON.stringify(info, null, 2), }, ], }; } throw new Error(Unknown tool: ${request.params.name}); }); // 启动服务器使用 stdio 传输与 mcp-run 兼容 const transport new StdioServerTransport(); await server.connect(transport); console.error(“System Info MCP Server running on stdio...”);使用 SDK 后代码结构更清晰协议处理更健壮。你可以用npm build将它编译成可执行文件然后在mcp.json中直接指向这个可执行文件完全脱离mcp-run。生态与社区MCP 的生态正在快速发展。除了自己编写服务器你还可以在社区找到大量现成的 MCP 服务器用于连接 GitHub、Jira、Notion、数据库等各种服务。通过mcp.json配置多个服务器你的 AI 助手就能同时获得几十种不同的超能力。学习和借鉴这些开源服务器的代码也是提升自己工具开发水平的好方法。从一个小小的mcp-run脚本起步到设计复杂的交互工具再到使用专业 SDK 构建生产级服务器这条路径清晰地展示了如何将外部能力一步步、安全可控地赋予大型语言模型。
返回列表