用 Playwright 和 Gemini 构建最小 WebMCP Agent
WebMCP 让网页可以向 AI Agent 暴露可调用的工具。这个想法听起来很直接,直到你想用 Chrome 扩展之外更强的模型来测试 WebMCP 工具。
之前我构建了一个小型解谜游戏,它暴露了 WebMCP 工具。我用 Model Context Tool Inspector 做了测试和调试——这个工具对快速实验很好用,但局限性是它只提供了少量轻量 Gemini 模型。我想用更强的模型来测试同样的 WebMCP 工具。
我的第一个想法是再写一个 Chrome 扩展,但这有点杀鸡用牛刀。WebMCP 工具需要一个真正的浏览器上下文:浏览器必须直接打开页面、发现工具并在页面内执行它们。所以我没有构建另一个扩展,而是寻找可以打开 Chrome 并控制页面的东西。
这就是 Playwright 的用武之地。
本文将展示如何创建一个简单的 Agent,通过 Playwright 将 Gemini API 与 WebMCP 连接起来:Gemini 请求调用工具,Playwright 在真实的 Chrome 浏览器中执行匹配的 WebMCP 工具。
前置条件
你需要以下环境:
- Node.js 20+
- Google Chrome
- Gemini API Key
准备项目
首先,在 Chrome 中启用 WebMCP。WebMCP 仍处于实验阶段,需要通过 Chrome 标志启用:
打开 Chrome 并访问 chrome://flags/#enable-webmcp-testing
将标志设置为 Enabled
重新启动 Chrome 以应用更改
然后创建 Node.js 项目:
mkdir custom-agent
cd custom-agent
npm init -y
安装 Playwright 及相关依赖:
npm install -D playwright tsx dotenv typescript @types/node
安装 Gemini SDK:
npm install @google/genai
在 package.json 中添加脚本:
{
"scripts": {
"agent": "tsx agent.ts"
}
}
检查 modelContext 是否存在
首先创建 agent.ts,检查浏览器页面中 modelContext 是否可用:
import { chromium } from "playwright";
const gameUrl = process.argv[2] ?? "http://localhost:5173";
async function main() {
const context = await chromium.launchPersistentContext(
"./.chrome-agent-profile",
{
channel: "chrome",
headless: false,
args: ["--enable-experimental-web-platform-features"],
},
);
const page = await context.newPage();
await page.goto(gameUrl, { waitUntil: "networkidle" });
const result = await page.evaluate(() => ({
userAgent: navigator.userAgent,
hasNavigatorModelContext: "modelContext" in navigator,
hasDocumentModelContext: "modelContext" in document,
}));
console.log(result);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
这段代码打开 Chrome、导航到游戏页面,然后检查 navigator 或 document 上是否存在 modelContext。
注意:我没有使用 Playwright 自带的 Chromium,而是通过 launchPersistentContext 配合 channel: "chrome" 打开系统上真实安装的 Chrome。这是因为 WebMCP 仍处于实验阶段,隔离的 Chromium 浏览器可能无法正确发现 WebMCP 工具。
读取 WebMCP 工具清单
接下来读取页面暴露的工具列表:
const result = await page.evaluate(async () => {
const modelContext = navigator.modelContext;
if (!modelContext) {
return { hasModelContext: false, tools: [] };
}
const tools = await modelContext.getTools();
return {
hasModelContext: true,
tools: tools.map((tool) => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
origin: tool.origin,
})),
};
});
这段代码返回页面暴露的所有工具信息,包括名称、描述、输入模式和来源。
执行 WebMCP 工具
为了能够按名称执行任意工具,创建一个可复用的辅助函数:
import type { Page } from "playwright";
export async function executeWebMcpTool(
page: Page,
toolName: string,
args: unknown,
): Promise<T> {
return await page.evaluate(
async ({ toolName, args }) => {
const modelContext =
(document as any).modelContext ?? (navigator as any).modelContext;
if (!modelContext) {
throw new Error("Model Context API is not available");
}
const tools = await modelContext.getTools();
const tool = tools.find((tool: any) => tool.name === toolName);
if (!tool) {
throw new Error(`Tool not found: ${toolName}`);
}
const result = await modelContext.executeTool(
tool, JSON.stringify(args),
);
return result;
},
{ toolName, args },
);
}
这个辅助函数接收 Playwright Page、工具名称和参数,在浏览器页面内执行对应 WebMCP 工具并返回结果。
创建最小 Agent 概念验证
现在将 Gemini 模型与 WebMCP 工具执行连接起来。首先创建 genai.service.ts:
import "dotenv/config";
import {
GoogleGenAI, type Content,
type GenerateContentConfig, type GenerateContentResponse,
} from "@google/genai";
export class GenaiService {
private readonly ai: GoogleGenAI;
private readonly model: string;
constructor(model: string = "gemini-2.5-flash-lite") {
this.model = model;
const apiKey = process.env.GEMINI_API_KEY;
if (!apiKey) {
throw new Error("Missing GEMINI_API_KEY in .env");
}
this.ai = new GoogleGenAI({ apiKey });
}
public async generateContentAsync(
request: GenerateRequest,
): Promise<GenerateContentResponse> {
return await this.ai.models.generateContent({
model: this.model,
contents: request.contents,
config: request.config,
});
}
}
然后创建 .env 文件:
GEMINI_API_KEY=your-api-key
最后在 agent.ts 中将所有组件组合在一起:
const response = await aiService.generateContentAsync({
contents,
config: {
tools,
toolConfig: {
functionCallingConfig: {
mode: FunctionCallingConfigMode.ANY,
allowedFunctionNames: ["getGameState"],
},
},
},
});
const functionCall = response.functionCalls?.[0];
if (!functionCall?.name) {
throw new Error("Gemini did not return a tool call");
}
const gameState = await executeWebMcpTool(
page, functionCall.name, functionCall.args ?? {},
);
console.log("Tool result:", gameState);
整个流程很简单:脚本打开 Chrome 并导航到游戏页面 → 将工具定义发送给 Gemini → Gemini 返回函数调用 → 验证函数名 → 通过 WebMCP 在浏览器中执行该工具 → 打印结果。
总结
本文展示了如何用 Playwright 为 WebMCP 创建自定义概念验证 Agent。我们检查了 modelContext 是否可用,发现了暴露的工具,执行了其中一个工具,并最终用 Gemini 函数调用连接了完整流程。
WebMCP 仍处于实验阶段,Model Context Tool Inspector 对调试很友好。但它提供的模型在某些类型 Web 应用中可能不够用。希望本文的方法能帮助大家用更强的模型测试 WebMCP 工具,而无需再创建一个 Chrome 扩展。
源码地址:概念验证 Agent | 完整 Agent 仓库
原文出处:https://dev.to/gramli/build-a-minimal-webmcp-agent-with-playwright-and-gemini-24fh