WebMCP 学习指南:用 Vue + TypeScript + Zod 打通 W3C 标准下的前端工具调用

发布时间:2026/10/18 14:07:51

WebMCP 学习指南:用 Vue + TypeScript + Zod 打通 W3C 标准下的前端工具调用 1. WebMCP 到底是什么为什么 Vue 项目要现在开始学WebMCPWeb Model Context Protocol是 W3C Web Machine Learning 社区组正在推进的一份提案规范它做的事情可以用一句话概括让网页把自己内部的 JavaScript 函数以结构化「工具」的形式暴露给浏览器里的 AI 代理让 AI 直接调用你的业务逻辑而不是靠截图识别和模拟点击去猜你的界面。它适合谁适合正在做 Vue、React 或者任意前端框架并且希望自己的网站能被 AI 代理「看懂并操作」的开发者。核心检索词就是 WebMCP、W3C 标准、Vue 集成、TypeScript 类型安全、Zod 入参校验这几个词基本覆盖了本文要讲的全部内容。我先把传统方案的问题摆出来你就能理解为什么需要它。现在 AI 代理要操作一个网页常见做法有三种截图后交给视觉模型解析、用 Playwright 之类的工具模拟点击、直接解析 DOM 抓数据。这三种方式都有一个共同的软肋——它们依赖的是「界面长什么样」而不是「功能是什么」。你改一个按钮的 class或者把搜索框从顶部挪到侧边栏代理就可能失效。视觉模型还贵复杂交互还容易点错。WebMCP 换了个思路。它不关心你的 UI 怎么排布而是让你主动声明我这个页面有一个叫search_products的工具它接收keyword和limit两个参数返回产品列表。AI 代理拿到这份结构化描述后直接调用这个函数拿到 JSON 结果。整个过程在浏览器内执行天然继承当前用户的登录态和权限不需要后端做任何改造也不需要把接口密钥暴露出去。这里要区分一个容易混淆的点WebMCP 和 MCP 不是一回事。MCP 是后端服务器向 AI 暴露能力的协议通常涉及 OAuth 2.1 认证跑在服务端WebMCP 是浏览器原生 API通过navigator.modelContext访问跑在页面里继承用户会话。简单说你要暴露企业数据库或本地文件系统用 MCP你要让网站本身被浏览器里的 AI 代理操作用 WebMCP。两者定位不同不冲突。对 Vue TypeScript 项目来说WebMCP 的吸引力在于类型安全。工具定义里的inputSchema如果手写 JSON Schema很容易和实际执行函数的参数类型对不上。而 Zod 可以在 TypeScript 里定义一次 schema既做运行时校验又能推导出静态类型还能转成 JSON Schema 给 AI 看。这条链路打通之后你写工具就像写普通的组合式函数一样自然。下面我会按「环境准备 → 可复制配置 → 验证调用 → 排错」的顺序把整条链路走一遍。你跟着做最后能在自己的 Vue 项目里注册一个工具并用浏览器扩展手动调用它看到真实返回结果。2. 环境准备与依赖安装Vue TypeScript Zod 项目初始化这一节的目标是让你有一个能跑起来的 Vue TypeScript 项目并且装好 WebMCP 相关的 polyfill 和 Zod。如果你已经有项目可以跳过创建步骤直接看依赖安装部分。先创建项目。用 Vite 的 Vue TypeScript 模板这是目前最省事的方式npm create vitelatest my-webmcp-app -- --template vue-ts cd my-webmcp-app npm install装完之后项目结构里会有src/main.ts、src/App.vue这些文件。TypeScript 配置默认已经开好tsconfig.json里strict通常是 true这对我们后面用 Zod 推导类型很友好。接下来装三个依赖npm install mcp-b/global mcp-b/vue-webmcp zod这三个包各自的作用要分清楚。mcp-b/global是 polyfill它会在浏览器里挂载navigator.modelContext对象让还不支持原生 WebMCP 的浏览器也能用。mcp-b/vue-webmcp是 Vue 的集成层提供组合式函数帮你在组件挂载和卸载时自动注册、注销工具。zod负责入参校验和类型推导。关于浏览器环境有两条路。第一条是用 Chrome 146 以上的 Canary 版本打开chrome://flags搜索并启用 Experimental Web Platform features重启浏览器这样能用原生 API。第二条是装 MCP-B 扩展在 Chrome 应用商店搜索 MCP-B 或 Model Context Tool Inspector添加到 Chrome。我建议两条都准备polyfill 保证代码在任何环境都能跑扩展用来手动测试工具调用。扩展这条路更稳定因为原生 API 还在 DevTrial 阶段行为可能变。装完依赖后在src/main.ts里引入 polyfill注意要放在创建应用之前import { createApp } from vue import App from ./App.vue import mcp-b/global const app createApp(App) app.mount(#app)这一步很关键。polyfill 必须在任何组件调用navigator.modelContext之前完成挂载否则你会遇到Cannot read properties of undefined (reading registerTool)这类报错。放在main.ts顶部是最稳妥的位置。如果你不想用 npm 包也可以在index.html里用 script 标签引入 IIFE 版本script srchttps://unpkg.com/mcp-b/globallatest/dist/index.iife.js/script但这种方式没有类型提示在 TypeScript 项目里不推荐。npm 包自带类型声明写代码时能自动补全registerTool的参数结构体验好很多。环境准备好之后先跑一下npm run dev确认页面能正常打开控制台没有报错。打开开发者工具在 Console 里输入navigator.modelContext如果返回一个对象而不是 undefined说明 polyfill 生效了。这一步是后面所有操作的前提别跳过。3. 可复制配置用 Zod 定义工具并用组合式函数注册这一节是全文的核心我会给你一份可以直接复制到项目里的配置包含 Zod schema 定义、TypeScript 类型推导、Vue 组合式函数封装以及一个完整的工具注册示例。路径和文件名都写清楚你照着建文件就行。先建一个目录src/composables在里面新建useWebMCP.ts。这个文件封装工具注册逻辑处理挂载时注册、卸载时注销import { onMounted, onUnmounted, ref } from vue import type { z } from zod export interface WebMCPToolT extends z.ZodTypeAny { name: string description: string schema: T readOnlyHint?: boolean execute: (input: z.inferT) Promiseunknown } export function useWebMCPT extends z.ZodTypeAny(tool: WebMCPToolT) { const registered ref(false) onMounted(() { if (!navigator.modelContext) { console.warn(WebMCP 不可用请检查 polyfill 或浏览器扩展) return } navigator.modelContext.registerTool({ name: tool.name, description: tool.description, inputSchema: zodToJsonSchema(tool.schema), readOnlyHint: tool.readOnlyHint ?? false, execute: tool.execute, }) registered.value true }) onUnmounted(() { if (registered.value navigator.modelContext) { navigator.modelContext.unregisterTool(tool.name) } }) return { registered } }这里有个细节要说明navigator.modelContext.registerTool接收的inputSchema是 JSON Schema 格式而 Zod 的 schema 对象不能直接传进去。所以需要一个转换函数zodToJsonSchema。Zod 官方有zod-to-json-schema这个包但为了减少依赖我这里给一个简化版的手写转换覆盖常见的 string、number、boolean、object 类型import type { z } from zod function zodToJsonSchema(schema: z.ZodTypeAny): Recordstring, unknown { const def (schema as any)._def const typeName def.typeName if (typeName ZodObject) { const shape def.shape() const properties: Recordstring, unknown {} const required: string[] [] for (const [key, value] of Object.entries(shape)) { properties[key] zodToJsonSchema(value as z.ZodTypeAny) if (!(value as any).isOptional()) { required.push(key) } } return { type: object, properties, required } } if (typeName ZodString) { return { type: string, description: def.description } } if (typeName ZodNumber) { return { type: number, description: def.description } } if (typeName ZodBoolean) { return { type: boolean, description: def.description } } if (typeName ZodOptional) { return zodToJsonSchema(def.innerType) } if (typeName ZodDefault) { const inner zodToJsonSchema(def.innerType) return { ...inner, default: def.defaultValue() } } return { type: object, properties: {}, required: [] } }如果你不想手写这个转换直接npm install zod-to-json-schema然后import { zodToJsonSchema } from zod-to-json-schema也行功能更全。我上面这个版本是为了让你看清转换逻辑实际项目建议用成熟库。接下来在组件里用。新建src/components/ProductSearch.vue写一个产品搜索工具script setup langts import { ref } from vue import { z } from zod import { useWebMCP } from /composables/useWebMCP const keyword ref() const results refArray{ id: string; name: string; price: number }([]) const loading ref(false) const searchSchema z.object({ keyword: z.string().min(1).describe(搜索关键词), limit: z.number().min(1).max(50).default(10).describe(返回结果数量上限), }) useWebMCP({ name: search_products, description: 根据关键词搜索产品返回产品列表, schema: searchSchema, readOnlyHint: true, async execute(input) { loading.value true try { const res await fetch( /api/products?keyword${encodeURIComponent(input.keyword)}limit${input.limit} ) const data await res.json() results.value data.products ?? [] return { success: true, count: results.value.length, products: results.value } } catch (error) { return { success: false, error: (error as Error).message } } finally { loading.value false } }, }) async function handleSearch() { if (!keyword.value) return const res await fetch(/api/products?keyword${encodeURIComponent(keyword.value)}limit10) const data await res.json() results.value data.products ?? [] } /script template div classproduct-search h2产品搜索/h2 input v-modelkeyword placeholder输入产品名称... keyup.enterhandleSearch / button clickhandleSearch搜索/button div v-ifloading加载中.../div ul v-else li v-foritem in results :keyitem.id{{ item.name }} - ¥{{ item.price }}/li /ul /div /template这份配置里searchSchema用 Zod 定义了keyword和limit两个字段limit有默认值 10。useWebMCP接收这个 schema在组件挂载时把工具注册到navigator.modelContext卸载时自动注销。readOnlyHint: true告诉 AI 这是一个只读操作不会修改数据代理可以放心调用。如果你要注册会修改数据的工具比如加入购物车把readOnlyHint设为 false并在execute里做权限检查。工具定义的三件套是 Base URL、Key、Model ID 吗不是那是模型接入的配置。WebMCP 工具的三件套是name、description、inputSchema这三个字段缺一不可AI 靠它们理解工具用途和参数格式。4. 验证请求用 MCP-B 扩展手动调用工具看结果配置写完了怎么确认工具真的注册成功、调用真的生效这一节给你一套可操作的验证流程从浏览器控制台到扩展面板一步步来。第一步启动项目npm run dev打开浏览器访问本地地址通常是http://localhost:5173。按 F12 打开开发者工具切到 Console 标签。第二步在 Console 里输入navigator.modelContext如果返回一个对象里面有registerTool、unregisterTool、provideContext这些方法说明 polyfill 正常。如果返回 undefined回到main.ts检查import mcp-b/global是不是在createApp之前。第三步确认工具已注册。在 Console 里输入navigator.modelContext.getTools?.()不同版本的 polyfill 方法名可能不同有的用listTools。如果这个方法不存在直接看 MCP-B 扩展面板更直观。第四步打开 MCP-B 扩展。点击浏览器工具栏的扩展图标在弹出的面板里切到 Tools 标签页。你应该能看到一个工具列表里面有一项叫search_products描述是「根据关键词搜索产品返回产品列表」。点开它能看到inputSchema的结构{ type: object, properties: { keyword: { type: string, description: 搜索关键词 }, limit: { type: number, description: 返回结果数量上限, default: 10 } }, required: [keyword] }这份 schema 就是 Zod 转换出来的结果。AI 代理看到它就知道调用这个工具需要传keyword可选传limit。第五步手动执行工具。在扩展面板里点击search_products参数输入框里填{ keyword: 笔记本, limit: 5 }点 Execute 按钮。如果一切正常你会看到返回的 JSON{ success: true, count: 5, products: [ { id: p1, name: 轻薄笔记本, price: 4999 }, { id: p2, name: 游戏笔记本, price: 8999 } ] }这个返回结果就是你的execute函数实际跑出来的。注意看limit传了 5返回的count就是 5说明 Zod 的默认值和校验都生效了。第六步测试校验失败的情况。把参数改成{ keyword: , limit: 100 }keyword是空字符串limit超过 50。如果 Zod 校验生效你应该看到错误提示而不是执行函数。这一步验证的是入参校验链路确保 AI 传了非法参数时不会直接打到你的业务逻辑。第七步测试只读标记。在扩展面板里看search_products的详情readOnlyHint应该显示为 true。这个标记会影响 AI 代理的调用策略只读工具通常不需要用户二次确认。如果你在扩展面板里看不到工具先刷新页面再检查 Console 有没有报错。常见的是navigator.modelContext is undefined回到第二步排查。还有一种情况是组件没挂载工具注册在onMounted里如果组件被v-if条件渲染且初始为 false工具就不会注册。验证通过之后你可以试着注册第二个工具比如get_cart然后刷新扩展面板确认两个工具都在列表里。这一步做完整条链路就算打通了。5. 常见报错排查401、local proxy failed、reading choices、OAuth这一节把你在接入过程中可能遇到的真实报错列出来对照着排查。这些报错不一定都来自 WebMCP 本身有些是模型接入或代理调用环节的但都会影响你验证工具是否生效。报错一navigator.modelContext is undefined这是最常见的。原因通常是 polyfill 没加载或者加载顺序不对。检查main.ts里import mcp-b/global是否在createApp之前。如果你用的是 script 标签确认它在所有业务脚本之前。还有一种可能是浏览器扩展和 polyfill 冲突先禁用扩展试试。报错二401 Unauthorized这个报错通常出现在你的execute函数里调用了后端 API而后端要求认证。WebMCP 工具继承用户会话但如果你的 fetch 请求没带 cookie 或 token就会 401。检查 fetch 是否设置了credentials: include或者手动带上 Authorization 头。如果你是通过 TaoToken 这类平台接入模型来驱动工具调用401 也可能是 API Key 配置问题去控制台确认 Key 是否有效、是否过期。报错三local proxy failed这个报错一般出现在你本地起了代理服务但代理没启动或端口不对。如果你在开发环境用代理转发请求检查代理进程是否在跑端口是否和配置一致。WebMCP 本身不需要代理这个报错多半来自你的网络请求层。报错四reading choicesCannot read properties of undefined (reading choices)是模型返回格式不符合预期时的典型报错。通常是你调用的模型接口返回了错误信息而不是标准的choices数组。检查请求体里的model字段是否写对Model ID 是否和平台文档一致。如果你用 TaoToken 接入确认 Base URL 是https://taotoken.net/apiModel ID 从文档里复制别手写。报错五OAuth相关错误WebMCP 本身继承用户会话不涉及 OAuth。但如果你在工具里调用了需要 OAuth 的第三方 API就会遇到 token 过期或 scope 不足的问题。检查 OAuth token 是否还在有效期scope 是否包含你要调用的接口。如果是 MCP 后端的 OAuth 2.1 流程那是另一套体系别和 WebMCP 混在一起。报错六工具注册了但扩展面板看不到先刷新页面再检查组件是否真的挂载了。如果工具注册在onMounted里而组件被v-if控制且初始为 false工具不会注册。把v-if改成v-show或者把注册逻辑提到父组件。还有一种可能是工具名重复registerTool对同名工具的处理策略因版本而异换个名字试试。报错七Zod 校验不生效检查zodToJsonSchema转换后的 schema 是否正确。在 Console 里打印navigator.modelContext里注册的工具看inputSchema是不是你期望的结构。如果required数组为空说明 Zod 的.optional()判断有问题检查字段是否真的必填。排查的时候有个通用思路先在 Console 里确认navigator.modelContext存在再确认工具注册成功最后确认execute函数能独立跑通。把这三层分开验证比一次性调试整个链路快得多。6. 从工具注册到代理调用把链路接到真实模型上工具能在扩展面板里手动调用只完成了一半。真正的场景是 AI 代理自动发现并调用你的工具。这一节讲怎么把链路接到真实模型上以及接入时需要注意的配置。WebMCP 的设计是浏览器原生 APIAI 代理通过navigator.modelContext发现工具。目前支持这个能力的代理还在早期Chrome 146 的 DevTrial 和 MCP-B 扩展是主要入口。如果你要在自己的应用里驱动工具调用通常的做法是前端注册工具后端或代理层通过模型决定调用哪个工具再把调用结果返回给模型继续推理。这里就涉及模型接入的配置。以 TaoToken 为例你需要三样东西Base URL、API Key、Model ID。Base URL 是https://taotoken.net/apiAPI Key 在控制台的 API Keys 页面创建Model ID 从文档里选一个支持工具调用的模型。配置写进你的请求体{ model: claude-sonnet-4-5, messages: [ { role: user, content: 帮我搜索一下笔记本 } ], tools: [ { name: search_products, description: 根据关键词搜索产品返回产品列表, input_schema: { type: object, properties: { keyword: { type: string }, limit: { type: number, default: 10 } }, required: [keyword] } } ] }模型返回tool_use块后你在前端执行对应的execute函数把结果作为tool_result回传模型继续生成最终回答。这条链路里WebMCP 负责工具发现和注册模型负责决策调用哪个工具你的execute函数负责实际执行。如果你用 Claude Code 做开发可以在项目里配置settings.json把工具调用相关的环境变量写进去。Cline 的 MCP 配置也是类似思路在配置文件里声明工具来源。Codex 的auth.json则用来存认证信息。这三件套的核心都是Base URL 指向服务地址Key 做认证Model ID 指定用哪个模型。长期做编码和 Agent 场景的话可以考虑用 Coding Plan 这类方案把模型调用和工具编排统一管理。验证模型是否支持工具调用可以在模型对话页面直接测试发一条带 tools 定义的请求看返回里有没有tool_use。接入文档里有完整的参数说明和示例遇到配置问题先查文档比在代码里猜快。API Keys 页面可以创建和管理密钥注意别把 Key 提交到代码仓库。整条链路跑通之后你的 Vue 项目就不只是给人看的页面了它同时是一个 AI 代理可以调用的工具集。从注册工具到浏览器端调用再到模型决策每一层都有可验证的动作。先把search_products这个只读工具跑通再逐步加带副作用的工具配合readOnlyHint和权限检查这样上线风险可控。
延伸阅读

