拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Puppeteer WebMCPTool API 深度解析:枚举、执行与取消页面端 WebMCP 工具

Puppeteer WebMCPTool API 深度解析枚举、执行与取消页面端 WebMCP 工具【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteerWebMCPTool是 Puppeteer 中代表页面注册的 WebMCPWeb Model Context Protocol工具的类它把网页里通过document.modelContext.registerTool()命令式或form toolname声明式暴露出来的 AI 工具映射为 Node.js 侧可直接枚举、订阅和调用的对象。本文以 docs/api/puppeteer.webmcptool.md 为主体结合 packages/puppeteer-core/src/cdp/WebMCP.ts 源码与 test/src/cdp/webmcp.test.ts 测试系统讲解WebMCPTool的类声明、全部属性语义、execute()底层调用链含 AbortSignal 取消机制以及完整的端到端使用范例。WebMCPTool 在 Puppeteer WebMCP 能力中的位置WebMCP 是一套实验性的浏览器侧模型上下文协议支持其 Puppeteer 侧 API 由实验性的 WebMCP 类 提供通过page.webmcp访问。在源码中抽象基类 Page 声明了实验性 getterabstract get webmcp(): WebMCPCDP 实现 cdp/Page.ts 在内部维护一个#webmcp实例并于页面初始化时调用WebMCP.enable开启协议域WebMCP类内部按 frame 维护一张工具表并把协议事件翻译成toolsadded、toolsremoved、toolinvoked、toolresponded事件见 WebMCP.ts。WebMCPTool正是这套能力中被注册出来的单个工具对象。它由WebMCP内部根据 CDP 协议事件WebMCP.toolsAdded自动创建见 WebMCP.ts因此其实例的name、description等字段与页面上注册的工具一一对应。官方 API 文档给出的最小使用方式如下await page.goto(https://www.example.com); const tools page.webmcp.tools(); for (const tool of tools) { console.log(Tool found: ${tool.name} - ${tool.description}); }类声明与继承关系WebMCPTool是一个基于事件驱动的公开类官方签名如下export declare class WebMCPTool extends EventEmitter{ toolinvoked: WebMCPToolCall; }Extends:EventEmitter{ toolinvoked: WebMCPToolCall }几点关键语义它继承自 Puppeteer 的EventEmitter泛型约束声明了唯一一个工具级事件toolinvoked载荷是 WebMCPToolCall。该事件在工具被调用开始时触发。构造函数标记为 internal第三方代码不应直接new WebMCPTool(...)或创建其子类。所有实例都应通过page.webmcp.tools()或在toolsadded事件中获得详见 WebMCP 类 的tools()方法。源码注释中该类被标记为experimental见 WebMCP.ts且测试环境需要以--enable-featuresWebMCP启动浏览器见 webmcp.test.ts意味着它在当前 Puppeteer 版本中属于预览特性使用前应确认你的浏览器版本已启用对应开关。属性逐一详解WebMCPTool的属性可以分为两类一类是直接从协议对象映射来的元数据name、description、inputSchema、annotations、location另一类是辅助定位页面上对应元素的运行时能力frame、formElement。属性修饰符类型说明annotationsoptionalProtocol.WebMCP.Annotation工具的可选注解信息description-string工具描述formElementreadonlyPromiseElementHandle | undefined当工具通过 form 声明时对应的 ElementHandleframe-Frame定义该工具的 FrameinputSchemaoptionalobject工具输入参数的 SchemalocationoptionalConsoleMessageLocation定义该工具的源码位置如有name-string工具名称name 与 descriptionname是工具名称如test-tool-1description是面向模型/调用方的自然语言描述。二者直接取自 CDP 事件中的协议对象源码构造器中this.name tool.name; this.description tool.description;是定位、展示和去重的核心标识。inputSchema输入参数 SchemainputSchema声明工具期望的输入结构。它直接透传页面注册工具时提供的 JSON Schema 对象测试用例中命令式注册一个含text字段的工具后枚举得到的inputSchema为{ type: object, properties: { text: { type: string, description: Some text } }, required: [text] }而在声明式form场景下页面只提供toolname/tooldescription因此浏览器合成的 schema 为空对象结构{ type: object, properties: {}, required: [] }。execute()传入的input参数即应匹配该 schema。annotations工具注解annotations记录工具的可选注解类型为Protocol.WebMCP.Annotation属于实验性协议信息。从测试可以归纳三类常见语义readOnly是否只读工具命令式注册时传readOnlyHint: true会映射为readOnly: trueuntrustedContent是否可能接触/产出不可信内容untrustedContentHint: true→untrustedContent: trueautosubmit声明式 form 工具若带toolautosubmit属性则autosubmit: true。对应断言见 webmcp.test.ts。由于是optional页面上注册工具未声明注解时该字段为undefined。frame工具所属的 Frame每个工具都绑定到定义它的 Frame。源码将工具按frameId分组存储于Mapstring, Mapstring, WebMCPTool实例的frame指向tool.frame._id对应的 frame。多 frame 场景下不同 frame 注册的同名工具互不干扰在测试中页面主 frame 注册的工具其frame恒等于page.mainFrame()。location定义处的源码位置location记录定义该工具的源码位置类型为 ConsoleMessageLocation。源码实现取自协议事件中的调用栈首帧if (tool.stackTrace?.callFrames.length) { this.location { url: tool.stackTrace.callFrames[0]!.url, lineNumber: tool.stackTrace.callFrames[0]!.lineNumber, columnNumber: tool.stackTrace.callFrames[0]!.columnNumber, }; }见 WebMCP.ts。因此命令式注册通过 JS 调用registerTool的工具通常能拿到location声明式form 工具则没有 JS 调用栈location为undefined测试 webmcp.test.ts 正好验证了这一差异。formElement声明式工具对应的表单元素formElement是只读 getter返回PromiseElementHandleHTMLFormElement | undefined。当工具通过form toolname...声明时它解析为该表单的 ElementHandle命令式注册的工具没有后端节点 ID则解析为undefined。底层实现采用惰性解析 缓存首次访问时若存在backendNodeId通过 frame 主世界的adoptBackendNode将后端节点收养为ElementHandle并缓存后续访问且句柄未被 dispose 时直接复用见 WebMCP.ts。由于是 Promise调用时务必awaitconst el await tool.formElement; // ElementHandleHTMLFormElement | undefined if (el) { const name await el.evaluate(f f.getAttribute(toolname)); }execute()执行一次工具调用execute()是WebMCPTool的核心方法官方文档签名如下class WebMCPTool { execute( input?: object, options?: WebMCPToolExecuteOptions, ): PromiseWebMCPToolCallResult; }参数类型说明inputobject(可选)与工具inputSchema匹配的输入参数对象optionsWebMCPToolExecuteOptions(可选)执行选项返回PromiseWebMCPToolCallResultWebMCPToolExecuteOptions 目前只有一个字段signal?: AbortSignal用于取消工具执行。底层调用链从 execute 到 CDP 再到响应阅读源码 WebMCP.ts 可以还原execute()的真实工作流发起调用input缺省为{}options缺省为{}。方法先调用内部#webmcp.invokeTool(this, input)后者向浏览器发送 CDP 命令WebMCP.invokeTool携带frameId、toolName与input返回一个invocationId。等待结果execute()挂载toolresponded事件监听只有event.id invocationId的响应才会被接受并 resolve。这一步保证了并发多次调用时结果不会串线。支持取消若传入的options.signalAbortSignal触发abort会调用WebMCP.cancelInvocation协议命令取消该次调用若 signal 传入时已处于 aborted 状态则立即执行取消逻辑。取消后的工具执行同样会收到一份status为Canceled的结果。对应的测试用例覆盖了完整闭环注册一个execute返回hello ${params.text}的工具然后执行await tool.execute({text: world})最终返回结果status Completed且output hello world见 webmcp.test.ts用延迟 5 秒返回的工具配合AbortController则得到status Canceled见 webmcp.test.ts。返回值语义WebMCPToolCallResult返回的 WebMCPToolCallResult 接口包含字段类型说明idstring调用标识符与对应的调用事件一致callWebMCPToolCall对应的调用对象若可得statusProtocol.WebMCP.InvocationStatus调用状态outputany交付给调用方的输出仅status为Completed时存在errorTextstring错误文本exceptionProtocol.Runtime.RemoteObject若 JS 工具抛错则携带异常对象由测试可以归纳出几种典型的返回组合工具正常返回 →status: Completedoutput为返回值errorText/exception为undefined工具执行体throw new Error(sorry!)→status: Erroroutput为undefinedexception.description中包含sorry输入参数无法解析如传给页面的不是合法 JSON→status: ErrorerrorText为Failed to parse input arguments调用被 AbortSignal 取消 →status: Canceled。监听 toolinvoked工具调用开始事件由于WebMCPTool继承自EventEmitter{toolinvoked: WebMCPToolCall}可以直接在单个工具上订阅调用事件const tool page.webmcp.tools().find(t t.name search-tool); tool?.on(toolinvoked, call { console.log(invocation ${call.id} started with input:, call.input); });WebMCPToolCall 的三个字段由源码实现见 WebMCP.ts支撑id调用的唯一标识符tool被调用的 WebMCPToolinput本次调用的输入参数对象。其中input的来路值得一提协议层把输入作为JSON 字符串交付源码通过JSON.parse(input)转成对象解析失败时兜底为{}并通过 debug 日志记录DEBUG_PREFIXES.error。因此当页面端传给工具的是非法 JSON 时工具调用事件中的input只会是空对象真正的错误会体现在稍后的toolresponded结果里。工具被调用时事件是双路广播的WebMCP管理类会同时emit(toolinvoked, call)见 WebMCP.ts所以既可以在单个WebMCPTool上监听也可以在page.webmcp上统一监听所有工具的调用。端到端实践注册、枚举、执行与取消把以上概念串起来一个完整、可复现的流程如下。前置条件使用支持 WebMCP 的 Chromium 版本并开启实验特性开关参考仓库测试的启动方式--enable-featuresWebMCP。import puppeteer from puppeteer; const browser await puppeteer.launch({ args: [--enable-featuresWebMCP], }); const page await browser.newPage(); await page.goto(https://example.com); // 1) 订阅工具增删与调用事件page.webmcp 与单个 tool 均可订阅 page.webmcp.on(toolsadded, ({tools}) { console.log(tools added:, tools.map(t t.name)); }); page.webmcp.on(toolsremoved, ({tools}) { console.log(tools removed:, tools.map(t t.name)); }); // 2) 枚举页面定义的所有工具等待工具注册完成后再调用 const tools page.webmcp.tools(); for (const tool of tools) { console.log(Tool found: ${tool.name} - ${tool.description}); if (tool.inputSchema) { console.log( inputSchema:, JSON.stringify(tool.inputSchema)); } const el await tool.formElement; // 声明式工具可拿到 form ElementHandle } // 3) 按名称挑选工具并执行input 需匹配 inputSchema const target tools.find(t t.name test-tool-1); if (!target) { throw new Error(tool not found); } target.on(toolinvoked, call { console.log(invoked: ${call.id}, call.input); }); const controller new AbortController(); const result await target.execute({text: world}, {signal: controller.signal}); // 4) 依据状态处理结果 if (result.status Completed) { console.log(output:, result.output); } else if (result.status Canceled) { console.log(tool execution was canceled); } else { console.error(tool failed:, result.errorText, result.exception); } // 超时兜底若不想再等主动 abort底层会发 WebMCP.cancelInvocation // controller.abort(); await browser.close();测试仓库中同样给出了页面侧如何注册工具的对照这部分发生在页面上下文属于浏览器 WebMCP 能力Puppeteer 侧只负责发现与调用// 命令式在页面内注册 await page.evaluate(async () { await document.modelContext?.registerTool({ name: test-tool-1, description: A test tool 1, inputSchema: { type: object, properties: {text: {type: string, description: Some text}}, required: [text], }, execute: (params: {text: string}) hello ${params.text}, annotations: {readOnlyHint: true, untrustedContentHint: true}, }); }); // 声明式插入带 toolname / tooldescription 的 form await page.evaluate(() { const form document.createElement(form); form.setAttribute(toolname, declarative tool name); form.setAttribute(tooldescription, tool description); document.body.appendChild(form); });注册完成后Puppeteer 侧会先后收到toolsadded事件page.webmcp.tools()的返回长度与注册的工具数量一致且命令式工具带location而无formElement声明式工具正好相反断言见 webmcp.test.ts。生命周期与清理行为理解WebMCPTool的存活边界有助于避免读到过期句柄工具按 frame 维度管理整页导航导致旧执行上下文销毁时该 frame 下所有工具会被清理并触发toolsremoved同时清空pendingCalls待处理调用见 WebMCP.ts。同文档导航如 hash 变化不销毁执行上下文因此工具依然保留测试验证了page.goto(url #hash)之后page.webmcp.tools()仍返回原工具见 webmcp.test.ts。命令式工具可由页面在注册时传入AbortController.signal后续controller.abort()即注销工具并触发toolsremoved声明式工具则通过移除对应form节点来卸载见 webmcp.test.ts。这意味着推荐的实践是用toolsadded/toolsremoved事件维护工具清单而不是长期缓存tools()的返回值在导航后重新调用page.webmcp.tools()获取最新集合。小结WebMCPTool把页面声明式/命令式暴露的 WebMCP 工具封装为可直接消费的对象通过name、description、inputSchema、annotations了解工具契约通过frame与formElement定位其来源通过execute(input, {signal})发起调用并可取消通过toolinvoked事件感知调用开始。深入阅读 packages/puppeteer-core/src/cdp/WebMCP.ts 可以看到它与 CDPWebMCP.*协议命令及toolsadded/toolsremoved/toolinvoked/toolresponded事件之间的完整映射test/src/cdp/webmcp.test.ts 则提供了覆盖成功、异常、解析失败、取消、导航清理等全部分支的可运行样本。由于 WebMCP 仍属实验特性生产使用前务必确认浏览器版本、特性开关与 Puppeteer 版本三者兼容。【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门