Test your WebMCP tools without a flagged Chrome or a live model. It installs a mock navigator.modelContext, captures the tools your page registers, and gives you a driver to list, validate-args, invoke, and snapshot the toolset — so tools become plain unit tests.
Works with any runner (Vitest, Jest, Playwright, Node) in any DOM-ish environment.
npm install -D @mcptrail/webmcp-testingimport { installModelContext } from "@mcptrail/webmcp-testing";
test("book_hotel books a room", async () => {
const mcp = installModelContext(); // mocks navigator.modelContext
renderMyApp(); // your code calls navigator.modelContext.registerTool(...)
expect(mcp.has("book_hotel")).toBe(true);
const result = await mcp.call("book_hotel", { hotelId: "h1", guests: 2 });
expect(result).toContain("Confirmation");
expect(document.querySelector("#bookings")).toHaveTextContent("h1");
mcp.uninstall();
});const mcp = installModelContext(options);
mcp.tools(); // ToolDescriptor[] (name, description, inputSchema, annotations, readOnly)
mcp.tool(name); // one descriptor
mcp.has(name); // boolean
await mcp.call(name, args); // run execute(args), await, return the result
mcp.validate(name, args); // { valid, errors[] } against the tool's inputSchema
mcp.assertValid(name, args); // throw if invalid
mcp.snapshot(); // { tools[], hash } — serializable + a stable hash for drift assertions
mcp.reset(); // clear the registry
mcp.uninstall(); // restore the previous modelContext
mcp.onRegister(cb); // (tool) => void
mcp.onCall(cb); // (name, args, result) => void| Option | Default | Notes |
|---|---|---|
strict |
false |
call() validates args against the schema and rejects on error |
target |
navigator |
object to receive .modelContext (created on globalThis if absent) |
alsoDocument |
true |
also set document.modelContext |
validate / assertValid / strict check args against a common JSON-Schema subset — type, required, enum, minimum/maximum, minLength/maxLength, nested objects and arrays. Catches "the model sent the wrong shape" in a test instead of production.
import { validateArgs } from "@mcptrail/webmcp-testing";
validateArgs(schema, args); // { valid, errors: [{ path, message }] }snapshot() returns a sorted, serializable view of the toolset plus a stable hash — pair it with toMatchSnapshot(), or assert the hash is unchanged to catch an unexpected change to what your page exposes to agents.
npm install
npm run typecheck
npm test # Vitest + jsdom
npm run build # tsup → dist (ESM + CJS + d.ts)MIT © Zied Guetari