更多相关文章

2026/10/18 14:07:51

C# WinForms嵌入PDF查看器:OCX控件零依赖集成指南

简介:PDFViewer OCX是一款面向C#、C及Web开发者的轻量级PDF文档嵌入控件,专为解决桌面应用与传统网页中无需依赖Adobe Reader即可实现PDF查看、交互与定制化集成的痛点。资源包共82个文件,涵盖12个头文件(.h)与9个C源码…

2026/10/18 14:07:51

新华字典微信小程序源码深度解析:汉字检索工程实践

简介:新华字典微信小程序源码是一份面向前端初学者与小程序开发入门者的实战型学习资源,聚焦汉字查询功能实现,帮助开发者快速掌握微信小程序核心开发范式。资源共34个文件,包含8个WXML页面结构文件、7个JS逻辑脚本、6个WXSS样式文…

2026/10/18 14:07:51

零代码自动化工作流,砍掉电商团队90%重复劳动

周一早上九点,我面前的三块屏幕上摆着三张必须手动整理的表格:一个后台的销售数据、另一个后台的广告报表、还有一个客户群里的异常订单清单。把这三个来源凑成一份像样的日报,再用复制粘贴的原始方式发给老板和项目方,大概需要一…

2026/10/18 18:03:36

政务数据分类分级落地难?低代码配置与业务赋能实践指南

