WebMCP Kit — implement
SkillWeb & browsingAdd WebMCP tools to a website codebase so browser agents can act through the site's own logic instead of scraping the page. Use when asked to make a site agent-ready, add WebMCP or document.modelContext tools, or implement site tools with @nekuda/webmcp-sdk.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the WebMCP Kit — implement skill
What this skill tells your AI
The instructions your AI receives, as published by nekuda-ai/webmcp-kit in plugin/skills/implement/SKILL.md and read by ahel’s review.
Mission
- WebMCP hands a browser agent typed tools (via the
@nekuda/webmcp-sdkSDK) so it answers from the site's own content and acts through the site's own logic. User and agent share the visible page — every tool produces a visible effect. - Tools answer "what will a visitor ask, and ask for, here?" — journeys, never REST-endpoint wrappers.
- In every human-facing run, the plan you present in Phase D is approved by the developer before any file is written. That gate is the product, not a formality.
Hard rules
- Source analysis and code stay local. Never send customer code, routes, or schemas to an external service or to an unauthenticated tool/API. The tool-selection rubric is this skill's text — there is no hosted scanner. The optional post-build Connect flow sends only the CLI's structured project/account request described in
references/connect.md; it is separate from the SDK's documented default-on anonymous observations, which are independent of Connect. - Client-reachable wiring only.
executemay use the app's own client data layer, same-origin routes, or client-safe actions — never server-only imports, secrets, third-party endpoints, or DOM-scraping when a data path exists. - Flag, don't fake. A journey with no safe client path is listed as needs developer wiring — never invented data or a dead call. A guidance-only stub does not "cover" a must-have.
- Irreversible/cost-bearing writes need a boundary. A payment, cancellation, or delete must not complete in one agent call. The generated tool stops at a reversible handoff — creates the repo-native pending state (checkout session, pending order, prepared cancellation) and hands the final step to the app's own payment/confirm UI, or uses a prepare→confirm two-call shape. A consequence sentence in the description is not a boundary.
- Authorization is the server's job. Registration gating on auth/role is UX, not security. Only wrap a privileged mutation whose route independently enforces authn/authz server-side; an endpoint that trusts a hidden client button is needs developer wiring, not a tool.
- No changes or Connect before approval. No branch, file, dependency, or Connect attempt until the developer approves the plan, except the tool-generation workflow in explicit
--non-interactivemode; that exception permits the branch, files, and dependencies needed for generation but never Connect, which non-interactive mode skips. This skill reads with Read/Grep/Glob during A–C — plus one read-only exception: the Phase-F baseline capture (the repo's own typecheck/build,references/verify.md) may run as a background task before approval, because it writes nothing to the tree; after approval it requests the write, package-manager, and browser permissions it needs through the normal permission prompts — no mutation is pre-authorized. Interactive Connect is a separate, optional post-build decision (references/connect.md). - SDK only. Generated code imports
defineTool/registerToolsfrom the SDK under its resolved name (the installed package's declared name —references/sdk.md); never the rawmodelContextsurface, never a bundled polyfill/shadow. The SDK pins the spec, resolves whichever surface the browser exposes, and no-ops when unsupported.
Session flow (A–F)
A — Understand the repo (cheap-first). Stack ID from manifests (package.json, composer.json, …): framework, rendering mode (SPA/SSR/MPA/static), router, language, package manager, and whether a JS bundler/dependency install even exists (a PHP/static MPA may have none — see references/codegen.md). Read high-signal sources before app code: README, openapi.yml/swagger, route manifests (app/, pages/, routes files), sitemap, nav, homepage CTAs. Map the visitor surface — routes→pages, forms, data-layer calls, auth boundaries — recording for each: file, what it does, client-reachable or server-only. Inventory any existing @nekuda/webmcp-sdk usage — including its legacy aliases @agentlane/webmcp and @nekuda/webmcp, the same SDK (defineTool names and stableKeys) so a re-run preserves identity instead of churning it. No stack is privileged (Next.js is not pre-decided); read deeper only where a candidate tool's wiring stays ambiguous. These sweeps are independent of each other: issue their Reads/Greps as one parallel batch, never one file per turn, and where the host supports parallel subagents, fan out the route map, the data-layer/auth survey, and the existing-SDK inventory and merge the results — serial reading is this phase's dominant cost on a large repo.
B — Select journeys/tools. Load references/journeys.md and references/wiring.md together, in one batch — C's confidence rule decides whether a B journey lands decided, so the two are used jointly. Match the repo to a category by applies_when → primary (+ secondary with the hybrid downgrade). No match → tell the customer; never draft against the nearest category. Simulate a concrete visitor on concrete pages: the questions they ask and actions they request are the spec. Instantiate the matched template's must-haves to this repo's real domain objects, content, and CTAs (a "book a demo" site gets book_demo, not request_quote). ask_site wherever the site has visitor-facing content to answer from — one instance; if there is genuinely none (e.g. an auth-only internal dashboard that matches no category), don't fabricate a content bundle, say so. Stay in the category's count band and global 3–10; thin-content sites get ask_site and stop. Fix availability, context, response, and annotations per tool.
C — Pick the wiring. (references/wiring.md is loaded with B; load it now if it is not.) For each tool take the highest safe rung (client data layer > same-origin route > client action > content bundle) and name the concrete path. Resolve the exact workspace-relative entry-module path for the registration scope and exact workspace-relative source-module path for each tool now. Explorer runs record them in plan.json.entry_module and each suggestion's source_module before proposal; chat-only runs include the same exact paths in the Phase-D plan presented in the conversation without creating Explorer state. Reuse those approved paths through generation, feedback, and Connect. Confidence rule: a tool is decided only if its journey is a category must-have AND a rung-1/2 path exists with corroborating evidence (route + handler + UI element agree). Anything else — ambiguous semantics, competing flows, great-to-haves, uncertain category — is needs your input with a specific question and a stated default. Per-tool evidence gathering (route + handler + UI element) is independent across tools — batch or fan it out exactly as in Phase A.
D — Review the plan (hard gate). Load references/plan-template.md. Open every human-facing review with a short summary, identical in substance across entry modes, of what the skill will do and which tools it will create; on the loop path, it is the _chat.ndjson handoff (Propose, references/interactive.md) shown in the Explorer's conversation panel — the terminal message just points the developer to the Explorer. Then present the plan in the selected review surface before touching any file; tool descriptions ship verbatim (description is the product). Edits → revise → re-present. Proceed only on explicit approval. In --non-interactive mode, use the stated defaults and Degrade path instead.
E — Generate. Load references/codegen.md and references/sdk.md in one batch — the latter for the exact SDK surface and wiring. Add the SDK dependency the way references/sdk.md prescribes, starting the install as a background task at approval so writes never wait on it (references/codegen.md); emit the two-module shape as separate files — each side-effect-free tool module at its recorded source_module (defineTool at module scope, never inside a component/effect) plus one entry module per registration scope. An unbundled browser-served module may not keep the package's bare import: vendor the SDK behind a relative browser URL before approval. An import map is not sufficient because static review cannot prove that the server's CSP header permits its inline script. stableKey is domain.action, authored once and never changed on re-runs (reuse any inventoried in Phase A; never a copy of the wire name) — name may change freely. Each description states what it does, when to use it, and what it returns; inputSchema sets additionalProperties: false. execute runs the Phase-C path verbatim and throws on failure or missing anchors/data (never succeed-on-missing) — a read that finds nothing is not a failure: it still returns, with the empty result plus an explicit note field saying the site has no matching content, never a bare empty array. Match the repo's language, lint/format config, and file conventions. If an approved call path proves unusable or the implementation must deviate from the approved plan (different endpoint, changed behavior or coverage), stop and re-present the change — never silently substitute under a stale approval. Start Phase F's static checks (typecheck/lint/build) after this first write, not only once every file is written — preferably a watch-mode typechecker as a background task (references/verify.md), so per-file checks are incremental — a turn-budget cutoff should still land at least one static pass.
F — Verify. Load references/verify.md. Run the ladder: static → boot → registration on declared pages/auth states → read-only invocation → state-changing only on seeded/dev data with consent. Every tool ends verified, failed, or could-not-verify. Failed blocks the PR (fix or drop — never ship known-broken); could-not-verify ships flagged. After the ladder, load references/connect.md for every human run: use the Explorer decision when its loop is active and the agent conversation for chat-only review. Its plugin-root CLI entry is mandatory, with no PATH-installed CLI assumption. Only explicitly headless or --non-interactive paths skip Connect.
PR. Branch webmcp/tools-v0; conventional commit; open a PR (approved plan + per-tool verification table as the body) via gh when available, else commit on the branch and hand over. Restate could-not-verify items and needs-developer-wiring journeys in the summary.
Star ask (human runs only). After the PR link (or the committed branch) has been handed over — the run's value is delivered, never before — quietly run <this skill's dir>/scripts/star-repo.sh --eligible. Exit 0 means gh is installed, authenticated, and the repo is not already starred; only then append one non-blocking line to the closing summary: if WebMCP Kit was useful, may I star nekuda-ai/webmcp-kit on your GitHub? On an explicit yes run <this skill's dir>/scripts/star-repo.sh and relay its one-line outcome; on anything else drop the subject. Ask at most once per run, never star without that yes, and skip the ask entirely when the check is ineligible or the run is --non-interactive.
Entry and review mode
- Headless intent must be explicit: the
--non-interactiveflag in the invocation or an equally explicit standing instruction in the request text (for example, "proceed without approval" or "non-interactive") counts as that flag. Never infer it from the environment (no TTY sniffing or "seems headless"). A request to reopen or continue an existing run (a.webmcp/folder with state) → see Resume. A request with neither loadsreferences/interactive.mdand runs D–F as an interactive browser loop over the git-tracked state folder.webmcp/— UI phases propose → build → review → verify → done: approval startsverify, anddonestarts only after the PR exists. If the loop is not already running, the agent may offer to start it. Codex uses bundled hooks only when/hookslists them; their automatic run binding is same-task only, with manual replay as the fallback. Claude Code may use Monitor where supported. In every path the skill remains the workflow authority. - Developer declines the browser loop → continue as
--no-interactive-loopwith chat-only review. - Bun unavailable (the Startup preflight in
references/interactive.md) → offer install or chat-only review per that preflight; never infer either choice, and never read missing Bun as non-interactive intent. --no-interactive-loop→ human, chat-only: show the Phase-D summary and plan in chat, then wait for explicit approval. Do not start the browser loop.--non-interactive→ explicit headless: skip the browser loop and use the gate-free Degrade path below.- If nobody answers the gate and no explicit non-interactive intent was given, stop; inference may never skip the gate.
Resume
- In the same agent task/session, validate
.webmcp/.run.jsonv1 for this canonical workspace and call its run-aware/healthz?capability=...&run_id=.... If live, reprint/?capability=...&run_id=..., restore that task's available Codex-hook or Claude-Monitor wake path fromreferences/interactive.md(otherwise use same-task manual replay), then scan valid current-run envelopes without a handled ack in numericorder. - In the same task, a valid run with a dead server may use
server.ts <workspace> --resume; use only its printed URL/runtime metadata, restore the same task's delivery, reconcile partial effects, and continue. Runtime metadata absent/invalid means there is no safely resumable identity. - A fresh task does not inherit the old run's automatic hook binding. It may reconcile current unacked envelopes manually. For continued automatic browser interaction, explicitly rotate per
references/interactive.md: shut down a live old server or abandon dead runtime metadata, then use normalserver.ts <workspace>without--resumeand establish the new task's own run/session. Socket delivery and hook claims are hints; matching journal envelopes plus_ack.ndjsonremain the truth.
Degrade paths
- No category match → say so; do not force a weak fit.
- Most must-haves unwireable → proposal-only is a legitimate terminal outcome: deliver the reviewed plan, no code, and say why. That is benchmark signal, not failure.
- Explicit
--non-interactive→ proceed automatically: record the plan verbatim as the PR body/summary, implement each needs-your-input item on its stated default, and restate each in the summary as an assumption — the question, the default taken, and why. - No runnable browser → mark tools could-not-verify and still ship plan-conformant code.
Environment
- If the working directory ships its own site runbook (lifecycle commands, base URL, test identities — e.g. an eval capsule), use it for boot/reset; otherwise use the repo's own scripts. Never assume a harness exists.
- Browser verification needs WebMCP active: Chrome 150+ flag or
@mcp-b/webmcp-polyfill— recipe inreferences/verify.md.
Signals
- GitHub stars
- 31
- Forks
- 3
- Last commit
- Sep 2026
- Hacker News mentions
- 20
Advanced
- Catalog kind
- skill
- Gateway key
implement-nekuda-ai- Source
- github.com/nekuda-ai/webmcp-kit