news 2026/10/1 5:35:09

独立开发者如何为小产品构建MCP Server:让AI代理自动发现并调用你的服务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
独立开发者如何为小产品构建MCP Server:让AI代理自动发现并调用你的服务

1. 一个独立开发者为什么要给自己的小产品写 MCP server

先说结论:我给我的小产品写了一个 MCP server,现在 Claude、Cursor 这类 AI 代理在对话里就能直接「发现」它、读取它的能力清单,甚至自动完成报价和下单流程。整个过程不需要用户手动打开浏览器、复制粘贴参数,也不需要我再去对接一堆平台方的私有协议。

这件事的背景其实很简单。我手上有一个小产品,提供的是某种标准化的服务能力(具体业务不展开,你可以理解成「按量计费的 API 服务」)。过去用户想用它,路径是这样的:打开我的官网,看文档,注册账号,拿 API key,写代码调用。这条链路对开发者还算友好,但对大量非技术用户来说,门槛高得离谱。而 2024 年下半年开始,越来越多人习惯直接问 AI:「帮我找个能做 XX 的服务」,然后让 AI 去执行。问题来了——AI 怎么知道我的产品存在?就算知道了,它怎么调用?

MCP(Model Context Protocol)就是解决这个问题的。它本质上是一套让 AI 代理和外部工具/服务对话的标准协议。你可以把它类比成「AI 世界的 USB 接口」:以前每个 AI 工具都要为每个外部服务写一套私有对接代码,现在只要服务方实现一个 MCP server,所有支持 MCP 的客户端(Claude Desktop、Cursor、各种 IDE 插件)都能即插即用。

我写这个 MCP server 的核心动机有三个。第一,降低发现成本:让 AI 代理能主动「看到」我的服务,而不是等用户去搜。第二,降低调用成本:把「注册-拿 key-写代码」压缩成「AI 直接调用」。第三,探索 agent-to-agent commerce:当 AI 代理可以自主发现服务、比较报价、完成交易时,商业的入口就从「人找服务」变成了「代理找服务」。这是个趋势,早入场比晚入场好。

这篇文章我会把整个实现过程拆开讲:协议怎么理解、server 怎么设计、工具怎么暴露、报价逻辑怎么处理、和 Claude/Cursor 怎么联调、踩了哪些坑。适合两类人看:一是手里有小产品、想让 AI 代理能调用它的独立开发者;二是想搞懂 MCP 到底怎么回事、准备自己动手写一个的技术同学。不需要你之前用过 MCP,但需要你会一点 Python 或 TypeScript,懂基本的 HTTP 和 JSON。

2. MCP 协议到底在解决什么问题

2.1 从「函数调用」到「标准化工具暴露」

很多人第一次接触 MCP 会懵:这不就是 function calling 吗?OpenAI 早就有了。区别在哪?

Function calling 是单个 AI 应用内部的能力:你在调用某个模型时,把可用的函数列表塞进 prompt,模型决定调哪个,你的代码去执行。这套机制的问题在于,它是绑死在具体应用里的。你在 Claude Desktop 里定义的工具,Cursor 用不了;你在自己写的 agent 里定义的工具,换个框架就得重写。

MCP 把这个过程协议化了。它定义了一套标准的通信方式:客户端(AI 应用)和服务端(工具提供方)通过 JSON-RPC 通信,服务端声明自己有哪些 tools、resources、prompts,客户端负责把这些能力转译给模型。模型看到的还是「工具列表」,但底层已经解耦了。

这个解耦带来的直接好处是:我写一次 MCP server,所有支持 MCP 的客户端都能用。Claude Desktop 能调,Cursor 能调,以后任何新出的 AI IDE 只要支持 MCP,我的服务就自动在里面可用。这就是我决定投入时间写它的根本原因——一次投入,多端复用。

2.2 MCP 的三个核心原语:Tools、Resources、Prompts

MCP 协议里服务端可以暴露三类东西,理解这三类是设计 server 的基础。

Tools(工具)是最重要的。它代表「可以被 AI 调用的动作」,比如「查询价格」「创建订单」「获取服务状态」。每个 tool 有名字、描述、输入参数的 JSON Schema。AI 根据描述决定什么时候调、传什么参数。这是 agent-to-agent commerce 的核心——AI 通过 tools 完成实际交易动作。

Resources(资源)代表「可以被读取的数据」,比如文档、配置、数据库记录。它和 tools 的区别是:resources 是只读的、被动的,AI 读取它来获取上下文;tools 是主动的、有副作用的。我的产品里,resources 用来暴露服务说明、价格表、SLA 文档。

