news 2026/10/2 15:41:40

给产品接入MCP Server:让AI Agent自动发现并调用你的服务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
给产品接入MCP Server:让AI Agent自动发现并调用你的服务

前阵子给我的小产品补了个很不起眼但影响很深远的接口:一个 MCP server。做完以后,效果很有意思——原本只能通过网页表单和 REST API 被人调用的报价服务,现在能被各种 AI agent 自动发现、自动调用、自动把报价单带回来。放在 2026 年这个节点上,这基本相当于给你的产品在 agent 生态里开了一个“系统级入口”。

这篇文章不打算复述官方文档,就讲我怎么想的、怎么写的、以及一路踩过的坑。适合正在做 AI agent 练手小项目、准备把自家服务接入 agent 生态的独立开发者,也适合那些只听过 MCP 但一直没搞明白“这东西到底能给我带来什么”的人。我会把协议原理、工具选型、核心代码、客户端配置、日志管理和并发处理全部串成一整条实操路径,你照着走一遍就能复现。

1. 为什么给小产品接 MCP:AI agent 开始“摸到”你的生意了

1.1 先给 MCP 正个名:它不是新语言,是“接口插座”

MCP 的全称是 Model Context Protocol,模型上下文协议。2024 年底由 Anthropic 开源,随后快速成了 AI 工具接入外部系统的事实标准。你可以把它理解成一个“AI 世界的 USB-C 接口”:谁家设备只要支持这个标准,插上就能互相通信,不需要为每家厂商单独写适配器。

整个架构分成三层。MCP host 是宿主程序,比如 Claude Desktop、Trae、Cursor 这类 AI 客户端;MCP client 是宿主内部负责建立连接的组件;MCP server 则是你写的、对外暴露能力的服务端。通信协议基于 JSON-RPC 2.0,不是 REST,不是 GraphQL,是一套专门为“AI 模型调用外部工具”设计的远程过程调用规范。

MCP server 内部定义了三种核心原语:tools、resources、prompts。Tools 是让 AI 执行的函数,Resources 是暴露给 AI 读取的数据,Prompts 是预设的提示词模板。大部分实际业务场景,你只需要先做好 tools 就能跑通闭环。

提示:MCP 并不替代 REST API。它是在 AI 客户端和你现有服务之间加了一层“可被发现”的中介。你原有的 API 继续保留,MCP server 只是把其中一部分能力用标准化的方式暴露给 agent。

1.2 agent 生态已经变了:从聊天到“干活”

2026 年你再去看市面上的 AI agent 产品盘点,会发现一个明显信号:能留在牌桌上的,没有一个还停留在“陪聊”层面。国内外的 agent 智能体、企业中台、低代码平台,连“AI agent 搭建设计”都已经变成常规教程选题。大家讨论的已经从“怎么搭一个 agent”变成了“怎么让 agent 真的下地干活”。

那“干活”靠什么?靠工具。一个 agent 如果只能基于训练数据回答问题,那它永远是个聊天机器人;一旦它能调用搜索、数据库、订单系统、报价引擎,它才真正变成了一个“数字员工”。像基于 FastAPI + LangChain + LangGraph 那套方案,本质上也是在给 agent 装配外部工具链。

这就带来一个残酷的现实:如果你的产品不支持 MCP,agent 在默认情况下根本“看不见”你。用户让 agent 帮忙找个能生成报价的小工具,agent 只会列出它已经联网检索到的服务,或者调用那些已经接好 MCP 的竞品。我去年年中给产品补 MCP 接口的动机就是这么简单:不想在 agent 消费链里彻底隐形。

1.3 我的产品很小,但它很适合被 agent “发现”

先交代一下背景。我的小产品是面向独立开发者和三五人小团队的报价组件,输入需求描述、开发周期、团队人数,就能算出合理的报价区间和工期建议。以前只有两套入口:一是网页上的交互表单,二是给程序员用的 REST API。表单适合人用,API 适合会写代码的人用,但 AI agent 两者都用不上——它需要的是“能自己发现、自己理解、自己调用”的接口。

MCP 的“发现”机制正好解决这个问题。server 启动后,agent 会自动读取工具清单,每个工具的 description 和参数 Schema 都是自描述的。AI 模型读完清单就知道你这个产品是什么、能干什么、需要哪些参数。它不需要去看你的开发文档,也不需要你提前教它怎么拼接 URL。我做完之后做了一个测试:在对话里输入“我想做一个带微信登录的小程序,大概一个月的开发周期”,agent 自动调用了我的报价工具,把生成结果直接发回对话。那一刻我就意识到,这玩意儿不是锦上添花,是必须补上的入口。

