Inspiration

WebMCP's whole premise is that agents shouldn't have to guess their way through a page — a site can just declare what an agent is allowed to do. Reading Chrome's WebMCP tool security guidance, one line stuck with us: agents are powerful precisely because they act with the user's session already open, which is also exactly why that power needs a boundary. Most of the WebMCP demos we saw were about letting agents do more — search faster, check out faster. We wanted to explore the opposite question: could WebMCP be the thing that lets an agent do less, on purpose, in exactly the right places? High-stakes forms — grant applications, insurance claims, legal filings — are where people are least willing to hand an agent full control. That felt like the right place to test whether "trust" could be a structural property of a tool, not just a line in a system prompt.

What it does

TrustFill is a grant application — the Riverbend Micro-Grant form — that a WebMCP-aware agent can fill out on your behalf, with a hard boundary baked into the tools themselves. For low-risk fields (business name, address, EIN, founding date), the agent fills them in directly. For anything with real consequences — annual revenue, requested amount, legal certifications — the agent cannot fill them at all; the tool it would need rejects the call outright and requires it to flag the field with a reason instead. The application cannot be submitted while any flagged field is unresolved. A live audit trail records every action, agent or human, in order, so nothing happens invisibly. The result: an agent that's genuinely useful for the boring 80% of a form, and structurally incapable of guessing on the 20% that matters.

How we built it

The frontend is React + Vite with Tailwind for styling, and all state lives in a single reducer-driven form model — no backend needed for the demo. Six tools are registered through the real WebMCP API, document.modelContext.registerTool, each with an AbortController for clean unregistration on unmount: get_form_state, fill_field, flag_uncertain, request_human_review, submit_form, and get_audit_trail. The two read-only tools carry readOnlyHint annotations so an agent knows they're always safe to call. The critical piece is inside fill_field itself: it checks each field's risk tier and rejects the call for high-risk fields before it ever touches state — the boundary lives in the tool's own code, not in a prompt telling the agent to behave. We registered the deployed Netlify domain for Chrome's WebMCP origin trial so the API is genuinely available to any visiting browser or agent in production, added /.well-known/webmcp and llms.txt so the site is discoverable before an agent even loads the page, and built an explicit demo-mode fallback (with console diagnostics reporting mode=real-webmcp vs mode=demo) so the concept is visible even in browsers without WebMCP support yet.

Challenges we ran into

Getting from "works locally with a Chrome flag" to "works for a real visiting agent in production" surfaced problems we didn't expect. The WebMCP API surface itself has been shifting (navigator.modelContext moved to document.modelContext), so we had to make sure we were building against the current spec rather than a stale example. Production availability required registering for Chrome's origin trial, and our first token was scoped as third-party by mistake — a mismatch that silently kept the site in demo mode until we re-registered with the correct scope. We also had to learn the hard way that not every "browser agent" actually uses WebMCP tool discovery — some general-purpose browsing tools simulate a human clicking through the UI instead, which looked like a WebMCP failure at first but was really a different agent entirely. Most importantly, testing surfaced a real bug where the Submit button's enabled state wasn't reading from the same blocker logic as the submit_form tool — meaning the UI could have let someone submit with unresolved high-risk fields, which would have quietly undermined the entire premise of the project if we hadn't caught it.

Accomplishments that we're proud of

The core guarantee isn't a claim, it's enforced in code: fill_field structurally cannot touch a high-risk field, and submit_form and the Submit button now share one blocker calculation, so there's no path to submitting with something unresolved. We verified the full six-tool integration independently with a WebMCP tool inspector showing real, callable schemas — not just our own word for it. And the live audit trail means every decision, whether made by the agent or by the human reviewing it, is visible and traceable rather than happening behind the scenes.

What we learned

The biggest shift in thinking: safety for agentic web apps doesn't have to live in a prompt at all — it can live in the shape of the tool contract itself, which is a guarantee no amount of clever prompting can quietly break. We also learned that the gap between local, flag-enabled WebMCP testing and real production behavior is bigger than the docs make it sound, and that "an agent used my site" can mean two very different things depending on whether it discovered structured tools or just simulated a human — a distinction worth designing and testing for explicitly, not assuming.

What's next for TrustFill

We'd like to make the risk tiers (low/medium/high) configurable per organization instead of hardcoded per field, so the same pattern could be dropped onto any long form — insurance claims, rental applications, government paperwork — without rebuilding the gating logic each time. We're also interested in extending request_human_review to support multiple humans on one application (co-applicants, cosigners) negotiating shared fields, and in exploring WebMCP's declarative HTML-attribute tools alongside our imperative ones to see whether the same trust boundary can be expressed even more simply. Longer term, we'd like to publish the gating pattern itself — reject-by-default on high-risk tool calls, shared blocker logic between tools and UI — as a small reusable library other WebMCP-based forms could adopt directly.

Built With

Share this project:

Updates

Submission history