webmcp-builder

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

WebMCP Tool Development Guide

WebMCP 工具开发指南

Overview

概述

WebMCP is a browser API that lets web developers expose their application's functionality as "tools" — JavaScript functions with natural language descriptions and structured schemas — that AI agents, browser assistants, and assistive technologies can invoke. Think of it as turning a web page into an MCP server, but the tools run in client-side JavaScript instead of on a backend.
The key insight: WebMCP enables collaborative, human-in-the-loop workflows where users and agents work together within the same web interface. The user stays in control, the UI updates in real time, and the agent gets structured access to app functionality instead of having to scrape or automate the UI.
WebMCP also benefits accessibility — users with accessibility needs can complete tasks via conversational or agentic interfaces instead of relying solely on the accessibility tree, which many websites haven't fully implemented. See Accessibility-Focused Tool Design for concrete patterns.
WebMCP aligns closely with MCP tool schemas (
name
,
description
,
inputSchema
,
execute
), so developers familiar with MCP can reuse their knowledge. The key difference: WebMCP tools run client-side in the browser, not on a backend server. The browser intermediates between the page and the agent, which allows it to enforce security policies and maintain backwards compatibility as MCP evolves. For always-on server-to-server tool access without a browser, use a traditional MCP server instead.

WebMCP是一款浏览器API,允许Web开发者将其应用的功能封装为「工具」——即带有自然语言描述和结构化Schema的JavaScript函数,AI Agent、浏览器助手及辅助技术均可调用这些工具。你可以把它理解为将网页转变为MCP服务器,但工具运行在客户端JavaScript中,而非后端服务器。
核心亮点:WebMCP支持协作式的人在环工作流,用户与Agent可在同一Web界面内协同工作。用户始终保持控制权,UI实时更新,Agent能以结构化方式访问应用功能,无需通过爬取或自动化UI来实现操作。
WebMCP还对可访问性有帮助——有访问需求的用户可通过对话式或Agent驱动的界面完成任务,无需完全依赖许多网站尚未充分实现的可访问性树。具体模式可参考面向可访问性的工具设计
WebMCP与MCP工具Schema(
name
description
inputSchema
execute
)高度对齐,熟悉MCP的开发者可复用已有知识。核心区别在于:WebMCP工具运行在浏览器客户端,而非后端服务器。浏览器作为页面与Agent之间的中间层,可执行安全策略,并在MCP演进时保持向后兼容性。如果需要无需浏览器的持续服务器对服务器工具访问,请使用传统MCP服务器。

Quick Start

快速开始

Here's a minimal, complete WebMCP tool — feature detect, register, execute, and return a result:
js
// Check if the browser supports WebMCP
if ("modelContext" in navigator) {
	navigator.modelContext.registerTool({
		name: "greet_user",
		description: "Returns a personalized greeting for the given name.",
		inputSchema: {
			type: "object",
			properties: {
				name: { type: "string", description: "The person's name" }
			},
			required: ["name"]
		},
		execute: ({ name }) => {
			document.getElementById("greeting").textContent = `Hello, ${name}!`;
			return `Greeted ${name} successfully.`;
		}
	});
}
This covers the four essentials: feature detection (
"modelContext" in navigator
), tool registration (
registerTool
), execution logic (update the DOM), and an informative return value. Everything below expands on this pattern.

以下是一个完整的极简WebMCP工具示例——包含特性检测、注册、执行及结果返回:
js
// 检查浏览器是否支持WebMCP
if ("modelContext" in navigator) {
	navigator.modelContext.registerTool({
		name: "greet_user",
		description: "Returns a personalized greeting for the given name.",
		inputSchema: {
			type: "object",
			properties: {
				name: { type: "string", description: "The person's name" }
			},
			required: ["name"]
		},
		execute: ({ name }) => {
			document.getElementById("greeting").textContent = `Hello, ${name}!`;
			return `Greeted ${name} successfully.`;
		}
	});
}
这个示例涵盖了四个核心要点:特性检测(
"modelContext" in navigator
)、工具注册(
registerTool
)、执行逻辑(更新DOM)以及信息丰富的返回值。下文将基于此模式展开详细说明。

Process

开发流程

Phase 1: Understand the Requirements

阶段1:明确需求