注意:这里的“发现”不是搜索引擎那种爬虫发现,而是协议层面的工具自发现。agent 通过 listTools 拿到你的能力清单,再根据 user 的诉求决定调用哪一个。你的工具描述写得越清楚,agent 调用越准确。

2. 动手之前的选型:协议原语、传输方式和 SDK

2.1 只用 tools 就够了?不,resources 和 prompts 偶尔也要用

我最早以为 MCP server 就是“注册几个函数”,后来认真看了协议才发现三个原语各有各的适合场景。我建议初始化项目时不要贪多,先把 tools 做好,但心里要清楚另外两个原语解决什么问题。

Tools:AI 可以执行的函数,通常有入参和返回值。适合报价计算、下单、查询状态这类动作。

Resources:暴露给 AI 的只读数据。适合产品目录、服务条款、价格表这类“AI 需要先读再判断”的内容。我后来就把产品基础信息放成了 resources,agent 在调用报价工具前可以先读一遍服务范围,避免拿完全陌生的需求来问价。

Prompts:预设提示词模板。适合把“报价前需要收集哪些信息”这类业务规则固化成模板。不过说实话,对一个小产品来说,prompts 的优先级最低,等用户量上来了再补也不迟。

如果你上来就把三种原语全铺开,维护成本会很快超过收益。最小可用方案就做 tools,一条路径跑通再扩展。

2.2 stdio 与 SSE:两种传输方式的取舍

MCP 支持多种传输方式,目前最常用的是 stdio 和 HTTP+SSE。stdio 模式下,MCP server 作为子进程被客户端拉起,双方通过标准输入输出通信。本地开发调试、配合 Claude Desktop、Trae、Cursor 这类桌面客户端,stdio 是最省事的方案:你不用部署服务、不用开端口、不用处理跨域。

SSE 模式适合 server 部署在远程服务器、多个客户端通过公网访问的场景。客户端通过 HTTP 建立连接,再通过 SSE 接收服务端消息。如果你的产品想要面向“任意 agent 都可发现可调用”这个目标,最终一定得支持 SSE 或升级版 Streamable HTTP。大家看那些“Trae IDE 搭载 Burp Suite MCP server 完整指南”之类的教程,本质用的也是这套连接逻辑,只不过工具换成了安全测试产品。

我在本地开发阶段用 stdio,联调稳定后补了一个 SSE 入口用于线上。一个 server 代码,两种 transport 都支持,切换成本非常低。

2.3 语言与 SDK:为什么我选 Node 而不是 Python

MCP server 官方 SDK 有 TypeScript、Python、Java、Go 等多个版本,选择主要看你现有的技术栈。我自己主力栈是 TypeScript,所以选了 @modelcontextprotocol/sdk。如果你在 FastAPI + LangChain + LangGraph 那套 Python 生态里,用官方的 Python SDK 也一样顺手;Java 生态还有 Spring AI 的 MCP 集成,做企业服务端很合适。

我不用 Python 还有一个具体原因:TypeScript 的 JSON Schema 一致性更好。MCP 工具参数用 JSON Schema 描述,TypeScript 里我可以把类型定义和校验规则写在一起,tsc 编译时就能发现类型漂移。另外 Node 生态的 npx 分发对客户端特别友好,用户客户端配置文件里写一行npx -y <包名>就能拉起最新版 server,不需要预先全局安装。

实操建议:MCP server 的代码量并不大,核心逻辑通常一两百行,没必要为了它单独引入一套重型框架。你的业务逻辑还是留在原服务里,MCP server 只做一层薄薄的转换层。

3. 核心实现:怎么让 agent “发现”并“报价”你的产品

3.1 先搭一个最小可用的 server 骨架

这是 SDK 初始化最基础的代码。我直接用 TypeScript + 官方 SDK,registerTool 的第二个参数就是 JSON Schema,第三个参数是执行函数。

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; const server = new McpServer({ name: "my-quote-mcp", version: "1.0.0", }); server.registerTool( "discover_product", { keyword: { type: "string", description: "搜索关键词,比如小程序、网站、API、后台" }, includePricing: { type: "boolean", description: "是否返回价格起点,默认 true" }, }, async ({ keyword, includePricing }) => { const result = searchCatalog(keyword, includePricing); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } ); const transport = new StdioServerTransport(); await server.connect(transport);

