首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >用 WorkBuddy 从零搭建一个 MCP Server:把内部 API 变成大模型能直接调用的工具

用 WorkBuddy 从零搭建一个 MCP Server:把内部 API 变成大模型能直接调用的工具

原创
作者头像
正直的数据官小瓦
发布于 2026-09-21 16:25:53
发布于 2026-09-21 16:25:53
2060
举报

摘要

大模型很聪明,但它默认是「瞎子」——看不到你的数据库、调不了你的内部系统、读不到你公司的文档。过去每个团队都在重复造轮子:写一堆胶水代码把 API 包成提示词。MCP(Model Context Protocol,模型上下文协议)的出现改变了这一点:它把「模型连外部世界」这件事标准化了。本文用 WorkBuddy 作为编排端,手把手带你用 Python 从零写一个 MCP Server,把任意一个内部 HTTP API 暴露成大模型可调用的标准工具,并讲清传输层、鉴权、动态注册、排错这些生产环境才会遇到的问题。读完你就能把公司里任何一个系统「接」进大模型。


一、为什么你需要 MCP:一个被忽视的痛点

先说一个真实场景。假设你公司有一套「订单查询系统」,提供 REST 接口:传订单号,返回订单状态、金额、物流节点。你想让客服同学用自然语言问大模型:「查一下订单 A12345 到哪了?」大模型本身做不到——它不知道这个接口长什么样,也调不了。

传统的做法是「提示词工程 + 代码封装」:

  • 要么把接口文档整段塞进提示词,让模型「照着调」,但上下文一长就乱,还容易幻觉出错的参数;
  • 要么你写个后端服务,解析模型输出的 JSON,再转发到真实接口,自己做解析、校验、错误处理。

这两种都脆弱。更糟的是,每接一个系统就要重写一遍,十几个系统就是十几个半成品。

MCP 想解决的就是这个「N 个模型 × M 个工具」的组合爆炸。它定义了一套标准协议:只要你的工具按 MCP 规范暴露出来,任何支持 MCP 的客户端(Claude Desktop、WorkBuddy、Cursor 等)都能即插即用。你写一次 Server,所有客户端通用。

对开发者来说,MCP 的价值可以一句话概括:把「调接口」这件事,从写代码变成了「声明一个工具」。


二、MCP 到底是什么:三个核心概念

MCP 采用经典的客户端-服务器架构,但层次比你想的清晰。理解这三层,后面写代码就不迷路。

2.1 三个角色

  • Host(宿主):你日常使用的 AI 应用,比如 WorkBuddy。它负责跑大模型、管理对话、决定什么时候调用哪个工具。
  • Client(客户端):Host 内部为每个 Server 维护的一个连接器,一对一连到某个 Server,负责协议通信。
  • Server(服务器):你写的那个程序,对外暴露「能力」。它跑在本地或远程,不跑模型,只提供数据或动作。

注意一个常见误解:Server 里不放大模型,它只是「能力提供方」。模型在 Host 里,Server 是被调用的。

2.2 三种能力原语

MCP Server 能向外暴露三类东西,理解它们的区别很重要:

  • Tools(工具):模型可以「主动调用」的动作,比如「查询订单」「发送消息」。这是最常用的,带副作用、有输入参数、返回结果。本文重点就是写 Tool。
  • Resources(资源):类似「文件」或「只读数据」,比如一份配置文件、一个数据库表的快照。模型通过 URI 读取,不主动执行。
  • Prompts(提示词模板):预定义的提示词片段,用户手动触发,比如「总结这份日志」的固定模板。

对大多数工程场景,你 80% 的精力会花在 Tool 上。

2.3 两种传输方式

  • stdio(标准输入输出):Server 作为本地子进程启动,Host 通过标准流和它通信。适合本地工具、命令行程序,零网络配置,最常用。
  • SSE / Streamable HTTP:Server 跑在远端服务器,Host 通过 HTTP 长连接通信。适合多人共享的「云端工具」。

新手一律先用 stdio,踩坑最少。本文示例也用 stdio。


三、动手前准备:环境与心智模型

动手前,先把心智模型钉死:你不是在「教模型调接口」,而是在「给模型一个标准工具描述」。模型看到的是工具的名字、一句话说明、参数 schema,然后它自己决定什么时候用、传什么参数。你写 Server 的本质,就是把这个「名字 + 说明 + 参数 + 执行逻辑」描述清楚。

环境准备(以 Python 为例):

  • Python 3.10 或以上
  • 安装官方 SDK:pip install mcp
  • 推荐用 FastMCP 高层封装(来自 mcp.server.fastmcp),它用装饰器就能定义工具,省去大量样板代码
  • 一个你熟悉的内部 API(本文用一个虚构的「订单查询 API」作示例,你把地址换成自己的即可)