这两年做政务数据相关项目的人,基本都绕不开“分类分级”这四个字。标准文件翻来覆去读了好几遍,方案PPT也写了几十页,但一落到实际环境里,经常是台账做了一本又一本,系统里该有的策略一条没配上。真正的问题不是大家不…

2026/10/18 18:03:36

形变场形式转换实战:DDF、B样条与速度场互转及避坑指南

做配准项目时间长了,你会发现一个规律:算法输出给你的,不一定是下游真正需要的。上周我处理一个跨模态配准任务,跑完变形模型,拿到的是一套B样条控制点和速度场,可下游要用来做标签传播,需要的是…

2026/10/18 18:03:36

YOLO结合SubspaceAD:一张良品图检出所有未知缺陷

YOLO SubspaceAD:一张良品图,检出所有未知缺陷在工业质检这个圈子里摸爬滚打了几年,我越来越觉得传统的视觉检测方案到了一个瓶颈:已知缺陷能查,但新出现的缺陷形态往往要等客户投诉之后才后知后觉。这次我想聊聊一套…

2026/10/18 18:03:36

机器学习分类任务全流程指南:从数据准备到模型评估

拿到“第五章:如何处理分类任务(预习)”这个标题,我第一反应是:这不就是大多数人在机器学习入门阶段都会卡住的那一章吗?前面还在学回归、学损失函数、学梯度下降,突然进入分类任务,…

2026/10/18 18:03:36

C#彻底删除PDF数字签名:字段、外观与残留清理全攻略

收到需求“用 C# 删除 PDF 里的数字签名”,大部分人以为这是件小事,打开文件、删个字段、保存,三行代码搞定。实际上我第一次接到类似需求就栽了跟头:用 RemoveField 删掉字段后,页面上的签名图片还赖着不走&#xff1…

2026/10/18 17:58:36

国产AI加速卡上的垂域大模型训练:从硬件选型到微调实战

过去一年我大部分时间都泡在国产AI加速卡的训练集群上,折腾的不是那种演示级别的玩具模型,而是真正要落地到具体行业里的垂域大模型。垂直行业的模型训练和微调,跟互联网那种亿万级通用数据训练完全是两码事:数据量没那么多&#…

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