贴这个代码是想说明一个点位:MCP 工具函数的返回值不是裸数据,必须包成content数组,数组里每一项是一个带类型的块(text 或 image)。AI 客户端就是靠解析这个数组把结果呈现给模型的。第一次写时很容易漏掉这层包裹,导致 agent 拿到空数据。

3.2 “发现”工具的描述有多重要,AI 就靠这个理解你

工具注册的代码只是骨架,真正决定 AI 调用准确率的,其实是 description 和参数注释。JSON Schema 的 description 字段是给模型读的,写得好不好直接决定 agent 是精准调用还是乱试。

我一开始给 discover_product 的 description 写的是“发现产品”,结果 agent 经常拿它来问“你们有什么产品”,甚至在我需要报价时先调用发现再调用报价,多出一步无效交互。后来我把 description 改成了“根据用户描述搜索可提供的产品与服务,返回产品编码、名称、计价单位与价格起点。调用报价工具前应先调用本工具确认产品编码”,效果立刻提升。AI 模型是依据文本语义来规划工具链的,你的描述越接近自然语言任务,它的工具编排越合理。

参数命名也一样。不要用id、type这种零语义的词,要用keyword、includePricing这种模型一眼能看懂的名字。必要的时候,把数值单位的约定写进参数注释,比如“价格单位为美元”“周期按自然周计算”,避免 agent 把用户说的“一个月”直接当成 4 周,或把人民币数字当美元。

3.3 “报价”工具:不要给 agent 设太多枷锁

报价工具是这套 MCP server 的核心。我设计了一个 create_quote 工具,输入三个参数:需求描述、期望周期、团队人数。参数 Schema 长这样:

{ "type": "object", "properties": { "demandDescription": { "type": "string", "description": "用户完整的需求描述,包括功能范围、平台、登录方式等" }, "durationWeeks": { "type": "number", "description": "期望开发周期(自然周),可空,为空则按默认排期计算" }, "teamSize": { "type": "number", "description": "团队人数,可空,默认 1" } }, "required": ["demandDescription"] }

注意我这里只把demandDescription设为必填,其余都是可选。一开始我把三个字段全设置成 required,结果 agent 在用户描述信息不足时直接报错,甚至放弃调用工具转身告诉用户“信息不完整”。AI agent 没有那么强的主动追问能力,工具层面的容错设计必须提前做。

内部报价计算逻辑我用了一个非常简单的模型:基准价乘以需求复杂度系数,再乘以周期调整系数。需求复杂度靠一组关键词匹配,比如“小程序”加 0.8,“AI”加 1.5,涉及支付的再额外加权。这个逻辑放在原服务里,MCP 工具只负责把参数翻译成内部请求。

注意:报价结果一定要带上quote_id。这个 id 是后续下单、改报价单、补差价的状态依据。agent 是无状态会话,没有 id 的话它一旦断开就彻底找不回这次报价。

3.4 日志管理:console.log 会毁掉整个 stdio 通道

这不是标题党,是我踩过的实坑。MCP 的 stdio 传输模式里,标准输出 stdout 是协议通道,你打一行console.log,就等于往协议流里塞了一段噪音。客户端解析 JSON-RPC 包时看到这行脏数据,轻则警告,重则直接报错,表现通常是 server 拉起后过几秒连接就断。

正确做法是把日志写到文件,或者用 stderr。更讲究一点,可以用 MCP 的日志能力向客户端发送结构化日志消息:

import { createLogger, format, transports } from "winston"; const logger = createLogger({ level: "info", format: format.combine(format.timestamp(), format.json()), transports: [ new transports.File({ filename: "/var/log/my-quote-mcp.log" }), ], });

我当时遇到的情况更隐蔽:代码里没直接用 console.log,但第三方依赖的某条错误处理路径偷偷打了一行。找了两小时才定位。所以我的建议很直接:如果你用 stdio 模式,在入口文件干脆做一层保护——把console.log整个替换成日志文件的写入。自定义日志管理和协议隔离,是你写 MCP server 第一天就要处理的基建问题,不要等线上跑起来了再补。