不需要 Docker、不需要框架,一个 .py 文件就能跑起来。


四、核心实战:写一个订单查询 MCP Server

下面这个类比是关键:你写的每个 Tool,本质是一个被 @mcp.tool() 装饰的普通 Python 函数。函数的 docstring 就是给模型看的「说明书」,函数的参数就是模型的「输入表单」,函数返回值就是「工具结果」。

4.1 最小可运行版本

下面是一个最小但完整的 MCP Server,它暴露一个 query_order 工具:



from mcp.server.fastmcp import FastMCP import httpx import os

mcp = FastMCP("order-tool-server")

ORDER_API_BASE = os.getenv("ORDER_API_BASE", "https://api.example.com") ORDER_API_TOKEN = os.getenv("ORDER_API_TOKEN", "")

@mcp.tool() async def query_order(order_id: str) -> str: """根据订单号查询订单的状态、金额和最新物流节点。

if name == "main": mcp.run(transport="stdio")


4.2 这段代码在做什么

逐行拆解,确保你真的懂:

  • FastMCP("order-tool-server"):创建一个 Server 实例,名字随便起,会显示在客户端里。
  • @mcp.tool():把下面这个函数注册成一个 MCP 工具。模型看到的工具名就是函数名 query_order。
  • docstring 极其重要:模型靠它判断「这个工具干嘛用的、什么时候该调」。写得含糊,模型就不会用;写清楚输入输出,模型调用准确率直线上升。这是写 MCP Server 最容易忽略、却最影响效果的地方。
  • 类型注解 order_id: str:SDK 会自动把它转成 JSON Schema 的一部分,模型知道要传字符串。
  • 返回值 str:工具结果以文本形式回传给模型。复杂结构建议序列化成 JSON 字符串,模型照样能读。

4.3 让它更健壮:参数校验与错误处理

生产环境绝不能像上面那样裸奔。模型偶尔会传错参数(比如传了空字符串、传了 SQL 片段)。加上校验:



from mcp.server.fastmcp import FastMCP import httpx, os, re

mcp = FastMCP("order-tool-server-v2") ORDER_API_BASE = os.getenv("ORDER_API_BASE", "https://api.example.com") ORDER_API_TOKEN = os.getenv("ORDER_API_TOKEN", "")

@mcp.tool() async def query_order(order_id: str) -> str: """根据订单号查询订单的状态、金额和最新物流节点。 Args: order_id: 订单编号,纯字母数字,例如 A12345 """ if not re.fullmatch(r"[A-Za-z0-9]{3,20}", order_id): return "参数错误:订单号需为3-20位字母或数字,请确认后重试。"

if name == "main": mcp.run(transport="stdio")


注意三个工程化细节:

  1. 入参用正则先挡一道:模型不是神仙,会传脏数据。先校验再发请求,省得把垃圾打到后端。
  2. 区分「业务错误」和「系统错误」:订单不存在(404)是正常业务结果,要友好返回;超时是系统问题,要明确告知。两类错误返回不同文案,模型才能正确决策下一步。
  3. 异常别直接抛:MCP 里抛未捕获异常会让整个工具调用崩掉。统一 catch 成字符串返回,模型能接着对话。

五、在 WorkBuddy 里接上这个 Server

Server 写好了,怎么让 WorkBuddy 用上它?核心是把 Server 注册进客户端的 MCP 配置。不同客户端配置位置不同,但结构一致:告诉客户端「Server 的名字、启动命令、环境变量」。

以 stdio 方式为例,WorkBuddy 的 MCP 配置文件(通常是 mcp.json)里加一段:



{ "mcpServers": { "order-tool": { "command": "python", "args": ["/绝对路径/order_server.py"], "env": { "ORDER_API_BASE": "https://api.example.com", "ORDER_API_TOKEN": "你的令牌" } } } }


填好后重启 WorkBuddy(或点「信任」新 Server),它会在后台拉起你的 order_server.py 子进程,自动发现 query_order 工具。之后你在对话里说「查订单 A12345」,WorkBuddy 就会自动调用这个工具,把结果拼回回答里——你完全不用写调用代码。

这一步的意义:你的订单系统现在成了 WorkBuddy 的「原生能力」。任何同事用 WorkBuddy 都能查订单,不用知道接口细节。这就是 MCP 的威力——一次接入,处处可用。


六、进阶:不止工具,还有资源和鉴权

写了工具只是入门。三个进阶点能让你在团队里显得专业。

6.1 暴露 Resource(只读数据)

有些东西不适合做成「动作」,而适合做成「可读取的数据」。比如一份「配送区域表」:



@mcp.resource("config://delivery-zones") def delivery_zones() -> str: """返回当前支持的配送区域列表,供模型参考。""" zones = ["南宁", "柳州", "桂林", "北海"] return "支持的配送区域:" + "、".join(zones)


模型在需要时会通过 config://delivery-zones 这个 URI 读取它,不会误当成「要执行某个动作」。

6.2 动态注册工具(插件化)

如果你的工具有几十个,一个个写函数太笨。可以用循环动态注册:



TOOL_REGISTRY = { "query_order": {...}, "refund_order": {...}, }

for name, spec in TOOL_REGISTRY.items(): mcp.add_tool(fn=build_handler(spec), name=name, description=spec["desc"])


这样你可以用配置文件驱动工具列表,新增工具改配置即可,不用动代码。

6.3 鉴权与安全

如果 Server 跑在远端(SSE 模式),必须加鉴权:

  • 用环境变量注入令牌,绝不硬编码进代码或提交到 Git;
  • 远端 Server 前面套一层 API 网关,做限流和审计;
  • 工具内部对参数做白名单校验,防止提示词注入(模型传入的 order_id 里夹带恶意指令,要在执行前剥离)。

安全提醒:MCP Server 等于把系统能力开放给大模型,参数校验和鉴权不是可选项,是必选项。


七、常见坑与排错清单

这部分是血泪经验,照着排查能省几小时。

  1. Server 启动就崩:看客户端日志,多半是 pip install mcp 没装对版本,或 Python 路径不对。用绝对路径指定 python 解释器最稳。
  2. 工具不显示:确认 mcp.run(transport="stdio") 写对了,且配置里 args 的路径是绝对路径。相对路径在子进程里会找不到文件。
  3. 模型不调用工具:九成是 docstring 写得太含糊。把「什么时候用、参数格式、返回什么」写清楚,效果立竿见影。
  4. 返回中文乱码:确保文件用 UTF-8 保存,且 httpx 拿到的响应 .json() 正确解码。
  5. 工具被注入攻击:模型可能把用户问题里的指令当作工具参数。对参数做白名单 + 转义,别直接拼进命令或 SQL。
  6. SSE 模式连不上:检查防火墙、确认网关转发了正确的端口和协议,stdio 改 SSE 后握手逻辑不同。

八、总结

MCP 把「大模型连外部系统」从手工胶水代码,升级成了标准协议。你今天学会的三件事:

  • 心智模型:写 Server 不是写调用代码,而是「声明一个工具」(名字 + 说明 + 参数 + 逻辑);
  • 最小实现:一个 @mcp.tool() 装饰的函数就能暴露一个工具,docstring 是效果的关键;
  • 生产三件套:参数校验、错误分类、鉴权安全,缺一不可。

下一步你可以把公司里任何系统——CRM、工单、库存、知识库——都按这个模板接进来。当你的 WorkBuddy 能查订单、能看库存、能发工单,它就从「聊天机器人」变成了「真正能干活的同事」。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 摘要
  • 一、为什么你需要 MCP:一个被忽视的痛点
  • 二、MCP 到底是什么:三个核心概念
    • 2.1 三个角色
    • 2.2 三种能力原语
    • 2.3 两种传输方式
  • 三、动手前准备:环境与心智模型
  • 四、核心实战:写一个订单查询 MCP Server
    • 4.1 最小可运行版本
  • if name == "main": mcp.run(transport="stdio")
    • 4.2 这段代码在做什么
    • 4.3 让它更健壮:参数校验与错误处理
  • if name == "main": mcp.run(transport="stdio")
  • 五、在 WorkBuddy 里接上这个 Server
  • { "mcpServers": { "order-tool": { "command": "python", "args": ["/绝对路径/order_server.py"], "env": { "ORDER_API_BASE": "https://api.example.com", "ORDER_API_TOKEN": "你的令牌" } } } }
  • 六、进阶:不止工具,还有资源和鉴权
    • 6.1 暴露 Resource(只读数据)
  • @mcp.resource("config://delivery-zones") def delivery_zones() -> str: """返回当前支持的配送区域列表,供模型参考。""" zones = ["南宁", "柳州", "桂林", "北海"] return "支持的配送区域:" + "、".join(zones)
    • 6.2 动态注册工具(插件化)
  • for name, spec in TOOL_REGISTRY.items(): mcp.add_tool(fn=build_handler(spec), name=name, description=spec["desc"])
    • 6.3 鉴权与安全
  • 七、常见坑与排错清单
  • 八、总结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档