webmcp-gen
v1.2.0
Published
CLI tool that generates WebMCP tool definitions from TypeScript interfaces. Built with AI assistance.
Maintainers
Readme
webmcp-gen

CLI tool that generates WebMCP tool definitions from TypeScript interfaces.
WebMCP is the browser-native API (navigator.modelContext) that lets web pages expose structured tools to AI agents. It shipped as a Chrome 149 origin trial in June 2026. This tool reads your TypeScript interfaces and produces spec-compliant JSON tool definitions plus ready-to-use handler stubs.
Disclaimer: This project is not affiliated with or endorsed by Google or the W3C.
Built with AI assistance.
Install
npm install -g webmcp-genOr use without installing:
npx webmcp-gen --api myapp.tsQuick start
1. Write your API as TypeScript interfaces:
// api.ts
/** Search products by keyword. */
interface SearchProducts {
/** The search query string. */
query: string;
/** Filter by category. */
category?: "electronics" | "clothing" | "home";
/** Max results (1-100). */
limit?: number;
}
/** Add an item to the shopping cart. */
interface AddToCart {
/** Product identifier. */
productId: string;
/** Quantity to add. */
quantity: number;
}2. Generate WebMCP definitions:
webmcp-gen --api api.ts3. Output (in webmcp-out/):
webmcp-out/
searchProducts.webmcp.json # JSON tool definition
searchProducts.handler.ts # TypeScript handler stub
addToCart.webmcp.json
addToCart.handler.tsThe .webmcp.json files contain the tool definition ready for navigator.modelContext.registerTool(). The .handler.ts files contain the full registration call with a stub execute callback for you to implement.
Usage
Generate from TypeScript
# Default output to ./webmcp-out/
webmcp-gen --api myapp.ts
# Custom output directory
webmcp-gen --api myapp.ts -o generated/
# Single combined file instead of per-tool files
webmcp-gen --api myapp.ts --combined
# Validate only (no files written)
webmcp-gen --api myapp.ts --validateExample templates
# List available templates
webmcp-gen --list-templates
# Emit a template to the current directory
webmcp-gen --template crud-api
# Then generate from it
webmcp-gen --api crud-api.tsAvailable templates:
| Template | Description |
|---|---|
| crud-api | CRUD operations (create, read, update, delete) |
| search | Search/filter with pagination and sorting |
| form-handler | Form submissions (contact, booking) |
| data-transformer | Data conversion and formatting tools |
How it works
- Parse -- Uses ts-morph to read TypeScript interfaces and type aliases from your source file.
- Convert -- Maps TypeScript types to JSON Schema:
string->"string",number->"number", union literals ->enum, arrays ->{ type: "array", items: ... }, nested objects -> nested schemas. - Annotate -- Pulls descriptions from JSDoc comments. Detects
@readonlytags and setsannotations.readOnlyHint. - Validate -- Checks every generated definition against the WebMCP spec: valid name, non-empty description, valid JSON Schema, no orphaned
requiredentries. - Output -- Writes one
.webmcp.json+ one.handler.tsper tool (or a combined pair with--combined).
Generated output format
JSON definition (*.webmcp.json)
{
"name": "searchProducts",
"description": "Search products by keyword.",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search query string."
},
"category": {
"type": "string",
"enum": ["electronics", "clothing", "home"]
},
"limit": {
"type": "number"
}
},
"required": ["query"]
},
"annotations": {
"readOnlyHint": true
}
}Handler stub (*.handler.ts)
// Chrome 149: navigator.modelContext — Chrome 150+: document.modelContext
const ctx = "modelContext" in document ? document.modelContext : navigator.modelContext;
ctx.registerTool({
name: "searchProducts",
description: "Search products by keyword.",
inputSchema: { /* ... */ },
annotations: { readOnlyHint: true },
execute: async (input: SearchProductsInput): Promise<string> => {
// TODO: Implement searchProducts logic here
throw new Error("Not implemented: searchProducts");
},
});Note:
navigator.modelContextis deprecated in Chrome 150. Generated stubs include a compatibility shim that works across Chrome 149–156+.
TypeScript mapping reference
| TypeScript | JSON Schema |
|---|---|
| string | { "type": "string" } |
| number | { "type": "number" } |
| boolean | { "type": "boolean" } |
| "a" \| "b" \| "c" | { "type": "string", "enum": ["a", "b", "c"] } |
| string[] | { "type": "array", "items": { "type": "string" } } |
| { nested: string } | { "type": "object", "properties": { "nested": ... } } |
| prop?: type | Excluded from required array |
| /** JSDoc */ | "description" field |
| @readonly tag | annotations.readOnlyHint = true |
| @untrusted tag | annotations.untrustedContentHint = true |
Security
WebMCP allows AI agents to execute tools that affect live web applications. Google advises developers to follow these practices — webmcp-gen bakes them into the generated handler stubs automatically:
- Human-in-the-loop for mutating actions. Tools that aren't marked
@readonlyget arequestUserInteraction()reminder in their handler stub. Use this to confirm sensitive operations (purchases, deletions, account changes) before executing. - Input sanitisation. Tools accepting freeform string inputs get a sanitisation reminder. WebMCP tool data may contain indirect prompt injection from contaminated tool responses or malicious manifests — validate and escape all inputs.
- Read-only annotations. Mark query/lookup interfaces with
@readonlyin JSDoc. The generator setsannotations.readOnlyHint = true, signalling to agents that the tool has no side effects.
See Chrome's WebMCP security guidance for full details.
Programmatic API
import { parseTypeScriptFile, generate, validateToolDefinition } from "webmcp-gen";
// Parse a file
const result = parseTypeScriptFile("./api.ts");
console.log(result.tools);
// Full pipeline
const output = generate({
inputFile: "./api.ts",
outDir: "./webmcp-out",
});
// Validate a definition
const validation = validateToolDefinition({
name: "myTool",
description: "Does something useful.",
inputSchema: {
type: "object",
properties: { id: { type: "string" } },
required: ["id"],
},
});npm package note
The primary package name is webmcp-gen. The fallback name untangled-webmcp is reserved on npm as an alternative if needed.
Development
git clone <repo-url>
cd webmcp-gen
npm install
npm run build
npm testLicense
MIT