Before writing any code, clarify what the web app needs to expose to agents:
  1. What actions should agents be able to perform? List the core operations (e.g., "add item", "search", "filter results", "submit form").
  2. What data should agents be able to read? Identify read-only queries (e.g., "get current state", "list items").
  3. Does the tool set change based on UI state? Single-page apps may need to register/unregister tools as the user navigates between views.
  4. What user interactions need confirmation? Destructive or irreversible actions (purchases, deletions) should use
    agent.requestUserInteraction()
    .
Guiding questions to ask before coding:
  • What existing JavaScript functions already do what you need? (Wrap them — don't rewrite.)
  • What's the app's framework? (Vanilla JS, React, Vue, etc. — this determines the UI sync pattern.)
  • Are there form validations or business rules that tools must respect?
  • What data is sensitive and should NOT be exposed as tool parameters?
  • Will the app be served over HTTPS in production? (Some browsers restrict
    modelContext
    to secure contexts.)
编写代码前,先理清Web应用需要向Agent开放哪些功能:
  1. Agent应能执行哪些操作? 列出核心操作(例如:「添加项目」「搜索」「筛选结果」「提交表单」)。
  2. Agent应能读取哪些数据? 确定只读查询(例如:「获取当前状态」「列出项目」)。
  3. 工具集是否随UI状态变化? 单页应用可能需要在用户切换视图时注册/注销工具。
  4. 哪些用户操作需要确认? 破坏性或不可逆操作(如购买、删除)应使用
    agent.requestUserInteraction()
编码前需思考的引导问题:
  • 现有JavaScript函数中已有哪些能实现所需功能?(直接封装——无需重写。)
  • 应用使用的框架是什么?(原生JS、React、Vue等——这决定了UI同步模式。)
  • 是否存在工具必须遵守的表单验证规则或业务逻辑?
  • 哪些敏感数据不应作为工具参数暴露?
  • 生产环境中应用是否通过HTTPS提供服务?(部分浏览器仅在安全上下文环境中允许使用
    modelContext
    。)

Phase 2: Design the Tools

阶段2:工具设计

Good WebMCP tools share these qualities:
  • Action-oriented names: Use verb-noun format like
    add_item
    ,
    search_flights
    ,
    set_filters
    . Kebab-case (
    add-item
    ) or snake_case (
    add_item
    ) are both acceptable — pick one and be consistent.
  • Clear descriptions: The description is what the agent reads to decide whether to use the tool. Be specific about what the tool does, what it returns, and any constraints.
  • Minimal required parameters: Only mark parameters as required if the tool truly cannot function without them. Use sensible defaults for optional parameters.
  • Structured input schemas: Use JSON Schema (
    type
    ,
    properties
    ,
    required
    ,
    enum
    ,
    description
    ) so agents know exactly what to pass.
  • Informative return values: Return text or structured content that tells the agent what happened. Include enough context for the agent to decide what to do next.
优秀的WebMCP工具具备以下特质:
  • 面向动作的命名:使用动词-名词格式,如
    add_item
    search_flights
    set_filters
    。短横线分隔(
    add-item
    )或下划线分隔(
    add_item
    )均可——选择一种并保持一致。
  • 清晰的描述:描述是Agent判断是否使用该工具的依据。需明确说明工具的功能、返回内容及任何约束条件。
  • 最少必填参数:仅将工具真正不可或缺的参数标记为必填项。为可选参数设置合理默认值。
  • 结构化输入Schema:使用JSON Schema(
    type
    properties
    required
    enum
    description
    ),让Agent明确知晓需传入的参数格式。
  • 信息丰富的返回值:返回文本或结构化内容,告知Agent操作结果。需包含足够上下文,以便Agent决定下一步操作。

Bad vs. Good Examples

反面与正面示例

Tool naming:
  • data
    — vague, agent can't tell what it does
  • get_cart_contents
    — specific, action-oriented
Descriptions:
  • "Does stuff with the form"
    — agent has no idea what to expect
  • "Submits the contact form with the given name, email, and message. Returns a confirmation ID or validation errors."
    — agent knows inputs, outputs, and failure modes
Parameters:
  • ❌ Requiring
    user_email
    and
    user_location
    on a search tool that doesn't need them
  • ✅ Only requiring
    query
    , with optional
    max_results
    defaulting to 10
工具命名:
  • data
    ——表述模糊,Agent无法判断其功能
  • get_cart_contents
    ——表述具体,面向动作
描述:
  • "Does stuff with the form"
    ——Agent完全无法预期结果
  • "Submits the contact form with the given name, email, and message. Returns a confirmation ID or validation errors."
    ——Agent清楚了解输入、输出及失败场景
参数:
  • ❌ 搜索工具要求传入
    user_email
    user_location
    ,但实际并不需要
  • ✅ 仅要求传入
    query
    ,可选参数
    max_results
    默认值为10

Tool Granularity

工具粒度

Balance between too many fine-grained tools and too few coarse ones:
  • Too fine:
    set_font_size
    ,
    set_font_color
    ,
    set_font_family
    → agent needs many calls for simple tasks
  • Too coarse:
    do_everything(instructions)
    → agent can't predict behavior, errors are vague
  • Right level:
    edit_design(instructions)
    for creative apps, or individual CRUD tools for data apps
When in doubt, start with one tool per user-facing action (each button, form submission, or filter corresponds to a tool).
需在过多细粒度工具与过少粗粒度工具之间找到平衡:
  • 过细
    set_font_size
    set_font_color
    set_font_family
    →Agent完成简单任务需多次调用
  • 过粗
    do_everything(instructions)
    →Agent无法预测行为,错误信息模糊
  • 合适粒度:创意应用使用
    edit_design(instructions)
    ,数据应用使用独立的CRUD工具
拿不定主意时,先为每个用户可见的操作(每个按钮、表单提交或筛选器)对应一个工具。

Phase 3: Implement

阶段3:实现开发

Project Structure

项目结构

WebMCP tools live in your web app's frontend code. A typical organization:
my-app/
├── index.html
├── style.css
├── script.js          # App logic + WebMCP tool registration
For larger apps, separate WebMCP code into its own module:
my-app/
├── index.html
├── style.css
├── script.js          # App logic
├── webmcp.ts          # WebMCP tool definitions and registration
WebMCP工具位于Web应用的前端代码中。典型的组织方式如下:
my-app/
├── index.html
├── style.css
├── script.js          # 应用逻辑 + WebMCP工具注册
对于大型应用,可将WebMCP代码分离到独立模块:
my-app/
├── index.html
├── style.css
├── script.js          # 应用逻辑
├── webmcp.ts          # WebMCP工具定义与注册

Complete Minimal Tool

完整极简工具示例

Here's a complete tool you can copy-paste as a starting point — it includes feature detection, registration, execution with error handling, and an informative return value:
js
window.addEventListener('load', () => {
	if ("modelContext" in navigator) {
		navigator.modelContext.registerTool({
			name: "add_todo",
			description: "Add a new todo item to the list. Returns confirmation with the current item count.",
			inputSchema: {
				type: "object",
				properties: {
					text: { type: "string", description: "The text of the todo item" }
				},
				required: ["text"]
			},
			annotations: {
				readOnlyHint: false,
				idempotentHint: false
			},
			execute: ({ text }) => {
				if (!text.trim()) {
					return "Error: Todo text cannot be empty.";
				}
				addTodo(text);  // Call your existing app function
				renderTodoList();  // Update the UI
				return `Added todo: "${text}". You now have ${getTodoCount()} items.`;
			}
		});
	}
});
以下是一个可直接复制使用的完整工具示例——包含特性检测、注册、带错误处理的执行逻辑及信息丰富的返回值:
js
window.addEventListener('load', () => {
	if ("modelContext" in navigator) {
		navigator.modelContext.registerTool({
			name: "add_todo",
			description: "Add a new todo item to the list. Returns confirmation with the current item count.",
			inputSchema: {
				type: "object",
				properties: {
					text: { type: "string", description: "The text of the todo item" }
				},
				required: ["text"]
			},
			annotations: {
				readOnlyHint: false,
				idempotentHint: false
			},
			execute: ({ text }) => {
				if (!text.trim()) {
					return "Error: Todo text cannot be empty.";
				}
				addTodo(text);  // 调用现有应用函数
				renderTodoList();  // 更新UI
				return `Added todo: "${text}". You now have ${getTodoCount()} items.`;
			}
		});
	}
});

The WebMCP API

WebMCP API

The API lives on
navigator.modelContext
. Always feature-detect before using it, and always do so inside a
window.addEventListener('load', ...)
callback — never at the top level of a script. Browser extensions and runtimes that inject
navigator.modelContext
do so during or after page load; checking too early will always find it missing.
⚠️ HTTP required:
navigator.modelContext
is only available when the page is served over HTTP or HTTPS (e.g.
http://localhost:8080
). It will not be injected on
file://
URLs. Always run a local dev server during development.
js
window.addEventListener('load', () => {
	if ("modelContext" in navigator) {
		// WebMCP is supported — register tools here
	}
});
There are two registration approaches:
Approach 1:
provideContext
(batch registration)
Registers all tools at once. Calling it again replaces all previously registered tools. Good for simple apps or when the full tool set is known upfront.
js
navigator.modelContext.provideContext({
	tools: [
		{
			name: "add-todo",
			description: "Add a new todo item to the list",
			inputSchema: {
				type: "object",
				properties: {
					text: { type: "string", description: "The text of the todo item" }
				},
				required: ["text"]
			},
			execute: ({ text }, agent) => {
				addTodo(text);
				return {
					content: [
						{ type: "text", text: `Added todo: "${text}"` }
					]
				};
			}
		}
	]
});
Approach 2:
registerTool
/
unregisterTool
(incremental)
Add or remove individual tools. Better for SPAs where available tools change based on UI state.
js
navigator.modelContext.registerTool({
	name: "search_flights",
	description: "Search for flights with the given parameters.",
	inputSchema: {
		type: "object",
		properties: {
			origin: {
				type: "string",
				description: "3-letter IATA airport code for origin",
				pattern: "^[A-Z]{3}$"
			},
			destination: {
				type: "string",
				description: "3-letter IATA airport code for destination",
				pattern: "^[A-Z]{3}$"
			}
		},
		required: ["origin", "destination"]
	},
	execute: async ({ origin, destination }) => {
		const results = await searchFlights(origin, destination);
		return `Found ${results.length} flights from ${origin} to ${destination}.`;
	}
});

// Later, when navigating away from search:
navigator.modelContext.unregisterTool("search_flights");
该API位于
navigator.modelContext
对象上。使用前务必先进行特性检测,且必须在
window.addEventListener('load', ...)
回调中执行——绝不能在脚本顶层执行。注入
navigator.modelContext
的浏览器扩展和运行时会在页面加载期间或之后完成注入;过早检测会始终返回未找到。
⚠️ 需HTTP环境
navigator.modelContext
仅在页面通过HTTP或HTTPS提供服务时可用(例如
http://localhost:8080
)。在
file://
协议的URL下无法注入。开发期间请始终运行本地开发服务器。
js
window.addEventListener('load', () => {
	if ("modelContext" in navigator) {
		// WebMCP已支持——在此注册工具
	}
});
有两种注册方式:
方式1:
provideContext
(批量注册)
一次性注册所有工具。再次调用会替换之前注册的所有工具。适用于简单应用或预先知晓完整工具集的场景。
js
navigator.modelContext.provideContext({
	tools: [
		{
			name: "add-todo",
			description: "Add a new todo item to the list",
			inputSchema: {
				type: "object",
				properties: {
					text: { type: "string", description: "The text of the todo item" }
				},
				required: ["text"]
			},
			execute: ({ text }, agent) => {
				addTodo(text);
				return {
					content: [
						{ type: "text", text: `Added todo: "${text}"` }
					]
				};
			}
		}
	]
});
方式2:
registerTool
/
unregisterTool
(增量注册)
添加或移除单个工具。更适用于单页应用,此类应用中可用工具会随UI状态变化。
js
navigator.modelContext.registerTool({
	name: "search_flights",
	description: "Search for flights with the given parameters.",
	inputSchema: {
		type: "object",
		properties: {
			origin: {
				type: "string",
				description: "3-letter IATA airport code for origin",
				pattern: "^[A-Z]{3}$"
			},
			destination: {
				type: "string",
				description: "3-letter IATA airport code for destination",
				pattern: "^[A-Z]{3}$"
			}
		},
		required: ["origin", "destination"]
	},
	execute: async ({ origin, destination }) => {
		const results = await searchFlights(origin, destination);
		return `Found ${results.length} flights from ${origin} to ${destination}.`;
	}
});

// 后续离开搜索页面时:
navigator.modelContext.unregisterTool("search_flights");

Tool Definition Shape

工具定义结构

Each tool object has these fields:
FieldRequiredDescription
name
YesUnique identifier for the tool
description
YesNatural language description of what the tool does
inputSchema
YesJSON Schema object describing the parameters
execute
YesFunction
(params, agent) => result
that implements the tool
outputSchema
NoJSON Schema describing the return value structure
annotations
NoHints like
readOnlyHint
,
destructiveHint
,
idempotentHint
,
openWorldHint
每个工具对象包含以下字段:
字段是否必填描述
name
工具的唯一标识符
description
工具功能的自然语言描述
inputSchema
描述参数的JSON Schema对象
execute
实现工具功能的函数,格式为
(params, agent) => result
outputSchema
描述返回值结构的JSON Schema
annotations
提示信息,如
readOnlyHint
destructiveHint
idempotentHint
openWorldHint

The
execute
Function

execute
函数

The execute function receives two arguments:
  1. params
    : An object with the parameters the agent passed, matching your
    inputSchema
    .
  2. agent
    : An interface for interacting with the agent during execution.
It can be synchronous or async (return a Promise). The return value is sent back to the agent.
Return formats:
js
// Simple text response
execute: ({ query }) => {
	return `Found 5 results for "${query}"`;
}

// Structured content response (MCP-aligned)
execute: ({ name }) => {
	return {
		content: [
			{ type: "text", text: `Item "${name}" created successfully.` }
		]
	};
}

// Return data for the agent to process
execute: () => {
	return JSON.stringify(getAppState());
}
execute函数接收两个参数:
  1. params
    :Agent传入的参数对象,与你定义的
    inputSchema
    匹配。
  2. agent
    :执行期间与Agent交互的接口。
函数可以是同步或异步(返回Promise)。返回值将发送回Agent。
返回格式:
js
// 简单文本响应
execute: ({ query }) => {
	return `Found 5 results for "${query}"`;
}

// 结构化内容响应(与MCP对齐)
execute: ({ name }) => {
	return {
		content: [
			{ type: "text", text: `Item "${name}" created successfully.` }
		]
	};
}

// 返回供Agent处理的数据
execute: () => {
	return JSON.stringify(getAppState());
}

Recommended Return Format

推荐返回格式

✅ Recommended: always include a
success
field and the new device state.
Returning a plain string (e.g.
"Light turned on."
) is valid, but some agents treat an ambiguous response as a potential error. To give the agent unambiguous confirmation, return a JSON-stringified object with:
  • success: true/false
    — explicit boolean indicating whether the action succeeded.
  • message
    — human-readable description of what happened.
  • new_state
    — the updated state of the device(s) affected by the call, so the agent can verify the outcome without a follow-up
    get_*
    call.
  • On failure, include
    error
    instead of
    new_state
    .
js
// ✅ Success — clear confirmation + updated state
execute: ({ light_id, action }) => {
	state.lights[light_id].on = (action === 'on');
	renderLight(light_id);
	return JSON.stringify({
		success: true,
		message: `${light_id} light turned ${action}.`,
		new_state: { light_id, on: state.lights[light_id].on },
	});
}

// ✅ Failure — explicit flag so the agent knows to retry or report
execute: ({ light_id, action }) => {
	if (!VALID_IDS.includes(light_id)) {
		return JSON.stringify({
			success: false,
			error: `Unknown light_id "${light_id}". Valid options: ${VALID_IDS.join(', ')}.`,
		});
	}
	// ...
}
For tools that affect multiple devices at once (e.g. a scene), include the full post-action snapshot in
new_state
so the agent doesn't need a separate status read.
✅ 推荐:始终包含
success
字段和新的设备状态。
返回纯字符串(例如
"Light turned on."
)是有效的,但部分Agent会将模糊响应视为潜在错误。为给Agent明确的确认信息,建议返回JSON字符串化的对象,包含:
  • success: true/false
    —— 明确的布尔值,指示操作是否成功。
  • message
    —— 人类可读的操作结果描述。
  • new_state
    —— 受调用影响的设备的更新状态,以便Agent无需后续调用
    get_*
    接口即可验证结果。
  • 失败时,用**
    error
    **字段替代
    new_state
js
// ✅ 成功——明确的确认信息 + 更新后的状态
execute: ({ light_id, action }) => {
	state.lights[light_id].on = (action === 'on');
	renderLight(light_id);
	return JSON.stringify({
		success: true,
		message: `${light_id} light turned ${action}.`,
		new_state: { light_id, on: state.lights[light_id].on },
	});
}

// ✅ 失败——明确的标志,让Agent知晓需重试或上报错误
execute: ({ light_id, action }) => {
	if (!VALID_IDS.includes(light_id)) {
		return JSON.stringify({
			success: false,
			error: `Unknown light_id "${light_id}". Valid options: ${VALID_IDS.join(', ')}.`,
		});
	}
	// ...
}
对于影响多个设备的工具(例如场景控制工具),请在
new_state
中包含操作后的完整快照,这样Agent无需单独调用状态读取接口。

User Interaction During Tool Execution

工具执行期间的用户交互

For actions that need user confirmation, use
agent.requestUserInteraction()
:
js
execute: async ({ product_id }, agent) => {
	const confirmed = await agent.requestUserInteraction(async () => {
		return new Promise((resolve) => {
			const ok = confirm(`Purchase product ${product_id}?`);
			resolve(ok);
		});
	});

	if (!confirmed) {
		throw new Error("Purchase cancelled by user.");
	}

	executePurchase(product_id);
	return `Product ${product_id} purchased.`;
}
对于需要用户确认的操作,使用
agent.requestUserInteraction()
js
execute: async ({ product_id }, agent) => {
	const confirmed = await agent.requestUserInteraction(async () => {
		return new Promise((resolve) => {
			const ok = confirm(`Purchase product ${product_id}?`);
			resolve(ok);
		});
	});

	if (!confirmed) {
		throw new Error("Purchase cancelled by user.");
	}

	executePurchase(product_id);
	return `Product ${product_id} purchased.`;
}

Annotations

注释信息

Annotations help agents understand tool behavior without reading the implementation:
js
annotations: {
	readOnlyHint: true,    // Tool only reads data, no side effects
	destructiveHint: false, // Tool doesn't delete or irreversibly modify data
	idempotentHint: true,  // Calling multiple times with same args has same effect
	openWorldHint: false   // Tool doesn't interact with external systems
}
⚠️ Annotation values must be booleans (
true
/
false
), not strings (
"true"
/
"false"
). Passing strings will cause a runtime validation error (
expected: "boolean"
,
code: "invalid_type"
).
注释信息可帮助Agent无需阅读实现代码即可理解工具行为:
js
annotations: {
	readOnlyHint: true,    // 工具仅读取数据,无副作用
	destructiveHint: false, // 工具不会删除或不可逆地修改数据
	idempotentHint: true,  // 使用相同参数多次调用,结果一致
	openWorldHint: false   // 工具不与外部系统交互
}
⚠️ 注释值必须为布尔值
true
/
false
),而非字符串(
"true"
/
"false"
)。传入字符串会导致运行时验证错误(
expected: "boolean"
,
code: "invalid_type"
)。