4. 让 agent 真的“接上”它:客户端配置、本地启动与安全边界

4.1 客户端接入:一份 config.json 完成最小接线

MCP 的一个好处是配置成本极低。以 Claude Desktop 和 Trae 这类兼容客户端为例,只需在配置文件里声明 server 启动方式和环境变量:

{ "mcpServers": { "my-quote-mcp": { "command": "npx", "args": ["-y", "my-quote-mcp"], "env": { "PRODUCT_API_KEY": "sk-这里填你服务的密钥" } } } }

npx -y是这里的关键。它意味着用户不需要预先安装你的包,客户端会自动拉取最新版并启动。对独立开发者来说,这是分发成本最低的方式。如果你是本地开发调试,当然也可以把 command 换成node、args 换成["dist/index.js"],这样每次改动不用重新发布 npm 包。

env 字段用来透传环境变量。我的 MCP server 里所有业务调用都走原服务的 REST API,身份鉴权就靠这个 API key,MCP 工具本身不保存任何敏感信息。

4.2 本地启动与联调实操:MCP Inspector 是最好用的调试器

很多教程停留在“会配置”层面,真正联调时会发现一大堆问题。我的完整流程是这样:

  1. npm run build,保证 dist 目录是最新的。
  2. 用官方提供的 MCP Inspector 启动调试:npx @modelcontextprotocol/inspector node dist/index.js。
  3. 浏览器打开 Inspector 面板,先看 Tools 列表,确认注册的工具名和描述都正确。
  4. 手动执行一次工具调用,检查返回的 content 结构。
  5. 一切正常后,再通过客户端配置走真实链路测试。

“本地启动 MCP server 教程”到处都有,但真正实用的技巧是:先在 Inspector 里跑通一遍,再上客户端。因为 Inspector 能看到协议层的原始请求和响应,而客户端里 agent 会把你的失败包装成“暂时无法完成”,你根本不知道是工具报错还是模型没调用对。

4.3 权限与安全:给 agent 的权限不能比内部系统还大

这个话题我是受那篇“Trae IDE 搭载 Burp Suite MCP server”教程启发的。你看,连安全测试这种高风险操作,现在都开始让 agent 直接控制工具了,说明业界对“agent 操作生产工具”这件事已经有了共识:不是不让动,是必须控制好边界。

我给自己定了三条规则。第一,MCP server 只暴露业务白名单工具,不开放任意命令执行或文件读取,防止 prompt injection 导致的信息泄露。第二,所有工具内部都要校验调用来源和身份,API key 从 env 传入,工具参数永不做信任。第三,对工具调用速率做限制,同一密钥每秒最多 10 次调用,防止 agent 循环失控把原服务打挂。

这里说一个容易被忽略的点:agent 收到的系统上下文可能被用户输入污染。如果用户诱导 agent 调用工具时带上恶意参数,你的工具如果不过滤,就会成为攻击入口。所以 MCP server 里每个输入参数都必须按“不可信输入”来处理。

5. 并发、超时和那些让人抓狂的坑

5.1 AI agent 怎么扛并发:先搞清楚你的运行模式

很多人一上来就问“AI agent 怎么扛并发”,这问题要先分场景。

stdio 模式下的 MCP server 是单客户端进程,每个客户端拉起一个独立子进程,天然隔离、天然分布,不存在共享状态竞争。但它的并发能力受限于单进程单连接,不适合对外大规模开放。

SSE 模式就完全是另一回事了。你的 server 变成一个常驻 HTTP 服务,所有客户端都连到同一份代码上,这时候必须考虑三件事:工具执行不能长时间占用请求线程、关键路径要有超时、计算密集的活要让位给任务队列。我的做法是:报价计算如果超过 500ms 就走异步任务,先返回“任务已受理,请稍后查询状态”这样的结果,再提供一个状态查询工具供 agent 轮询。这比硬扛同步等待稳得多。

5.2 我遇到过的四个典型错误级别

把服务发给十几个人试用之后,我整理了一张问题排查表,基本覆盖了大部分新手会踩的坑:

表现可能原因排查方向
客户端显示 server 连接失败stdio 通道被日志污染 / Node 版本不兼容检查是否用了 console.log,确认 process.stdout 没被第三方占用
agent 说“工具出现异常”工具函数抛异常后没格式化返回看 stderr 日志,确认代码没有 switch 后走 throw
agent 调用了工具但结果为空content 数组格式错误或返回体太大被截断用 MCP Inspector 看原始响应体
调用重复导致限流agent 编排时多次重试同一工具工具加幂等键,相同参数直接返回缓存结果