Prompts(提示模板)是预定义的提示词模板,用户可以主动选择。这个我用得少,因为我的场景里 AI 是自主决策的,不太需要用户手动选模板。但如果你做的是「引导式」产品,prompts 很有用。

设计时的关键判断:哪些能力该做成 tool,哪些该做成 resource。我的原则是——如果这个操作会改变状态(下单、扣费、创建资源),必须是 tool;如果只是读取信息(查价、看文档),优先做 resource,因为 resource 更轻量,AI 读取时不需要「调用」的仪式感。

2.3 传输层:stdio 还是 HTTP

MCP 支持两种传输方式:stdio(标准输入输出)和HTTP with SSE(Server-Sent Events)。

stdio 适合本地运行的服务:客户端启动时把 server 作为子进程拉起来,通过标准输入输出通信。Claude Desktop、Cursor 本地配置 MCP server 时默认走这条路。优点是简单、无需网络配置、天然隔离;缺点是只能本地用,没法部署到服务器给多人共享。

HTTP+SSE 适合远程服务:server 部署在公网,客户端通过 URL 连接。这是我要走的路,因为我的产品是给所有用户用的,不可能让每个人都本地跑一个 server。

实际实现时我用了官方 SDK 的 Streamable HTTP 传输(这是较新的方式,比早期的 SSE 方案更稳定)。配置上就是暴露一个/mcp端点,客户端用 URL 连接。这里有个坑后面会讲:认证怎么做。stdio 模式下进程隔离,不太需要考虑鉴权;HTTP 模式下必须考虑,否则任何人都能调你的付费接口。

3. 我的 MCP server 架构设计

3.1 整体分层:协议层、业务层、计费层

我没有把 MCP server 写成一个大文件,而是分了三层,这个结构在后期维护时救了我很多次。

协议层负责 MCP 协议的实现:注册 tools、处理 JSON-RPC 请求、参数校验、错误格式化。这一层用官方 SDK,尽量薄,不掺业务逻辑。好处是协议升级时改动集中在这里。

业务层是真正的服务能力:查询、下单、状态检查。这一层是我原有的业务代码,MCP server 只是给它套了个壳。关键设计:MCP server 不重新实现业务,只做适配。这样业务逻辑只有一份,不会出现「网页端和 MCP 端行为不一致」的问题。

计费层单独抽出来,因为 agent-to-agent commerce 的核心就是「AI 调用要能计费」。这一层处理配额检查、扣费、生成账单。它被业务层调用,但独立于协议层。

分层的直接收益:调试时我能明确知道问题出在哪一层。协议层报错通常是 schema 写错了;业务层报错是逻辑问题;计费层报错多半是配额或并发问题。

3.2 工具清单设计:让 AI 一眼看懂你能干什么

工具清单是 AI 代理「发现」你的产品的唯一入口,设计得好不好直接决定 AI 会不会用你。

我最终暴露了 5 个 tool,每个都经过反复打磨描述文案:

Tool 名称作用关键参数是否有副作用
list_services列出所有可用服务及简介无否
get_quote根据需求返回报价service_id, quantity, options否
create_order创建订单并返回订单号quote_id, confirm_token是
get_order_status查询订单状态order_id否
get_service_docs获取某服务的详细文档service_id否

设计原则有三条。第一,读操作和写操作分离:get_quote和create_order分开,让 AI 可以先报价、让用户确认、再下单。这符合 agent-to-agent commerce 的信任模型——AI 不应该在用户没确认的情况下直接扣费。

第二,报价和下单之间用 quote_id 绑定。get_quote返回一个带时效的 quote_id,create_order必须带上它。这样能防止「AI 拿旧价格下单」的问题,也让我能在服务端校验价格一致性。

第三,描述文案要写给 AI 看,不是写给人看。我最初的描述是「获取报价」,太模糊。改成「根据服务 ID、数量和可选配置,返回当前有效报价及报价有效期。报价 15 分钟内有效,下单时需携带返回的 quote_id」之后,AI 的调用准确率明显提升。描述里要包含:什么时候用、参数含义、返回值含义、约束条件。

3.3 报价逻辑:为什么不能直接返回一个数字

报价这块我踩过坑。最初get_quote直接返回一个价格数字,结果 AI 在对话里说「这个服务 100 元」,用户问「为什么是 100」,AI 答不上来,因为它只拿到了一个数字。

后来我改成返回结构化报价:

