Skip to content

useWebMCP ​

类别
导出体积
803 B
上次更改
2 months ago

注册一个 WebMCP 工具,并将其生命周期绑定到当前 Vue 作用域。

WebMCP 允许页面将 JavaScript 函数公开为“工具”,供 AI 代理(浏览器内置代理、iframe 承载的代理或扩展)发现并调用,而无需抓取 DOM、无障碍树或屏幕截图。useWebMCP 将基于 AbortSignal 的命令式注册 API 封装为声明式组合式函数:调用时注册工具,作用域销毁时自动注销,让代理可见的工具始终与屏幕上实际显示的内容保持同步。

实验性

WebMCP 规范仍处于 🧪 实验阶段,并在 document.modelContext 上提供命令式 API(使用 registerTool 注册,并通过 AbortSignal 注销)。此组合式函数会检测 API 是否可用;若 API 不存在则不执行操作。使用前请检查 isSupported。

示例 ​

浏览器支持:false

工具已注册:false

WebMCP 兼容代理可以调用 add-todo 工具向下方列表添加项目;你也可以手动编辑同一列表。此演示卸载时会自动注销该工具。

用法 ​

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 如下:

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()

结果规范化 ​

execute 返回的值会被规范化为有效的 MCP 工具结果:

  • 字符串 → { content: [{ type: 'text', text }] }
  • undefined/null(无返回值)→ { content: [] }(成功,无负载)
  • 已经是 { content: [...] } 的值 → 原样传递
  • 抛出的值(无论是否为 Error,例如 throw 'not signed in'、throw { code: 403 })→ 触发 onError 后返回 { content: [{ type: 'text', text }], isError: true }。失败不能被代理误认为成功。
  • 返回的 Error → 与抛出错误的处理方式相同:触发 onError,然后返回带有 isError 的结果
  • 其他值(对象、数组、数字)→ 序列化为 JSON 文本块

响应式与条件注册 ​

name、description、inputSchema、annotations 和 enabled 都接受 ref 或 getter。更改可发现字段时会重新注册工具;切换 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
)
}, })

注册多个工具 ​

每个工具调用一次 useWebMCP 即可注册多个工具;每次调用都会独立管理自身的注册生命周期。

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
() {
// … }, })

参考资料 ​

类型声明 ​

显示类型声明
ts
/**
 * A single block of a WebMCP tool result.
 *
 * @see https://github.com/webmachinelearning/webmcp
 */
export interface WebMCPToolContent {
  
type
: string
text
?: string
[
key
: string]: unknown
} /** * The normalized result an agent receives after a tool runs. */ export interface WebMCPToolResponse {
content
: WebMCPToolContent[]
isError
?: boolean
} /** * Hints an author can attach to a tool to shape how an agent uses it. */ export interface WebMCPToolAnnotations { /** * The tool does not mutate state and is safe to call speculatively. */
readOnlyHint
?: boolean
/** * The tool may return content that should be treated as untrusted. */
untrustedContentHint
?: boolean
[
key
: string]: unknown
} /** * The imperative descriptor passed to `document.modelContext.registerTool`. */ export interface WebMCPToolDescriptor {
name
: string
description
: string
inputSchema
?: object
annotations
?: WebMCPToolAnnotations
execute
: (
args
: any) =>
Promise
<WebMCPToolResponse> | WebMCPToolResponse
} /** * The (experimental) imperative WebMCP API surface exposed on `document`. */ export interface ModelContext {
registerTool
: (
tool
: WebMCPToolDescriptor,
options
?: {
signal
?: AbortSignal
}, ) => void } export interface
UseWebMCPOptions
<
Args
,
Result
> extends ConfigurableDocument {
/** * Tool identifier the agent uses to invoke this tool. */
name
:
MaybeRefOrGetter
<string>
/** * Natural-language description the agent reads to decide when to call it. */
description
:
MaybeRefOrGetter
<string>
/** * JSON Schema describing the tool arguments. */
inputSchema
?:
MaybeRefOrGetter
<object | undefined>
/** * Hints (`readOnlyHint`, `untrustedContentHint`, …) shaping agent behavior. */
annotations
?:
MaybeRefOrGetter
<WebMCPToolAnnotations | undefined>
/** * The function the agent calls. May be async. Its return value is normalized * into a WebMCP tool result, and any thrown/returned `Error` becomes an * `isError` result. */
execute
: (
args
:
Args
) =>
Result
|
Promise
<
Result
>
/** * Register the tool only while this is `true`. * * @default true */
enabled
?:
MaybeRefOrGetter
<boolean>
/** * Shape the `execute` result before it is normalized into a tool response. */
formatOutput
?: (
result
:
Result
,
args
:
Args
) => unknown
/** * Side effect invoked when `execute` (or `formatOutput`) throws/returns an error. */
onError
?: (
error
: unknown) => void
} export interface UseWebMCPReturn extends Supportable { /** * Whether the tool is currently registered with the browser. */
isRegistered
:
ShallowRef
<boolean>
/** * Registration error, e.g. a `NotAllowedError` from a `tools` permissions policy. */
error
:
ShallowRef
<Error | null>
} /** * Register a [WebMCP](https://github.com/webmachinelearning/webmcp) tool and * tie its lifecycle to the current scope. * * The tool is registered when the composable runs (and whenever a discoverable * part — `name`, `description`, `inputSchema`, `annotations` or `enabled` — * changes) and unregistered automatically on scope dispose, so the tools an * agent sees stay in lockstep with what is on screen. Call it multiple times to * register multiple tools. * * The API is experimental (`document.modelContext`), so this feature-detects * and degrades to a no-op wherever it is absent. * * @see https://vueuse.org/useWebMCP * @see https://github.com/webmachinelearning/webmcp */ export declare function
useWebMCP
<
Args
=
Record
<string, any>,
Result
= unknown>(
options
:
UseWebMCPOptions
<
Args
,
Result
>,
): UseWebMCPReturn

源码 ​

源码 • 演示 • 文档

贡献者 ​

zhcndoc-bot
Anthony Bot

更新日志 ​

172c5 - feat(core): add useWebMCP (#5580)