别把 MCP 做成“REST API 套壳”:一篇讲透 MCP 工具设计的实战教程
最近不少团队都在上 MCP。
然后出现了一个很尴尬的场面:
看起来接入了 MCP,实际体验还不如直接调 REST API。
更扎心的是,很多所谓的 MCP Server,本质就是把原来的 REST API 原封不动包了一层。
接口名没变。 参数没变。 返回值没变。 文档还更绕了。
AI 调起来一脸懵,人用起来也一脸懵。
这就很像你给一辆自行车套了个跑车壳,然后问它为什么跑不过高铁。🚲
今天咱们就聊清楚:
- MCP 到底适合解决什么问题?
- 为什么“REST API 套壳”会翻车?
- 一个好用的 MCP 工具应该怎么设计?
- 团队落地时怎么避坑?
这篇不讲概念八股,直接讲能照着改的东西。
MCP 不是 REST API 的新皮肤
很多人一开始理解 MCP,会把它想成:
给大模型调用的 API 协议。
这个理解不算错,但太浅了。
REST API 面向的是开发者。
MCP 更偏向面向 AI Agent。
区别在哪里?
开发者会看文档,会理解业务,会知道接口之间怎么串。
AI Agent 不一样。它拿到工具之后,需要靠工具描述、参数结构和返回内容来判断:
- 这个工具能干什么?
- 什么时候该用?
- 参数该怎么填?
- 调完之后下一步做什么?
所以 MCP 工具不是“把接口暴露出去”就完事。
它更像是给 AI 准备的一套工作台。
工具摆得乱,AI 就会乱拿。 工具说明写得虚,AI 就会瞎猜。 工具返回值太脏,AI 就会读不懂。
为什么 REST API 套壳不好用?
典型翻车现场长这样:
{
"name": "getUserInfo",
"description": "获取用户信息",
"parameters": {
"userId": "string"
}
}
看起来没毛病,对吧?
问题来了。
AI 怎么知道 userId 从哪里来?
用户说:
帮我查一下张三最近三个月的订单情况。
你的工具只有 getUserInfo(userId)。
AI 手里没有 userId。 它可能会猜。 它可能会问用户。 它可能会放弃。 它也可能乱调用。
如果你还有一堆接口:
getUserInfo
getUserByPhone
getOrderList
getOrderDetail
getPaymentInfo
getRefundList
getCouponList
开发者知道怎么串。
AI 未必知道。
这就是“REST API 套壳”的最大问题:
它把技术接口丢给了 AI,却没有把业务动作交给 AI。
REST API 和 MCP 的设计目标不一样
咱们用一个客服场景看。
用户问:
帮我看看这个客户为什么投诉退款还没到账。
如果你只有 REST API 思路,可能会设计成这样:
getCustomerByName
getCustomerOrders
getOrderRefunds
getRefundStatus
getPaymentChannel
getTicketList
每个接口都很干净。 后端同学看了很舒服。
但 AI 需要自己判断调用顺序:
- 先找客户
- 再找订单
- 再查退款
- 再查支付渠道
- 再查工单
- 再组织答案
链路一长,就容易出错。
MCP 更适合把工具设计成业务动作:
investigate_refund_delay
描述可以写成:
用于排查客户退款未到账的原因。输入客户姓名、手机号或订单号,工具会自动查询相关订单、退款记录、支付渠道状态和客服工单,返回可直接解释给客户的排查结论。
参数也更贴近用户表达:
{
"customer_name": "张三",
"phone": "可选",
"order_id": "可选",
"time_range": "最近三个月"
}
返回值别甩一堆数据库字段。
给 AI 能读的结构:
{
"status": "refund_pending",
"reason": "退款已发起,但支付渠道尚未完成入账处理",
"related_order": "20240518001",
"refund_amount": 199,
"expected_arrival_time": "1-2个工作日",
"suggested_reply": "这笔退款已经提交到支付渠道,预计1-2个工作日到账。建议客户关注原支付账户。",
"next_action": "如超过2个工作日未到账,可升级给财务客服处理"
}
这才是 MCP 的味道。
不是暴露接口。
是交付一个能完成任务的工具。
一个好 MCP 工具,应该长什么样?
你可以按这 5 个标准检查。
1. 工具名要像“动作”,别像数据库接口
别这样:
query_order_table
get_user_data
select_refund_record
AI 看了也累。
改成这样:
find_customer_orders
check_refund_status
analyze_order_problem
create_customer_service_ticket
工具名要回答一个问题:
AI 在什么任务里会用它?
如果工具名只能让后端看懂,不适合直接扔给 Agent。
2. 描述要写“使用场景”,别只写功能
很多工具描述写得像废话:
获取订单信息。
这对 AI 帮助很小。
更好的写法:
当用户询问订单状态、物流进度、退款相关问题时使用。支持通过订单号、手机号或客户姓名查询订单摘要,返回订单状态、支付状态、物流状态和异常提示。
注意这个描述里包含了:
- 什么时候用
- 支持哪些输入
- 会返回什么
- 适合解决什么问题
AI 需要的就是这些。
3. 参数要贴近用户语言
用户不会说:
请使用 customer_primary_key 查询我的售后记录。
用户会说:
我手机号是 138xxxx,帮我看看退款到哪了。
所以 MCP 参数别只围着数据库主键转。
可以支持这些入口:
{
"order_id": "可选,订单号",
"phone": "可选,客户手机号",
"customer_name": "可选,客户姓名",
"issue_type": "退款未到账 / 物流异常 / 商品损坏 / 其他",
"time_range": "可选,比如最近30天"
}
一个好工具要尽量吃得下用户的自然表达。
别逼 AI 先做一堆“查 ID”的苦力活。
4. 返回结果要给结论,别只给原始数据
这点特别关键。
很多 MCP 工具返回长这样:
{
"refund_status": 2,
"pay_channel": "WX",
"updated_at": "2024-05-18T10:21:00Z",
"biz_code": "RFD_PENDING_CHANNEL"
}
人都得查枚举表,AI 更容易解释错。
更好的返回:
{
"refund_status": "处理中",
"status_explanation": "退款已经从商户侧发起,正在等待微信支付渠道入账确认",
"expected_arrival_time": "1-2个工作日",
"risk_level": "低",
"suggested_response": "您的退款已经提交,预计1-2个工作日退回原支付账户。",
"need_human_followup": false
}
AI 不怕结构化数据。
AI 怕的是没上下文的脏数据。
5. 工具粒度别太碎,也别太胖
太碎的问题:
get_user
get_order
get_refund
get_payment
get_ticket
AI 要自己串流程。 调用次数多,错误率高。
太胖的问题:
handle_everything
描述写不清,边界模糊。 AI 不知道什么时候该用,后端也不好维护。
比较舒服的粒度是:
一个工具解决一个明确业务任务。
例如:
check_refund_status
analyze_delivery_delay
summarize_customer_history
create_after_sales_ticket
search_internal_policy
每个工具都有清晰边界。 Agent 调用时也不容易乱。
实战示例:把一个 REST API 改成 MCP 工具
假设你现在有一个订单接口:
GET /api/orders/{orderId}
返回:
{
"id": "O123",
"user_id": "U456",
"status": 3,
"paid": true,
"logistics_code": "SF123456",
"created_at": "2024-05-01"
}
如果直接包成 MCP,大概是这样:
{
"name": "get_order_by_id",
"description": "根据订单ID获取订单信息",
"inputSchema": {
"order_id": "string"
}
}
能用。
但不好用。
改成更适合 AI 的版本:
{
"name": "check_order_status",
"description": "当用户询问订单是否发货、物流到哪里、订单是否支付、订单是否异常时使用。支持通过订单号查询订单状态,并返回适合直接回复用户的解释。",
"inputSchema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "用户提供的订单号"
}
},
"required": ["order_id"]
}
}
返回值建议这样封装:
{
"order_id": "O123",
"order_status": "已发货",
"payment_status": "已支付",
"delivery_status": "运输中",
"logistics_company": "顺丰",
"tracking_number": "SF123456",
"summary": "订单已支付并发货,目前由顺丰运输中。",
"suggested_reply": "您的订单已经发货,目前正在运输中,物流单号是 SF123456。",
"next_action": "如果用户追问预计送达时间,可继续查询物流详情。"
}
差别非常明显。
前者是接口。
后者是工具。
什么时候 REST API 就够了?
别一听 MCP 火,就什么都往 MCP 里塞。
下面这些场景,REST API 仍然很好用:
- 前端页面固定展示数据
- 移动端 App 调后端接口
- 内部系统之间做稳定集成
- 调用方是明确的程序,不需要模型判断
- 数据结构稳定,流程固定
比如一个后台列表页,要分页查订单。
REST API 很合适。
没必要强行搞 MCP。
MCP 更适合这些场景:
- AI 助手需要自己判断该调用哪个工具
- 用户输入是自然语言,不是固定表单
- 任务需要跨多个系统查信息
- 返回结果要给模型继续推理
- 业务动作比底层接口更重要
比如客服助手、数据分析助手、研发运维助手、企业知识库助手。
这些地方 MCP 的价值会明显很多。
MCP 工具设计 checklist
做完一个 MCP Server,别急着上线。
拿这份清单过一遍。
工具命名
- 名字是不是一个明确动作?
- AI 只看名字能不能猜到用途?
- 有没有一堆
get_xxx、query_xxx、select_xxx?
工具描述
- 有没有写清楚使用场景?
- 有没有说明不该什么时候用?
- 有没有告诉 AI 返回结果能做什么?
参数设计
- 参数是不是贴近用户表达?
- 是否支持手机号、姓名、订单号这类常见入口?
- 必填字段是不是过多?
- 参数描述有没有写具体例子?
返回结构
- 有没有返回可读结论?
- 有没有给 suggested_reply 这类可直接复用的内容?
- 有没有把枚举值翻译成人话?
- 有没有 next_action 帮 AI 决定下一步?
工具粒度
- 是否一个工具解决一个业务任务?
- 有没有拆得太碎,导致 Agent 要连续调十几个工具?
- 有没有胖成一个万能工具,边界完全失控?
常见坑:别让 MCP 变成“更难用的 API”
坑 1:把所有后端接口都自动生成 MCP 工具
听起来省事。
实际上很容易产出一堆 AI 不会用的工具。
后端接口通常按资源、表、服务拆。
AI 工具应该按任务拆。
这两套逻辑不一样。
自动生成可以当起点,不能当终点。
坑 2:工具描述写得太短
查询用户信息 这种描述,真的别再写了。
它没有告诉模型:
- 什么情况下查?
- 用什么字段查?
- 查不到怎么办?
- 返回结果怎么用?
描述不是写给人类后端看的。
描述是给模型做决策用的。
写细一点,不丢人。
坑 3:返回原始数据库字段
status = 3。
这到底是已发货、已退款,还是已取消?
别让 AI 猜枚举。
你自己都不想猜,模型凭什么猜得准?
返回时直接给中文解释、业务状态、建议话术。
准确率会高很多。
坑 4:权限和安全没设计
MCP 工具一旦接入 Agent,调用门槛会变低。
必须提前处理:
- 哪些工具只读?
- 哪些工具会写入数据?
- 删除、退款、发券这类高风险动作要不要二次确认?
- 是否要记录调用日志?
- 是否要按用户角色控制权限?
特别是 delete、refund、send_coupon、update_salary 这类工具。
别让 AI 一句话把生产数据改飞了。
坑 5:没有做工具调用测试
MCP 工具不是能跑就算完成。
你要拿真实问题测试。
比如客服场景,可以准备这些问题:
帮我查一下张三退款为什么还没到账
客户说订单一直没发货,手机号是 138xxxx
这个用户最近投诉很多吗?
帮我总结一下客户最近三个月的售后情况
如果客户要求赔偿,我该怎么回复?
看 Agent 会不会选对工具。
看参数填得对不对。
看返回结果能不能支撑最终回答。
这一步比写协议更重要。
一个简单的 MCP 改造思路
如果你已经有一堆 REST API,别推倒重来。
可以这样改。
从高频场景下手
别一口气包全系统。
挑最常见的问题:
- 查订单
- 查退款
- 查物流
- 查客户历史
- 创建工单
- 搜索内部知识库
这些场景用户天天问,改完立刻能看到效果。
把接口组合成业务工具
一个 MCP 工具背后可以调用多个 REST API。
比如:
check_refund_status
背后可以调用:
用户接口
订单接口
退款接口
支付渠道接口
工单接口
对 AI 暴露一个工具。
复杂度藏在服务端。
AI 负责判断任务。 服务端负责稳定执行。
分工清楚,系统才稳。
给返回值加“人话层”
内部字段可以保留。
但要额外补充:
{
"summary": "一句话结论",
"reason": "原因解释",
"suggested_reply": "建议回复用户的话术",
"next_action": "下一步建议",
"need_human_followup": true
}
这几个字段非常值钱。
它们能让 Agent 少编、少猜、少跑偏。
判断 MCP 做得好不好,看这 3 件事
别只看“能不能调通”。
调通只是及格线。
更该看这三个指标。
1. AI 是否会主动选对工具
用户自然表达一个问题,Agent 能不能选对工具?
如果它总是乱选,工具描述和命名大概率有问题。
2. AI 是否能一次填对参数
如果每次都缺字段、填错字段、把姓名填进手机号,参数设计大概率不够贴近用户语言。
3. AI 是否能基于返回结果给出靠谱回答
如果工具返回后,AI 还在胡编,返回结构大概率太原始。
给它结论。 给它解释。 给它下一步。 别只给字段。
写在后面
MCP 的价值,不是把 REST API 换个包装。
真正的价值在于:
把系统能力整理成 AI 能理解、能判断、能执行的业务工具。
REST API 是给程序员用的。
MCP 工具是给 Agent 用的。
程序员能忍受复杂接口,因为程序员会读文档、会查代码、会问同事。
Agent 不行。
你给它的工具越像真实工作动作,它越容易干好活。
所以别再做“REST API 套壳版 MCP”了。
那玩意儿看着赶潮流,用起来真难受。