Advanced Patterns

高级模式

For advanced implementation details, please see Advanced Patterns. Topics include:
  • Choosing a UI Synchronization pattern (Direct DOM, Custom Events, Framework State) — with a decision guide
  • Dynamic Tool Registration for SPAs
  • Error Handling Patterns (DOM not found, network failure, invalid state, timeout)
  • Useful tips (Web Workers,
    toolactivated
    event, returning
    outputSchema
    )
如需了解高级实现细节,请查看高级模式。涵盖主题包括:
  • UI同步模式选择(直接DOM操作、自定义事件、框架状态)——含决策指南
  • 单页应用的动态工具注册
  • 错误处理模式(未找到DOM、网络故障、无效状态、超时)
  • 实用技巧(Web Workers、
    toolactivated
    事件、返回
    outputSchema

Phase 4: Testing and Validation

阶段4:测试与验证

Manual Testing Checklist

手动测试清单

Verify these before moving to automated evals:
  • Feature detection: App works normally when
    navigator.modelContext
    is undefined (browsers without WebMCP support)
  • HTTP server: App is served over
    http://
    or
    https://
    , not
    file://
  • Load event: Tool registration is deferred to
    window.addEventListener('load', ...)
  • Annotation types: All annotation values are booleans (
    true
    /
    false
    ), not strings
  • Tool schema validation:
    inputSchema
    accurately describes what
    execute
    expects — mismatches cause agent errors
  • UI sync: After each tool call, the UI visually reflects the change
  • Return values: Every
    execute
    returns a JSON object with
    success: true/false
    , a
    message
    , and
    new_state
    (or
    error
    ) so the agent gets unambiguous confirmation — avoid returning plain strings that agents may misinterpret as errors
  • Error handling: Tools return
    { success: false, error: "..." }
    for invalid inputs, not unhandled exceptions or bare error strings
  • Edge cases: Test with missing optional parameters, empty strings, boundary values
  • Optional parameter defaults: Call tools with only required parameters — defaults should apply correctly
  • Destructive actions: Confirm
    requestUserInteraction()
    is used for purchases, deletions, etc.
  • Multiple calls: Calling the same tool twice in a row doesn't break state
在进行自动化评估前,先验证以下内容:
  • 特性检测:当
    navigator.modelContext
    未定义时(不支持WebMCP的浏览器),应用仍能正常运行
  • HTTP服务器:应用通过
    http://
    https://
    提供服务,而非
    file://
  • 加载事件:工具注册延迟至
    window.addEventListener('load', ...)
    回调中执行
  • 注释类型:所有注释值均为布尔值(
    true
    /
    false
    ),而非字符串
  • 工具Schema验证
    inputSchema
    准确描述
    execute
    函数所需参数——不匹配会导致Agent错误
  • UI同步:每次工具调用后,UI可直观反映变化
  • 返回值:每个
    execute
    函数均返回包含
    success: true/false
    message
    new_state
    (或
    error
    )的JSON对象,为Agent提供明确的确认信息——避免返回可能被Agent误判为错误的纯字符串
  • 错误处理:工具对无效输入返回
    { success: false, error: "..." }
    ,而非未处理的异常或纯错误字符串
  • 边界情况:测试缺失可选参数、空字符串、边界值等场景
  • 可选参数默认值:仅传入必填参数调用工具——默认值应正确生效
  • 破坏性操作:购买、删除等操作已使用
    requestUserInteraction()
    确认
  • 多次调用:连续两次调用同一工具不会破坏应用状态

Automated Evaluation

自动化评估

Use the WebMCP Evals CLI to test tool selection against AI agents. Write eval cases with natural language prompts and expected tool calls, then run them against your tool schema. For detailed setup and usage, see Testing WebMCP Tools.

使用WebMCP Evals CLI测试AI Agent的工具选择能力。编写包含自然语言提示和预期工具调用的评估用例,然后针对你的工具Schema运行测试。如需详细设置和使用说明,请查看测试WebMCP工具

Reference

参考文档

Building

开发相关

  • Advanced WebMCP Patterns — UI synchronization, SPA routing, error handling, patterns & tips
  • Simple vanilla JS examples — Pizza maker, restaurant booking, complete end-to-end example, accessibility patterns
  • React/TypeScript example — Flight search app with dynamic tool registration, complete component example
  • WebMCP高级模式——UI同步、单页应用路由、错误处理、模式与技巧
  • 原生JS简单示例——披萨制作器、餐厅预订、完整端到端示例、可访问性模式
  • React/TypeScript示例——带动态工具注册的航班搜索应用、完整组件示例

Quality

质量保障

  • Testing guide — Manual checklist and automated evaluation with the Evals CLI
  • Security & privacy guide — Prompt injection, output injection walkthrough, over-parameterization, and a pre-ship checklist
  • 测试指南——手动测试清单及使用Evals CLI进行自动化评估
  • 安全与隐私指南——提示注入、输出注入实战、参数过度暴露、发布前检查清单

Advanced

高级主题

  • Service worker patterns — Background tool execution, session management, discovery, and routing
  • Service Worker模式——后台工具执行、会话管理、发现与路由