Make a website usable by browser agents — with tools wired to the code you already have, not to the shape of your pages.
WebMCP lets a page hand a browser agent
typed tools through document.modelContext
, so the agent acts through your own logic instead of guessing at your DOM. This repository is a coding-agent plugin that audits what your site could expose, writes those tools against real seams in your codebase, proves each one works in a real browser, and publishes the manifests that let agents find them.
MIT end to end. No vendor SDK. No telemetry — the runtime makes no network request other than the ones your own tools declare, and a test fails the build if that stops being true.
Claude Code
/plugin marketplace add glippy-dev/glippy-webmcp
/plugin install glippy-webmcp@glippy-dev
Codex
codex plugin marketplace add glippy-dev/glippy-webmcp
codex plugin add glippy-webmcp
Then, in your own project, ask your agent to audit the site's agent readiness.
Four skills, one arc:
| Skill | What it does |
|---|---|
auditing-agent-readiness |
|
| Read-only. Produces a coverage table of user intents against the tools that exist — including the intents that are not worth building. Writes nothing at all. | |
implementing-webmcp-tools |
|
| Generates tools behind a hard human approval gate, wiring each to the highest available seam. | |
verifying-webmcp-tools |
|
| Executes every tool against the real site in a real browser and marks it verified, failed, or could-not-verify. Failed never ships. | |
publishing-agent-manifests |
|
| Emits the four artifacts that let agents discover your tools even where WebMCP is unsupported. |
Inventory a codebase first and you get forty candidate tools, on a page where Chrome's own guidance says an agent starts choosing worse above about twenty. Supply-first auditing is how a site ends up keyword-stuffed with tools nobody calls.
So the audit establishes what people actually try to do on the site, then inventories the
seams, and matches only at the end. The row it exists to be able to print is
SKIP — no demand
.
Each tool takes the highest rung available, because the rung decides whether it still works after the next redesign:
An exported client function— already typed and exercised by your UI.** An HTTP route the client already calls**— stable across restyles, and if the route validates its body, your input schema was written by someone who knew the answer.A form— including the declarative target, marked experimental because the spec section describing it says, verbatim,*"This section is entirely a TODO."*Recorded DOM steps— works on anything, breaks on the next redesign.
WebMCP has no consent primitive. requestUserInteraction()
does not exist in the spec repository at HEAD, despite Chrome's documentation referring to it. So nothing in the platform stops a browser agent from calling a tool that charges a card.
This repository enforces it instead, as an error rather than a convention: an irreversible action must be gated by a confirmation in handoff mode, or end at a terminal navigation that returns control to your own UI. A warning sentence in a tool description is not a gate.
Actions are classified by effect, not by HTTP verb — a GET
that starts a checkout
session is a write — and readOnlyHint
is derived from the step graph rather than trusted from the author, so a tool that writes cannot describe itself as safe.
| Package | |
|---|---|
@glippy/webmcp-flow |
@glippy/webmcp
plugin/
The expression resolver is a path walker, not an evaluator: no eval
, no new Function
.
A flow document is fetched over the network and inlined into your page, so anything that
could execute arbitrary text would be a remote-execution primitive aimed at your visitors.
It also means the runtime works under script-src 'self'
with no unsafe-eval
.
The surface is document.modelContext
— a partial interface Document
. The string
navigator
appears zero times in the specification at HEAD; navigator.modelContext
is a 2025 alias that survives only as a deprecated fallback in polyfills. Code written against it silently finds nothing.
Tool names are 1–128 characters of [A-Za-z0-9_.-]
— that is normative, and violating it
throws InvalidStateError
. The ~30-character figure that circulates is Chrome ergonomics guidance, so this repository treats it as a warning and never as an error.
For local development: chrome://flags/#enable-webmcp-testing
.
pnpm install
pnpm test # packages + the plugin hook
pnpm typecheck
pnpm lint
MIT.