)
1. WebMCP 到底是什么为什么 AI Agent 需要它WebMCP 是一套基于 JSON-RPC 2.0 的通信协议专门用来把 Web 应用里已经存在的功能以「方法」的形式暴露给 AI Agent 调用。你可以把它理解成给网页装了一个标准化的「服务窗口」Agent 不用去猜页面上的按钮在哪、DOM 结构长什么样只要按协议发一条 JSON-RPC 请求Web 应用就执行对应逻辑并返回结构化结果。它适合谁适合正在做 AI Agent 落地、想让 Agent 操作自家 Web 系统比如查订单、建工单、读报表的前端和后端开发者。传统做法里Agent 调 Web 能力一般走两条路一是自己写一套 HTTP API二是用浏览器自动化去点页面。前者的问题是每个业务都要重新定义接口风格鉴权、超时、错误码各写各的后者的问题是页面一改Agent 就失灵而且很难做细粒度权限。WebMCP 想解决的就是这两件事——用统一的 JSON-RPC 消息格式收敛通信用声明式的权限控制收敛鉴权。它的核心结构分三层。协议层负责收发和解析 JSON-RPC 请求处理握手和数据序列化Handler 层管理方法的注册与调用做权限验证和请求分发业务逻辑层执行真正的业务代码并返回结果。这种分层的好处是新增一个 Agent 能力只需要注册一个 handler不用动协议层和通信层。消息格式上WebMCP 完全遵循 JSON-RPC 2.0。请求对象包含jsonrpc、method、params、id四个字段响应对象包含jsonrpc、result或error、id。错误码也沿用标准定义比如-32700解析错误、-32601方法不存在、-32602无效参数、-32603内部错误。这意味着任何熟悉 JSON-RPC 的开发者几乎零学习成本就能上手。权限控制是 WebMCP 区别于普通 RPC 的关键。它支持方法级权限声明可以标public、user、admin也可以传一个自定义函数根据调用上下文里的用户角色动态判断。这样 Agent 拿到的 token 决定了它能调哪些方法而不是拿到一个 key 就能调全部。对做企业级 Agent 的团队来说这一点直接决定了能不能过安全评审。我在实际项目里踩过的坑是一开始把所有方法都设成public结果 Agent 在测试环境误调了删除类接口。后来改成默认user权限、敏感操作单独标admin并且给每个方法加了参数校验才稳下来。所以下面我会从接入配置讲到权限声明再到用 TaoToken 统一 Key 完成一次真实调用验证。2. 用 TaoToken 统一 Key 打通 WebMCP 的鉴权链路WebMCP 本身解决的是「Agent 怎么调 Web 应用」但它不负责模型侧的凭证管理。也就是说Agent 在决定调用哪个 WebMCP 方法之前通常要先经过一次大模型推理而这次推理需要一个可用的 API Key。如果你同时接了好几个模型供应商Key 散落在各个配置文件里调试和轮换都很痛苦。TaoToken 在这里的角色就是提供一个统一的 Key 和 API 通道让模型调用这一层先收敛。TaoToken 是一个 AI 模型 API 聚合通道官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。它的价值在于你只需要维护一个 Key就能在 Agent 侧调用不同模型而 WebMCP 侧的方法调用和权限校验仍然由你自己的 Server 控制。两层职责分开排查问题时不会互相干扰。具体到 WebMCP 场景链路是这样的Agent 收到用户指令 → 通过 TaoToken 的统一 Key 调用模型做意图识别和方法选择 → 模型返回要调用的 WebMCP 方法名和参数 → Agent 用 WebMCP Client 发 JSON-RPC 请求到你的 WebMCP Server → Server 做权限校验并执行 → 结果回传给 Agent。整个过程中TaoToken 管的是第一步的模型凭证WebMCP 管的是后面几步的方法调用和权限。为什么要把这两层分开因为它们的失败模式完全不同。模型调用失败通常是 401、余额不足、模型名写错WebMCP 调用失败通常是方法不存在、权限拒绝、参数校验不过。如果混在一起用一个 Key 管所有事出问题时你很难判断到底是模型侧还是业务侧。分开之后401 就去查 TaoToken 的 KeyPERMISSION_DENIED就去查 WebMCP 的权限声明。在 TaoToken 控制台里你可以创建 API Key路径是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。创建好之后Key 的管理页面在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。如果你用的是 Claude Code 这类编码 AgentTaoToken 也提供了对应的接入方式文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite Claude Code 的专门说明在 https://taotoken.net/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。需要提醒的是TaoToken 是模型 API 通道不是 WebMCP Server 的替代品。WebMCP Server 仍然要你自己部署权限声明也要你自己写。TaoToken 只是让模型调用这一层的 Key 统一减少你在多供应商之间来回切换的成本。下面进入可复制的配置环节。3. 可复制的 WebMCP 端点配置与权限声明这一节给出可以直接抄的配置片段。先看 WebMCP Server 的初始化配置我用的是opentiny/next-sdk风格的接口路径和字段名保持一致你换成自己项目的 SDK 时对照字段即可。// src/server/webmcp-server.ts import { createWebMCPServer, WebMCPServer, Handler } from opentiny/next-sdk interface WebMCPServerConfig { port: number auth?: boolean timeout?: number handlers: Recordstring, Handler } const server: WebMCPServer createWebMCPServer({ port: 8080, auth: true, timeout: 5000, handlers: { // 公开方法无需鉴权 getPublicConfig: { handler: async (params) { return { version: 1.0.0, env: production } }, permission: public }, // 普通用户权限 getUserInfo: { handler: async (params: { userId: number }) { return { userId: params.userId, name: demo-user } }, permission: user }, // 管理员权限 deleteRecord: { handler: async (params: { recordId: string }) { return { deleted: true, recordId: params.recordId } }, permission: admin }, // 自定义权限函数 editArticle: { handler: async (params: { articleId: string; content: string }) { return { updated: true, articleId: params.articleId } }, permission: (context) { return context.user.roles.includes(editor) } } } })权限声明的关键点是permission字段既可以是字符串也可以是函数。字符串走内置的 RBAC 判断函数则拿到完整的调用上下文你可以根据context.user.roles、context.user.id甚至请求来源 IP 做判断。我建议默认全部设成user只有明确要对外开放的才设public删除、修改类操作一律admin或自定义函数。接下来是 WebMCP Client 的配置这里要同时接上 TaoToken 的模型通道和 WebMCP 的 Server 地址// src/utils/webmcp-client.ts import { createWebMCPClient, WebMCPClient } from opentiny/next-sdk const client: WebMCPClient createWebMCPClient({ serverUrl: http://localhost:8080, timeout: 5000, retry: { enabled: true, maxRetries: 3, delay: 1000 }, auth: { token: localStorage.getItem(webmcp_token) } }) export default client如果你用配置文件的方式管理 TaoToken 的 Key可以写成 JSON 或 TOML。JSON 版本如下路径放在项目根目录的config/taotoken.json{ baseUrl: https://taotoken.net/api, apiKey: sk-your-taotoken-key, model: claude-sonnet-4-20250514, webmcp: { serverUrl: http://localhost:8080, timeout: 5000 } }TOML 版本放在config/taotoken.toml[taotoken] base_url https://taotoken.net/api api_key sk-your-taotoken-key model claude-sonnet-4-20250514 [webmcp] server_url http://localhost:8080 timeout 5000如果你用的是 Claude Code 或 Cline 这类工具配置通常写在settings.json或auth.json里。以 Claude Code 为例Base URL 填https://taotoken.net/apiKey 填你在控制台创建的 KeyModel ID 填你要用的模型名。这三件套缺一不可Base URL 决定请求发到哪Key 决定能不能过鉴权Model ID 决定用哪个模型。Cline 的 MCP 配置也是同样的三件套逻辑只是字段名可能叫baseUrl、apiKey、model。配置写完后启动 Server 和 Client确认端口 8080 没有被占用。如果启动时报EADDRINUSE说明端口冲突改port字段即可。权限声明写完后建议先用public方法测通链路再逐步加权限避免一上来就被 403 挡住。4. 验证一次 Agent 到 Web 应用的完整调用配置就绪后跑一次真实调用。先启动 WebMCP Servernpx ts-node src/server/webmcp-server.ts看到WebMCP Server listening on port 8080就说明起来了。然后用 curl 发一条 JSON-RPC 请求验证协议层是否正常curl -X POST http://localhost:8080/rpc \ -H Content-Type: application/json \ -H Authorization: Bearer sk-your-taotoken-key \ -d { jsonrpc: 2.0, method: getPublicConfig, params: {}, id: 1 }预期返回{ jsonrpc: 2.0, result: { version: 1.0.0, env: production }, id: 1 }这一步验证的是协议握手和公开方法调用。如果返回-32601说明方法名写错了或者没注册如果返回 403说明auth开了但 token 没带对。接下来验证带权限的方法。先调getUserInfo它需要user权限curl -X POST http://localhost:8080/rpc \ -H Content-Type: application/json \ -H Authorization: Bearer sk-your-taotoken-key \ -d { jsonrpc: 2.0, method: getUserInfo, params: { userId: 123 }, id: 2 }如果 token 对应的角色是user会返回用户信息如果是匿名会返回PERMISSION_DENIED。再调deleteRecord它需要admin权限用普通 user token 调应该被拒绝这正好验证权限控制是否生效。最后跑一次完整的 Agent 调用。Agent 侧先用 TaoToken 的统一 Key 调模型让模型输出要调用的方法名和参数再把结果转成 JSON-RPC 请求发给 WebMCP Server。下面是一个简化的 Agent 调用示例// src/agent/run-agent.ts import client from ../utils/webmcp-client async function runAgent(userInput: string) { // 第一步通过 TaoToken 调模型做意图识别 const modelResponse await fetch(https://taotoken.net/api/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${process.env.TAOTOKEN_API_KEY} }, body: JSON.stringify({ model: claude-sonnet-4-20250514, messages: [ { role: system, content: 你是一个 Agent根据用户输入选择 WebMCP 方法并输出 JSON。 }, { role: user, content: userInput } ] }) }) const modelData await modelResponse.json() const toolCall JSON.parse(modelData.choices[0].message.content) // 第二步用 WebMCP Client 调用 Web 应用方法 const result await client.call(toolCall.method, toolCall.params) return result } runAgent(帮我查一下用户 123 的信息).then(console.log)跑通后你会看到控制台先打印模型返回的方法选择再打印 WebMCP 返回的用户信息。整个过程里TaoToken 负责模型调用WebMCP 负责方法调用和权限校验两层各司其职。如果模型返回的choices读不到通常是响应结构不对检查modelData.choices[0].message.content是否存在如果 WebMCP 返回METHOD_NOT_FOUND检查方法名是否和 Server 注册的一致。5. 常见报错排查401、local proxy failed、reading choices、OAuth这一节对照真实报错逐个拆。第一个是 401通常出现在模型调用侧。报错信息类似401 Unauthorized或invalid api key。原因有三种Key 没填、Key 填错、Key 被禁用。排查顺序是先确认Authorization头有没有带Bearer前缀再确认 Key 是不是从 TaoToken 控制台复制的完整字符串最后去控制台看 Key 状态。如果是 WebMCP 侧返回 401检查auth.token是否为空以及 Server 的auth字段是否开了。第二个是local proxy failed。这个报错一般出现在你本地起了代理层但代理层连不上上游。排查时先确认baseUrl是不是https://taotoken.net/api注意结尾不要多加/v1或斜杠。再确认本地网络能正常访问该地址可以用curl -I https://taotoken.net/api看返回码。如果代理层配置了超时把timeout调大到 10000 再试。这个报错和 WebMCP 本身无关是模型通道的问题。第三个是reading choices相关报错典型信息是Cannot read properties of undefined (reading choices)。这说明你拿到的响应体里没有choices字段。原因通常是请求根本没成功返回的是错误对象或者模型名写错上游返回了错误结构。排查时先把完整响应console.log出来看是error字段还是choices字段。如果是error按错误码处理如果是空对象检查请求体 JSON 是否合法。第四个是 OAuth 相关报错。如果你用的是 Claude Code 或类似工具可能会遇到OAuth token expired或invalid_grant。这类工具默认走 OAuth 流程但接 TaoToken 时应该用 API Key 模式不是 OAuth 模式。检查配置文件里是不是还留着旧的 OAuth 字段把它删掉改成apiKey或api_key。Claude Code 的接入文档在 https://taotoken.net/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 里面有完整的字段对照。还有一个容易忽略的报错是PERMISSION_DENIED。这不是网络问题是 WebMCP 的权限声明生效了。检查你调的方法的permission字段以及 token 对应的角色。如果是自定义权限函数在函数里加一行console.log(context.user)看角色数组里到底有什么。我遇到过角色名写成Editor但判断时用的是editor大小写不一致导致一直拒绝改成统一小写就好了。排查时建议按这个顺序先确认模型调用通不通401、local proxy failed、reading choices 都属于这一类再确认 WebMCP 协议通不通METHOD_NOT_FOUND、INVALID_PARAMS最后确认权限通不通PERMISSION_DENIED、403。三层分开查比混在一起猜快得多。6. 把统一 Key 接入你的 Agent 工作流走到这里你已经有了一个能跑的 WebMCP Server、一份权限声明、一个通过 TaoToken 统一 Key 调模型的 Agent 链路。接下来要做的是把这套东西固化到日常工作流里。我的做法是模型 Key 只存在一个地方就是 TaoToken 的配置WebMCP 的权限声明跟着代码走进版本控制每次新增 Agent 能力只改 handler 注册和权限字段不动通信层。如果你还在选模型阶段想先对比不同模型对 JSON-RPC 方法选择的准确率可以用 TaoToken 的模型对话入口快速试https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。同一个 prompt 换不同模型跑几遍看哪个模型输出的方法名和参数最稳再决定生产用哪个。如果你是要长期跑编码类 Agent或者做多步工具调用的 Agent建议直接上 Coding Plan入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。它适合那种需要反复调模型、反复调 WebMCP 方法的场景比按次调用更省心。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite API Key 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。建议先把 Key 创建好再把上面的 JSON 或 TOML 配置抄进去跑通第 4 节的 curl 验证最后接 Agent。顺序别反反了出问题不好定位。最后留一个实用技巧在 WebMCP Server 里加一个ping方法权限设public返回服务器时间和版本号。Agent 每次调用前先 ping 一下能快速判断是 Server 挂了还是权限问题。这个方法我每个项目都会加排查时省很多时间。