第四个问题我单独多讲一句。agent 在处理长流程时,经常因为上下文超限或网络中断进行工具重试。如果同一报价被重复创建,用户会收到两份几乎相同的报价单。我在报价工具里加了一个幂等判断:相同 demandDescription 摘要 + 相同产品编码的请求,60 秒内直接返回上次的 quote_id,不再新建。

5.3 一次真实事故复盘:日志救了我一命

上线第二个星期,有个用户反馈 agent 报价偶发失败。我查了服务端日志,发现失败请求都是同一个特征:teamSize参数传了字符串"2",而 JSON Schema 定义的是number。系统做了严格类型校验,直接拒绝。看起来是 agent 把用户对话里的“两个人”转成了字符串。

这个问题的根源是我的 Schema 设得太严格。修复方案不是让 agent 更聪明,而是把工具入参放宽:teamSize允许number或字符串数字,在工具内部统一做 Number() 转换。从那以后,我再也没收到过这类报错。这个经验值得记住:MCP server 的校验逻辑要宽容,内部转换要严谨。你的服务可以严格要求内部数据,但不要对 AI 模型的输出抱有完整富格假设。

6. 一些没有写在文档里的经验值

MCP server 做完这段时间,我个人最深的体会是:它不应该成为一个“大项目”,它就应该是你原服务的一层薄薄的外接适配器。不要把业务逻辑往 MCP server 里塞,塞得越多越难维护。合理状态是,MCP server 只做参数转换、身份校验和结果格式化,真正的计算、存储、鉴权全部留在原服务。这样你以后换协议、换 SDK、换客户端,都只需要调整这薄薄一层。

如果你现在正在做 AI agent 练手小项目,我建议你挑一个自己已有的小产品,或者干脆写一个最简单的报价计算器,按这篇文章的路径从零到一跑通一遍 MCP。你会发现,当 agent 真的“看到”你的工具并且自动调用成功的那一瞬间,你对“AI 原生应用”的理解会完全不同。别再观望了,把接口做出来,让 agent 先“摸到”你的产品,这才是 2026 年不落伍的第一步。

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

AI Agent算力底座矩阵:CPU与GPU异构编排实战

1. 从"模型竞赛"到"算力编排"&#xff1a;AI Agent 真正吃的是什么过去两年&#xff0c;大家聊 AI 聊的都是模型本身——参数多大、榜单多高、上下文多长。但真正把 AI Agent 跑起来的人会发现&#xff0c;卡脖子的地方往往不在模型&#xff0c;而在算力怎…

作者头像 李华
网站建设 2026/10/2 15:39:36

Nagios部署实战:用TaoToken统一Key打通告警链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 15:38:26

VSCode插件实战:用AI自动生成规范的Git提交信息

1. 项目概述与核心思路拆解 先说个开头。 VSCode Commit AI - 智能生成提交信息 &#xff0c;这个名字看起来挺直白&#xff0c;核心就一句话&#xff1a;在 VSCode 里&#xff0c;让 AI 根据你的代码改动自动生成规范的 Git 提交信息。 为什么这个事值得做&#xff1f;我自…

作者头像 李华
网站建设 2026/10/2 15:37:04

GitHub Trending日榜解读:热门项目、热搜词与开发者需求分析

1. 榜单速览&#xff1a;今天的热点都在哪 GitHub Trending 页面的更新频率是每小时一次&#xff0c;但真正有价值的不是某一小时的波动&#xff0c;而是一整天下来反复出现的那些项目。今天&#xff08;2026-09-29&#xff09;的日榜整体看下来&#xff0c;有几个明显的信号&a…

作者头像 李华
网站建设 2026/10/2 15:36:49

27B三元量化模型在RTX 4090上的部署与调优实战

1. 为什么选这套组合&#xff1a;27B参数、三元量化与单卡4090的适配逻辑先说结论&#xff1a;RTX 4090 的 24GB 显存&#xff0c;在过去是“跑 7B/13B 很欢、跑 30B 级别很尴尬”的容量。而 Ternary-Bonsai-2-27B 这种 27B 参数的模型&#xff0c;配合 PTQ1_0 训练后量化方案&…

作者头像 李华