主题
useWebMCP
注册一个 WebMCP 工具,并将其生命周期绑定到当前的 Vue 范围。
🌐 Register a WebMCP tool and tie its lifecycle to the current Vue scope.
WebMCP 允许页面将 JavaScript 函数作为“工具”暴露出来,这样 AI 代理(浏览器内置、iframe 托管或扩展)就可以发现并调用它们,而不需要抓取 DOM、无障碍树或截图。useWebMCP 将命令式的、基于 AbortSignal 的注册 API 封装成一个声明式可组合体:当可组合体运行时工具会被注册,当作用域被销毁时会自动注销,所以代理看到的工具集合会与屏幕上实际存在的工具保持同步。
🌐 WebMCP lets a page expose JavaScript functions as "tools" that an AI agent (browser-built-in, iframe-hosted, or extension) can discover and call, instead of scraping the DOM, the accessibility tree, or screenshots. useWebMCP wraps the imperative, AbortSignal-based registration API in a declarative composable: the tool is registered when the composable runs and unregistered automatically when the scope is disposed, so the set of tools an agent sees stays in lockstep with what is actually on screen.
实验性的
WebMCP 规范是 🧪 实验性的,并且在 document.modelContext 上暴露了命令式 API(registerTool + 一个用于注销的 AbortSignal)。这个可组合功能会进行特性检测,并在 API 不存在的地方降级为无操作——在依赖它之前请检查 isSupported。
示例
Supported: false
Tool registered: false
When a WebMCP-capable agent is present, it can call the
add-todo tool to append items below — the same list you edit by hand. The tool is unregistered automatically when this demo unmounts. 用法
🌐 Usage
ts
import { useWebMCP } from '@vueuse/core'
import { shallowRef } from 'vue'
const todos = shallowRef<string[]>([])
const { isSupported, isRegistered, error } = useWebMCP({
name: 'add-todo',
description: 'Add a new item to the user\'s active todo list',
inputSchema: {
type: 'object',
properties: {
text: { type: 'string', description: 'The text content of the todo item' },
},
required: ['text'],
},
async execute({ text }) {
todos.value = [...todos.value, text]
return `Added todo item: "${text}" successfully.`
},
})js
import { useWebMCP } from '@vueuse/core'
import { shallowRef } from 'vue'
const todos = shallowRef([])
const { isSupported, isRegistered, error } = useWebMCP({
name: 'add-todo',
description: "Add a new item to the user's active todo list",
inputSchema: {
type: 'object',
properties: {
text: {
type: 'string',
description: 'The text content of the todo item',
},
},
required: ['text'],
},
async execute({ text }) {
todos.value = [...todos.value, text]
return `Added todo item: "${text}" successfully.`
},
})这个封装的原始命令式 API 看起来像这样:
🌐 The raw imperative API this wraps looks like:
ts
const controller = new AbortController()
document.modelContext.registerTool({
name: 'add-todo',
description: 'Add a new item to the user\'s active todo list',
inputSchema: { /* … */ },
async execute({ text }) {
return { content: [{ type: 'text', text: `Added todo item: "${text}".` }] }
},
}, { signal: controller.signal })
// Unregister later:
controller.abort()js
'use strict'
const controller = new AbortController()
document.modelContext.registerTool(
{
name: 'add-todo',
description: "Add a new item to the user's active todo list",
inputSchema: {/* … */},
async execute({ text }) {
return {
content: [{ type: 'text', text: `Added todo item: "${text}".` }],
}
},
},
{ signal: controller.signal },
)
// Unregister later:
controller.abort()结果归一化
🌐 Result normalization
无论 execute 返回什么,都会被规范化为有效的 MCP 工具结果:
🌐 Whatever execute returns is normalized into a valid MCP tool result:
- 一个 字符串 →
{ content: [{ type: 'text', text }] } undefined/null(无返回)→{ content: [] }(成功,无负载)- 一个已经是
{ content: [...] }的值 → 无变化通过 - 一个 抛出的值 —
Error或不是(throw 'not signed in'、throw { code: 403 })→{ content: [{ type: 'text', text }], isError: true },在onError之后。失败绝不能被代理当作成功读取。 - 一个 返回的
Error→ 完全像抛出一样处理:onError触发,然后得到一个isError结果 - 其他任何东西(对象/数组/数字)→ 序列化为 JSON 文本块
反应式&条件注册
🌐 Reactive & conditional registration
name、description、inputSchema、annotations 和 enabled 接受 refs 或 getters。修改可发现的字段会重新注册该工具;切换 enabled 会先注销再重新注册。execute、formatOutput 和 onError 会在调用时实时读取,所以不断变化的闭包不会影响注册。
ts
import { useWebMCP } from '@vueuse/core'
import { shallowRef } from 'vue'
const signedIn = shallowRef(false)
useWebMCP({
name: 'checkout',
description: 'Complete the checkout for the current cart',
enabled: signedIn, // only exposed to agents while signed in
annotations: { readOnlyHint: false },
execute() {
// …
},
onError(err) {
console.error('checkout tool failed', err)
},
})注册多个工具
🌐 Registering multiple tools
每个工具只需调用一次 useWebMCP 来注册多个 —— 每次调用都会管理自己的注册生命周期。
🌐 Call useWebMCP once per tool to register several — each call manages its own registration lifecycle.
ts
import { useWebMCP } from '@vueuse/core'
useWebMCP({
name: 'add-todo',
description: 'Add a new item to the todo list',
execute({ text }) {
// …
},
})
useWebMCP({
name: 'clear-todos',
description: 'Remove every item from the todo list',
annotations: { readOnlyHint: false },
execute() {
// …
},
})参考
🌐 References
- WebMCP 讲解与规范说明 (webmachinelearning/webmcp)
- GoogleChromeLabs/use-webmcp-tool — 这个可组合函数是基于这个 React hook 模型的