Agentic Self-Service Website Compliance and Discoverability

About the project

A public API is not enough when a person and an agent have to work on the same page. Scraping the DOM is brittle. Handing the agent an unchecked POST is worse: it can spend budget, kick off work, or touch production with nobody in the loop.

anc.dev audits a site for the interfaces both sides actually use: machine-readable docs, OpenAPI, MCP discovery and protocol behavior, auth metadata, and browser-side WebMCP tools. The page renders a scorecard a human can read. The same markup is also a worksheet the in-page agent can query.

The agent can fill the target URL and leave a short plan. I click Audit and complete Turnstile. After the result is on screen, the agent can read that scorecard and pull remediation prompts. It cannot start a second audit, skip the challenge, switch targets, or submit the form.

Why WebMCP

I wanted the agent on the same page I was looking at, with tools that match what that page is for.

On /web-audit, WebMCP tools prepare the form: fill_audit_url, set_plan, and a few other helpers scoped to that page. They do not submit it.

On a result page, four read-only tools turn the visible scorecard into a repair queue:

  • get_worksheet lists findings as JSON rows (id, keyword, status, evidence, remediable). Filter by RFC 2119 keyword and status; omit status, and you get the remediable set that was actually observed. Each page is a JSON envelope with cached, scored_at, refresh_after, and next_offset.
  • get_fix_prompt returns the stored remediation prompt for one check id, or remediable: false with a reason.
  • get_fix_prompts returns prompts for many checks at once, with the same filters and pagination.
  • get_audit_summary returns site and global scores, per-status counts, freshness, and the paged issue list.

The tools read the DOM I am looking at. They do not call a backend and dress the response up as a browser tool. Output is capped, and a row that cannot be auto-fixed says so.

The two-pass loop

The demo target is Sounding, a public Worker I shipped in an incomplete state so there would be something real to fix.

  1. A browser agent prepares an audit of Sounding. A person authorizes it.
  2. On the result page, the agent asks get_worksheet for MUST findings and pulls get_fix_prompt for each remediable row.
  3. Those fixes land in Sounding, get deployed, and we audit again.
  4. The second scorecard shows the new evidence. Same page, different results.

Inspect, fix, audit again. The agent helps turn the report into a small patch set I can review. I still own the audit click and the deploy.

How I built it

This is a production Cloudflare Workers site. A client bundle registers tools with document.modelContext.registerTool when the browser supports WebMCP. Which tools appear depends on the pathname: the form page can prepare an audit, a result page can expose the worksheet, and the scoring route registers nothing.

The result renderer stamps stable metadata on every visible finding. The WebMCP tools read that metadata back, so status and remediation eligibility match what is on screen. Responses are sized for the browser-tool cap.

The engine checks discovery documents, OpenAPI, MCP protocol behavior, auth metadata, markdown availability, bot reachability, and whether the page exposes WebMCP. The running stack is Workers, KV and R2 for audit data, Turnstile, and a public TypeScript repo.

What I learned

In this use case, WebMCP became more useful when I started removing capabilities.

Filling a form from a tool is easy. What I actually needed was a hard line between "prepare this" and "spend this audit," plus tool output that does not hide state from the person looking at the page.

The result-page webmcp tools are read-only and make no network requests. They cannot skip Turnstile. They return complete JSON items, include cache freshness next to the findings, mark which rows are fixable, and link out to the full remediation doc when a prompt is too long for the browser-tool budget.

I checked this in a real browser: captured the tools registered on rendered audit pages, ran the result tools against the DOM, compared their schemas to the published docs, and confirmed none of them can hit the audit endpoint. The live site is meant to open in ChatGPT's in-app browser or in Chrome with WebMCP enabled.

Built With

  • agentic-workflows
  • bun
  • cloudflare-kv
  • cloudflare-r2
  • cloudflare-turnstile
  • cloudflare-workers
  • developer-tools
  • html
  • markdown
  • model-context-protocol
  • openapi
  • playwright
  • typescript
  • web-standards
  • webmcp
Share this project:

Updates

Submission history