{ "quote_id": "q_abc123", "service_id": "svc_translate", "unit_price": 0.05, "quantity": 2000, "subtotal": 100.0, "discount": 0.0, "total": 100.0, "currency": "CNY", "valid_until": "2025-01-01T12:15:00Z", "breakdown": [ {"item": "基础翻译", "unit": "千字", "qty": 2, "price": 50.0} ] }

这样 AI 能向用户解释价格构成,用户也更信任。breakdown字段是关键——它让报价「可解释」。在 agent-to-agent commerce 场景里,可解释性直接影响成交率,因为用户会追问,AI 答不上来就会放弃。

valid_until也很重要。报价有时效,过期后create_order会拒绝,AI 需要重新报价。这防止了价格波动带来的纠纷。

4. 动手实现:从零到能被 Claude 调用

4.1 环境准备与依赖安装

我用 Python 实现,因为业务代码本来就是 Python。官方 SDK 是mcp,安装很简单:

pip install mcp

如果你用 TypeScript,对应的是@modelcontextprotocol/sdk。两者 API 设计思路一致,选你熟悉的。

环境上要注意 Python 版本,我用的是 3.11。3.10 以下某些类型语法会报错。另外建议用虚拟环境,因为 MCP SDK 迭代较快,隔离环境方便升级。

4.2 最小可运行 server 骨架

先上一个最小骨架,让你看到全貌:

from mcp.server.fastmcp import FastMCP mcp = FastMCP("my-product-server") @mcp.tool() def list_services() -> list[dict]: """列出所有可用服务及其简介。""" return [ {"id": "svc_translate", "name": "文本翻译", "desc": "中英互译,按千字计费"}, {"id": "svc_summarize", "name": "文本摘要", "desc": "长文摘要,按篇计费"}, ] @mcp.tool() def get_quote(service_id: str, quantity: int) -> dict: """根据服务 ID 和数量返回报价。报价 15 分钟内有效。""" # 业务逻辑:查价、算折扣、生成 quote_id ... if __name__ == "__main__": mcp.run(transport="streamable-http")

FastMCP是官方提供的高层封装,装饰器一挂,函数签名自动转成 JSON Schema,docstring 自动变成 tool 描述。这个设计非常省事,但有个坑:docstring 会被原样暴露给 AI,所以别在里面写内部注释或 TODO。

4.3 参数校验与错误处理

AI 传参是不可控的。它可能传字符串给整型参数,可能漏传必填项,可能传一个不存在的 service_id。这些都要在服务端兜住。

我的做法是:用 Pydantic 定义参数模型,让 SDK 自动校验。FastMCP 支持直接标注类型,但复杂校验还是 Pydantic 更清晰:

from pydantic import BaseModel, Field class QuoteRequest(BaseModel): service_id: str = Field(..., description="服务 ID,来自 list_services") quantity: int = Field(..., gt=0, le=100000, description="数量,必须为正整数") @mcp.tool() def get_quote(req: QuoteRequest) -> dict: ...

错误处理上,不要抛裸异常。MCP 协议里 tool 执行失败应该返回结构化的错误信息,让 AI 能理解并决定下一步。我统一用这样的返回:

return { "error": "INVALID_SERVICE", "message": "服务 ID 不存在,请先调用 list_services 获取有效 ID", "retryable": False }

retryable字段很关键。如果是临时故障(比如下游超时),标True,AI 会重试;如果是参数错误,标False,AI 会换参数或告知用户。这个字段让 AI 的决策更聪明。

4.4 认证与配额:HTTP 模式下的必答题

stdio 模式下进程隔离,鉴权压力小。HTTP 模式下,任何人都能访问你的/mcp端点,必须做认证。

我的方案是Bearer Token + 用户绑定。用户在网页端登录后生成一个 MCP token,配置到 Claude/Cursor 里。server 收到请求后校验 token,解析出用户身份,后续所有操作都绑定到这个用户。

from mcp.server.fastmcp import FastMCP from starlette.middleware.base import BaseHTTPMiddleware class AuthMiddleware(BaseHTTPMiddleware): async def dispatch(self, request, call_next): token = request.headers.get("authorization", "").replace("Bearer ", "") user = verify_token(token) if not user: return JSONResponse({"error": "unauthorized"}, status_code=401) request.state.user = user return await call_next(request)

配额检查放在业务层,每次 tool 调用前先查用户剩余额度。这里有个细节:报价不扣费,下单才扣费。因为报价是只读操作,如果报价也扣费,AI 反复报价会烧掉用户额度,体验很差。

注意:token 一定要支持吊销。用户可能把 token 泄露了,或者想换设备。我在网页端做了「重新生成 token」按钮,旧 token 立即失效。

