让Claude能力飞升:用MCP协议构建自定义工具实战
引言
Claude 是当下最强大的大语言模型之一,但你有没有遇到过这些场景:需要它读取本地文件、查询实时数据库、调用公司内部 API,或者只是简单地获取当前时间?由于安全和架构限制,Claude 本身无法直接访问外部资源。而Model Context Protocol (MCP)正是 Anthropic 推出的标准解决方案——它定义了一套通用协议,让 AI 应用(如 Claude Desktop)能够安全、标准地连接你提供的工具、资源和提示模板。
本文将带你从零开始,掌握 MCP 的核心概念,并通过一个完整可运行的 Python 示例,构建你自己的 Claude 自定义工具。读完你会发现,扩展 Claude 的能力其实比你想象的简单得多。
一、MCP 核心概念:为什么它如此重要?
在 MCP 出现之前,如果你想让大模型集成某个工具,通常需要针对不同模型写不同的插件,或者通过 LangChain 等框架做各种适配。这种碎片化让工具开发者疲于奔命,也让用户难以复用。
MCP 的出现改变了这一切,它像一个“USB-C 接口”:
-统一标准:无论是 OpenAI、Claude 还是其他模型,只要支持 MCP,就能使用同一个工具服务器。
-安全隔离:工具运行在独立的进程中,模型只能通过标准协议调用,无法随意执行系统命令。
-可插拔:你可以在 Claude Desktop 中随时添加或移除 MCP 服务器,无需修改应用本体。
MCP 的核心架构由三个角色构成:
-主机(Host):即 AI 应用本身,例如 Claude Desktop。
-客户端(Client):由 Host 内部创建,与指定的 MCP 服务器维持 1:1 连接。
-服务器(Server):你编写的轻量级程序,负责暴露具体的“能力”,比如工具函数、数据资源、提示模板。
你现在需要的就是开发一个MCP 服务器,然后将它配置到 Claude Desktop 中。开发一个服务器只需要遵循 MCP 协议,通过标准传输方式(如 stdio)与客户端通信即可。下面,上实战!
二、实战示例:构建一个“系统助手” MCP 服务器
我们将用 Python 编写一个 MCP 服务器,提供三个工具:
-get_current_time:返回当前系统时间。
-add_numbers:计算两个数的和。
-echo:回显输入的字符串(验证工具通信)。
最终效果:在 Claude Desktop 中,可以让 Claude 调用这些工具,比如问它“现在几点”或“帮我算 123+456”。
2.1 环境准备
确保你的 Python 版本 ≥ 3.10,然后安装 MCP 的 Python SDK:
pip install mcp该库提供了快速构建 MCP 服务器的装饰器和基础类。
2.2 编写服务器代码
新建一个文件system_assistant.py,内容如下:
#!/usr/bin/env python3 """ 一个简单的 MCP 服务器,暴露三个工具: - get_current_time: 获取当前时间 - add_numbers: 两数相加 - echo: 回显字符串 """ import datetime from mcp.server import Server, NotificationOptions from mcp.server.models import InitializationCapabilities from mcp.server.stdio import stdio_server import mcp.types as types # 创建服务器实例 server = Server("system-assistant") @server.list_tools() async def handle_list_tools() -> list[types.Tool]: """返回工具列表,Claude 会根据工具描述决定何时调用""" return [ types.Tool( name="get_current_time", description="获取当前系统时间,返回 ISO 格式字符串", inputSchema={ "type": "object", "properties": {}, # 无需参数 }, ), types.Tool( name="add_numbers", description="将两个数字相加,返回计算结果", inputSchema={ "type": "object", "properties": { "a": {"type": "number", "description": "第一个数"}, "b": {"type": "number", "description": "第二个数"}, }, "required": ["a", "b"], }, ), types.Tool( name="echo", description="回显用户输入的文本,可用于测试", inputSchema={ "type": "object", "properties": { "message": {"type": "string", "description": "要回显的内容"}, }, "required": ["message"], }, ), ] @server.call_tool() async def handle_call_tool( name: str, arguments: dict ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]: """当 Claude 实际调用工具时,执行对应逻辑""" if name == "get_current_time": now = datetime.datetime.now().isoformat() return [types.TextContent(type="text", text=f"当前时间:{now}")] elif name == "add_numbers": a = arguments["a"] b = arguments["b"] result = a + b return [types.TextContent(type="text", text=f"{a} + {b} = {result}")] elif name == "echo": msg = arguments["message"] return [types.TextContent(type="text", text=f"ECHO: {msg}")] # 未知工具 raise ValueError(f"未知工具: {name}") async def main(): # 启动基于标准输入输出的 MCP 服务器 async with stdio_server() as (read_stream, write_stream): await server.run( read_stream, write_stream, InitializationCapabilities( sampling={}, # 无需采样能力 experimental={} ), ) if __name__ == "__main__": import asyncio asyncio.run(main())代码解读:
-@server.list_tools()注册一个函数,返回可用工具的定义。每个工具包含名称、描述和符合 JSON Schema 的输入参数规范,这能让 Claude 在对话时自动判断何时调用哪个工具。
-@server.call_tool()是真正的执行逻辑,当 Claude 决定调用某个工具时,MCP 客户端会将工具名称和实参传入该函数,你需要在此完成具体计算,并将结果封装为TextContent返回。
- 最后使用stdio_server()启动服务器,通过标准输入/输出与 Claude Desktop 通信。这也是的推荐的本地连接方式,简单可靠。
2.3 配置 Claude Desktop
Claude Desktop 支持通过配置文件添加 MCP 服务器。
找到配置文件位置:
-macOS:~/Library/Application Support/Claude/claude_desktop_config.json
-Windows:%APPDATA%\Claude\claude_desktop_config.json
-Linux:~/.config/Claude/claude_desktop_config.json编辑该文件,添加如下内容(如果文件不存在则新建):
{ "mcpServers": { "system-assistant": { "command": "python", "args": [ "/完整路径/system_assistant.py" ] } } }将/完整路径/替换为你刚刚保存system_assistant.py的绝对路径。
如果你使用虚拟环境,请确保python指向虚拟环境中的 Python 解释器,或者使用uv等工具管理。
- 重启 Claude Desktop。此时,Claude 会自动连接该 MCP 服务器。
2.4 测试效果
重启后,在 Claude Desktop 的聊天框中检查“可用工具”图标(一个小锤子),你会看到system-assistant已经连接。然后可以这样测试:
- 输入:“现在几点了?” → Claude 会调用
get_current_time,回复时间。 - 输入:“帮我算 998 + 254” → 调用
add_numbers,返回计算结果。 - 输入:“请回显 Hello MCP” → 调用
echo,返回ECHO: Hello MCP。
恭喜!你已经成功让 Claude 突破了内置限制,获得了自定义外部能力。
三、常见问题与注意事项
1. 工具描述的重要性
Claude 对工具的调用完全是基于你提供的名称、描述和参数 schema 进行的。如果描述模糊,Claude 可能不会触发调用,或调用时参数传递错误。例如,add_numbers的描述若写成“计算”,Claude 可能不理解其用途。务必在描述中明确“两个数字相加”、“返回计算结果”等关键词。
2. 传输方式的选择
上述示例使用stdio传输,因为大多数本地服务器用这个最简单。MCP 还支持SSE (Server-Sent Events)通信,适合远程部署或需要多客户端的场景。但初学者从 stdio 入手即可。
3. 服务器进程管理
当你关闭 Claude Desktop 时,它启动的 MCP 服务器也会终止。但如果你手动杀掉了服务器进程,Claude 的对应能力会变为不可用,需要重启客户端才能恢复。调试期间,直接在终端运行python system_assistant.py可以单独测试服务器。
4. 安全考量
- 切勿在工具中执行危险的系统命令或暴露敏感数据,除非你完全清楚风险。
- MCP 协议本身不提供鉴权,若服务器通过 SSE 暴露在网络上,需要自行添加认证层。本地 stdio 模式则相对安全。
- 工具返回的信息会原样展示给用户,注意不要意外泄露密钥等信息。
5. 复杂工具的扩展
当你的工具需要访问数据库、调用 API 时,只需在handle_call_tool中完成操作。例如,接入一个天气 API:定义get_weather工具,参数为城市名,内部用httpx发起请求,将结果格式化返回。MCP 让集成难度大幅降低,你只需专注业务逻辑。
四、总结
本文通过一个极简的 Python MCP 服务器,演示了如何为 Claude Desktop 注入自定义能力。MCP 的价值在于标准化:你编写的工具不再绑定特定模型,一次开发,多处使用(未来任何支持 MCP 的客户端都能连接)。这种思路极大提升了 AI 应用的扩展性和生态活力。
学习 MCP 不意味着要抛弃现有框架,而是为你的项目增加一种更原生、更通用的集成方式。你可以基于这个示例继续添加更多工具,比如文件操作、知识库查询、甚至控制智能家居。AI 的边界,正由你来定义。
现在,打开你的编辑器,开始构建你的第一个 MCP 工具吧!
延伸阅读:
- MCP 官方文档
- Anthropic 的 Claude 工具使用指南
