# Implement

> Add 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.

- Skill: `nekuda-ai/implement` (Agent Skill, multi-file: 15 files)
- Install (CLI): `npx skillmds@latest add nekuda-ai/implement`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nekuda-ai/implement/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: nekuda-ai (https://skillmd.com/u/nekuda-ai)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/nekuda-ai/implement

---


# WebMCP Kit — implement

## Mission
- WebMCP hands a browser agent typed tools (via the `@nekuda/webmcp-sdk` SDK) 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 or routes to an external service, and never send anything to an unauthenticated tool/API. The one exception is the separately approved publish step in `references/connect.md`, which sends the approved tool descriptions and input schemas — never a handler body, a route file, or a credential — to the authenticated API the developer just connected to. 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.** `execute` may 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-interactive` mode; 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` / `registerTools` from the SDK under its resolved name (the installed package's declared name — `references/sdk.md`); never the raw `modelContext` surface, 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 `stableKey`s) 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, collected per `references/decisions.md`. 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. That file also carries the second optional decision it unlocks — publishing the approved tool descriptions to the catalog, offered only after a healthy connection, sending descriptions and never code or credentials.

**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, and — when Connect finished healthy — the dashboard link from `references/connect.md`'s hand-over step.

**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-interactive` flag 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 loads `references/interactive.md` and runs D–F as an interactive browser loop over the git-tracked state folder `.webmcp/` — UI phases propose → build → review → verify → done: approval starts `verify`, and `done` starts only after the PR exists. If the loop is not already running, the agent may offer to start it (a decision per `references/decisions.md`). Codex uses bundled hooks only when `/hooks` lists 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-loop` with chat-only review.
- Bun unavailable (the Startup preflight in `references/interactive.md`) → offer install or chat-only review per that preflight, collected per `references/decisions.md`; 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 collect approval per `references/decisions.md`. 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.json` v1 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 from `references/interactive.md` (otherwise use same-task manual replay), then scan valid current-run envelopes without a handled ack in numeric `order`.
- 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 normal `server.ts <workspace>` without `--resume` and establish the new task's own run/session. Socket delivery and hook claims are hints; matching journal envelopes plus `_ack.ndjson` remain 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 in `references/verify.md`.