5. 让 AI 代理真正「发现」并调用你的服务

5.1 在 Claude Desktop 里配置

Claude Desktop 的 MCP 配置在claude_desktop_config.json里。远程 HTTP server 的配置大概长这样:

{ "mcpServers": { "my-product": { "url": "https://api.example.com/mcp", "headers": { "Authorization": "Bearer YOUR_TOKEN" } } } }

配置完重启 Claude Desktop,在对话里问「你能用哪些工具」,如果能看到list_services、get_quote这些,说明连接成功。

这里有个常见坑:Claude Desktop 对 HTTP MCP 的支持是逐步完善的,早期版本只支持 stdio。如果你配置后没反应,先确认版本。另外,配置文件的路径在不同系统下不一样,Mac 在~/Library/Application Support/Claude/,Windows 在%APPDATA%\Claude\。

5.2 在 Cursor 里配置

Cursor 的 MCP 配置在设置里的 MCP 面板,或者直接编辑配置文件。格式和 Claude 类似。Cursor 的优势是它本身是 IDE,你可以在写代码时直接让 AI 调用你的服务,比如「帮我用 my-product 翻译这段注释」。

实测下来,Cursor 对 MCP 的调用触发比 Claude Desktop 更「主动」——它会根据你当前编辑的内容判断是否需要调用工具。这在开发场景里很顺手,但也意味着你的 tool 描述要足够精确,否则 Cursor 可能在不该调用的时候调用。

5.3 让 AI「发现」你的关键:描述文案与示例

工具能被调用,不等于 AI 会主动调用。发现这件事,靠的是描述文案的质量。

我做了三件事提升「被发现率」。第一,在 tool 描述里写清楚适用场景。比如get_quote的描述里我加了「当用户询问价格、预算、费用时使用此工具」。这直接告诉 AI 什么时候该调。

第二,提供参数示例。JSON Schema 里可以写examples字段,AI 看到示例后传参准确率明显提升。

第三,在 server 的 instructions 里写一段总述。MCP 协议支持 server 声明自己的用途,这段文字会进入 AI 的上下文。我写的是「本服务提供文本翻译和摘要能力,按量计费。用户询问相关需求时,先调用 list_services 了解可用服务,再调用 get_quote 获取报价」。

这三件事做完,我在测试里发现 AI 主动调用率从大概三成提升到了八成以上。描述文案就是你的产品在 AI 世界里的门面,值得反复打磨。

6. 踩过的坑与排查实录

6.1 常见问题速查表

现象可能原因排查方向解决
客户端连不上URL 或 token 错看客户端日志检查配置、token 有效期
工具列表为空server 启动失败看 server 日志检查依赖、端口占用
AI 不调用工具描述太模糊看对话记录补充场景说明和示例
参数校验失败Schema 与实现不符对比签名用 Pydantic 统一
报价后下单失败quote 过期看 valid_until重新报价
并发下单重复扣费幂等没做看订单表加幂等键

6.2 三个我印象最深的坑

第一个坑:报价和下单的价格不一致。早期我没做 quote_id 绑定,AI 报价后过了很久才下单,期间我调了价,导致用户看到的价格和实际扣费不符。后来加了 quote_id 和 valid_until,下单时校验,问题解决。教训是:任何涉及金额的流程,都要有服务端的一致性校验,不能信任客户端传来的价格。

第二个坑:AI 反复调用只读工具。有次测试,AI 在对话里连续调了七八次list_services,浪费 token 也拖慢响应。原因是我的描述里没说明「结果稳定,无需重复调用」。加上这句后,重复调用大幅减少。AI 的行为高度依赖描述,你没想到的边界,它就会踩。

第三个坑:错误信息太技术化。最初我返回的错误是 Python 异常堆栈,AI 看到后完全不知道怎么处理,直接把堆栈念给用户听。改成结构化错误 + 人类可读 message + retryable 标志后,AI 能正确决策:参数错就换参数,临时故障就重试,权限问题就提示用户。错误信息是给 AI 看的,要按 AI 能理解的方式组织。

6.3 日志与可观测性

MCP server 的日志和普通服务不太一样,因为你要同时观察「协议层」和「业务层」。

我的做法是:协议层日志记录每次 JSON-RPC 请求的方法、参数、耗时;业务层日志记录业务动作和结果;两层用同一个 trace_id 串联。这样出问题时能快速定位是协议问题还是业务问题。

