npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@webmcp-stack/codegen

v0.10.1

Published

Generate safe, typed, human-reviewed WebMCP tools from the API contracts you already have (OpenAPI, tRPC, Zod).

Readme


Hand-writing a WebMCP tool for every action is a chore, and the descriptions drift from the API they describe. If you already maintain an OpenAPI spec or validation schemas, you already have the source of truth.

@webmcp-stack/codegen turns that source into WebMCP tools as real TypeScript files in your repo. It writes the safe defaults, withholds anything risky until you enable it, scaffolds a skill file so your own coding agent knows the rules, and ships a verify command you can gate in CI.

Part of webmcp-stack, the open-source developer stack for WebMCP.

Quick start

No install, no config for the first run:

npx @webmcp-stack/codegen generate

One run finds your OpenAPI spec (monorepos included), finds the package that is your web app, and:

  • writes one .webmcp.ts file per endpoint
  • gives read tools working implementations that call your API with the signed-in user's session
  • withholds writes and destructive tools: the working code is generated, but the tool is not registered until you enable it
  • skips webhooks, flags auth and admin endpoints
  • wires registration into your app with two additive lines
  • scaffolds a skill file for your coding agent, and a journey factory if you want one

Preview everything without writing:

npx @webmcp-stack/codegen generate --dry-run

Measure the surface before you ship, and gate it in CI:

npx @webmcp-stack/codegen verify

Browse and test the tools locally:

npx @webmcp-stack/codegen dev

Then open your app in Chrome with chrome://flags/#enable-webmcp-testing enabled, and let an agent use a tool. Other browsers work with the WebMCP polyfill.

What you get

A small, intent-level surface. Not every endpoint should be a tool. Reads register so you can see the surface; writes and destructive tools stay withheld until you turn them on one at a time.

Handshake grouping. When a begin/end pair (request an upload, then complete it) is really one action split across two calls, the generator merges them into a single withheld tool and threads the first response into the second by exact name. A pair it cannot thread is skipped with a note, never guessed.

Journeys. For a goal that takes several calls and ends in one confirmed write, you write a small file in src/webmcp/journeys/ and the generator scaffolds the rest: a shared draft, one tool per step, and a submit gate a human confirms. See Journeys.

A skill file for your coding agent. Every run writes .agents/skills/webmcp-tools/SKILL.md, where Claude Code, AGENTS.md, and the generic standard already look. Your agent follows the same naming, description, and safety rules the generator uses.

Safety as part of generation. Every endpoint is classified read, write, or destructive, corrected when the name disagrees. The audit runs inside generate: it names PII in outputs, descriptions that try to instruct the agent, and auth or admin endpoints. Errors block generation and set an exit code for CI; warnings report and continue.

Descriptions you can trust. Constraints become sentences ("A number from 30 to 600."), every description says what the tool returns, and free-text outputs are marked as untrusted. Your own text is kept in full. Chrome's 500 and 150 character budgets are treated as guidance, so verify warns on an overrun instead of shortening your words to pass a counter.

Regeneration that never clobbers your code. The API contract lives above a marker line and regenerates freely; your execute() body lives below it and is never touched. Hand-edited generated regions produce a .new file to merge, never a silent overwrite.

Where this fits

This tool generates from a contract, not from a scan of your codebase. That is a deliberate choice, not a hidden limitation:

  • It needs a source you maintain. An OpenAPI spec, or the validation schemas your app already uses (zod, valibot, arktype, TypeBox). If neither exists yet, there is nothing good to generate from, and writing that source is the work to do first.
  • The source has to be good. A tool's description is part of the prompt a model reasons over. A vague or stale contract produces vague or stale tools; what an agent can do is bounded by what your contract actually says.
  • One thing done well. A generator that claims to work on any codebase, by guessing intent from source code, tends to work well nowhere. This one asks for a contract and rewards you for keeping it current.

If you have an OpenAPI spec or maintained schemas, you are exactly who this is for. If you do not, the schema source lets you declare tools from schemas you write by hand in the meantime.

A generated tool

One file per endpoint, like create-trip.webmcp.ts:

// --- webmcp-codegen: generated. Do not edit this region. ---
export const createTripTool = {
  name: "create-trip",
  title: "Create Trip",
  description: "Create a new trip. Returns the trip.",
  inputSchema: createTripInputSchema,
  annotations: {
    readOnlyHint: false,
    untrustedContentHint: true,
    consequentialHint: false,
  },
};

// Journeys and your own code compose this raw caller; executeCreateTrip wraps it.
export async function fetchCreateTrip(input: CreateTripInput, signal?: AbortSignal) {
  const data = await callApi("/v1/trips", { method: "POST", body: { ... }, signal });
  return data;
}

// Withheld, so the registration is generated but commented out, confirmation included:
//   const confirmed = await requestUserConfirmation("Allow the agent to: Create a new trip...");
// --- webmcp-codegen: end generated. Your code below survives regeneration. ---

CLI

| Command | What it does | |---|---| | webmcp-codegen generate | Generate and update tools, wire registration (the audit runs by default) | | generate --dry-run | Preview everything, write nothing | | generate --watch | Re-generate when source files change | | generate --force | Write files even when the audit reports errors | | generate --spec PATH / --out DIR | Overrides without a config file | | webmcp-codegen verify | Score the surface against the standard; exits 1 on errors | | verify --url URL | Also check a deployed page serves an origin trial token | | webmcp-codegen dev | Open the tools dashboard (--port N to change the port) | | webmcp-codegen init | Write codegen.config.mjs for full control (needs the package installed) |

Config

Structure lives in codegen.config.mjs (code). Remembered choices and per-tool overrides live in .webmcp-codegen.json (data, safe with npx, meant to be committed).

// codegen.config.mjs
import { defineConfig } from "@webmcp-stack/codegen";
import { openapi } from "@webmcp-stack/codegen/sources";
import { tools } from "@webmcp-stack/codegen/outputs";

export default defineConfig({
  sources: [openapi({ spec: "./openapi.yaml" })],
  outputs: [tools({ outDir: "./src/webmcp" })],
  safety: {
    piiFields: ["internalId"], // extend the built-in PII heuristics
    exclude: ["internal"],     // skip tools by name or route substring
  },
});

No OpenAPI spec? Declare tools from the schemas you already use, and a schema entry can also refine an endpoint from your spec:

// import { schema } from "@webmcp-stack/codegen/sources";
// import { CreateTripInput } from "./src/schemas";

sources: [
  openapi({ spec: "./openapi.yaml" }),
  schema({
    tools: [{ name: "create-trip", schema: CreateTripInput, operation: "createTrip" }],
  }),
],

Annotating a literal <form> instead? The form output wires WebMCP's declarative attributes onto it, so an agent fills the controls a person can see.

Requirements

  • Node.js 20 or newer
  • To use the generated tools in a browser: enable chrome://flags/#enable-webmcp-testing for local development (Chrome 149+, Edge 150+). Production pages join the WebMCP origin trial, or use the polyfill.

License

MIT