另外,记录 AI 的调用序列很有价值。你会发现 AI 的调用模式和人类完全不同——它可能先调get_service_docs再调get_quote,也可能反过来。分析这些序列能帮你优化工具设计,比如把常用的调用组合做成一个复合 tool。

7. 关于 agent-to-agent commerce 的一些实践体会

写这个 MCP server 最大的收获,不是技术上的,而是对「AI 代理如何做生意」的理解。

第一,AI 代理是「急性子」。它不会像人类那样耐心读完整篇文档,它看的是 tool 描述和参数 schema。所以你的产品信息必须结构化、前置、精炼。我把最重要的信息(价格区间、交付时间、能力边界)放在 tool 描述的第一句,效果立竿见影。

第二,信任靠可解释性建立。人类用户看到「100 元」会问为什么,AI 代理也一样——它会向用户转述。报价里的breakdown字段让 AI 能解释价格构成,用户信任度明显提升。在 agent-to-agent 场景里,可解释性就是转化率。

第三,幂等和一致性是底线。AI 可能因为网络抖动重试,可能因为理解偏差重复调用。所有写操作必须幂等,所有金额相关操作必须服务端校验。我用了「幂等键 + quote 绑定」双保险,实测下来没出现过重复扣费。

第四,别指望 AI 一次调对。设计 tool 时要假设 AI 会犯错,用清晰的错误信息和 retryable 标志引导它自我纠正。好的错误处理能让 AI 的端到端成功率提升一大截。

这个 MCP server 上线后,我观察到一些有意思的数据:通过 AI 代理进来的订单,客单价和人类用户差不多,但决策链路短很多——从「询问」到「下单」平均只有两三轮对话。这说明 AI 代理确实在改变交易入口。对于手里有小产品的开发者,我的建议是:尽早把你的能力 MCP 化,这不是赶时髦,而是在为「代理找服务」的新入口提前占位。工具描述多打磨几遍,错误处理多写几行,这些投入在 AI 调用场景里的回报比想象中高。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 5:35:09

Jev不是AI模型,而是AI API的类型安全契约协议

1. Jev 不是新模型,而是 TypeSafe AI 推出的开发者协议层——它解决的从来不是“谁更聪明”,而是“怎么不翻车”最近刷到“Jev爆火”“Jev模型官网”“Jev密钥申请”这类标题,点进去却发现内容五花八门:有人在教Python调用Jev API…

作者头像 李华
网站建设 2026/10/1 5:34:37

OpenCV全景拼接实战:从特征匹配到图像融合的完整流程

简介:基于Python的OpenCV全景图像拼接系统是一个完整的毕业设计项目,包含前端页面、Python后台、数据库脚本与工具软件,面向需要掌握图像拼接与Web系统开发的初学者或完成课程设计的学生。全项目共308个文件,主要涵盖28个Python源…

作者头像 李华
网站建设 2026/10/1 5:34:25

EasyMock原理与避坑指南:动态代理、录制回放与参数匹配

1. EasyMock不是“Easy”Mock,而是“Easy to Misuse”的Mock刚接触EasyMock那会儿,我正带一个三人小团队赶一个金融类后台接口联调。前端已经等不及要测UI了,但第三方支付网关的沙箱环境还在审批流程里,后端同事说:“用…

作者头像 李华
网站建设 2026/10/1 5:33:50

AgentScope:Java构建生产级记忆型AI Agent的工程实践

1. 这不是玩具项目:为什么“生产级记忆型 AI Agent”必须从 AgentScope 开始你刷到过太多“5分钟用 LangChain 搭个聊天机器人”的教程,也见过不少“基于 Llama3 的本地智能体 demo”,但真正能扛住每天 10 万次调用、自动记住用户三年前提过的…

作者头像 李华
网站建设 2026/10/1 5:33:50

从前端到Agent开发:用LangChain+Playwright构建自动化测试Agent

坦白说,我第一次认真思考“Agent开发”,不是被什么宏大宣言打动的,而是2024年年底的一次真实到有点痛的迭代:我们前端组要同时接管三个后台管理系统的页面改版,AI辅助编码工具已经能把组件写得又快又像样。我当时坐在工…

作者头像 李华
网站建设 2026/10/1 5:33:43

ST-GCN骨骼动作识别实战:从数据预处理到模型训练与推理

简介:这是一份面向毕业设计场景的Python骨骼动作识别项目资源,基于时空图卷积网络(ST-GCN)实现动作分类,适合计算机视觉方向学生、研究者及对姿态识别感兴趣的开发者参考与二次开发。资源共91个文件,压缩包…

作者头像 李华