-
-
Attaching the three bundled sample documents through the canonical manifest — the same files whether clicked or registered by the agent.
-
Every step names both paths at once: the button to click, and the exact sentence to tell the agent instead.
-
The Spanish interface, with an explainer panel describing what WebMCP is and how each action maps to a tool.
-
The agent creates a dossier, is blocked from skipping a step, then submits it — all through the page's own validated logic.
-
Review step: every extracted field cites the exact document and page it came from, before a human approves submission.
Inspiration
What it does
How I built it
Challenges I ran into## Inspiration
We wanted to test a real, unglamorous shape of task against the WebMCP standard: a government procedure. A trámite is a bounded set of well-defined actions with real validation and real consequences — exactly the kind of task where an agent guessing at buttons or screen text is not an acceptable failure mode. RUTIC is a synthetic GovTech app: a public telecom-provider registry for Colombia where every action a person can do with buttons, an AI agent can also do, through the same page-owned logic, never around it.
What it does
RUTIC lets a person create a dossier by uploading three documents, which the page extracts and validates locally — no PDF ever reaches the AI model. From there they review or edit nine typed fields, submit with an explicit human-approved code, modify a submitted dossier without re-uploading anything, cancel an edit and keep the last submitted version untouched, list and check their dossiers, and switch the interface between Spanish and English. Every one of those actions is reachable two ways: a button, or a sentence to the agent. "Modify my dossier" resolves to the one submitted dossier without asking for its code back; "the second one" or "el segundo" resolves against a list the agent just showed; "envíalo" is accepted as the explicit approval without repeating a code already on screen. The task takes the same number of real steps either way — talking removes the cost of finding the right control, and a person can switch between clicking and talking mid-task because both paths write to the same state.
How we built it
Every dossier action is a real, imperative document.modelContext.registerTool call, not a static list — the set of registered tools is recomputed from the page's own state machine on every change, so the agent can only ever see and call what's actually valid at that moment. Gemini (gemini-3.5-flash-lite) receives a fresh summary of the true page state on every turn and is instructed to reuse only values it has actually seen: it never receives PDF bytes and never invents a claim value, a dossier code, or an approval code. The page keeps the authority; the agent only routes intention to it.
Challenges we ran into
We built and load-tested a declarative variant — an annotated form the browser fills and submits directly — for the one task that looked like a natural fit, editing form fields, and reverted it. Our full-page re-render recreates the form's DOM node on every state change, and the browser's declarative discovery treated that as a brand-new tool appearing each time, causing a runaway feedback loop. We're documenting that attempt rather than hiding it, because it's a real, useful finding about the standard's current rough edges, not just a footnote.
Accomplishments that we're proud of
Nothing the agent can do is something the page can't already validate and execute on its own — the agent only ever decides which action, never how it runs. That guarantee holds across nine typed fields, a document manifest, and a state machine with an explicit human-approval gate, and it's backed by 45 tests covering the state machine, the WebMCP bridge, the Gemini boundary and its retries, extraction, and localization.
What we learned
The clearest lesson came from the failure: WebMCP's declarative discovery assumes a form's DOM identity is stable, and a framework that re-renders the DOM on every state change breaks that assumption outright. The imperative registerTool path, recomputed from the same state machine, doesn't have that problem — for a UI built around frequent re-render, the imperative API is the one that composes safely with real application state, not just a fallback.
What's next
The pattern holds past this one registry: any administrative procedure with well-defined actions, real validation, and real consequences can be built this way — clicked through as usual, or described in plain language, with every check the process requires staying exactly as strict either way. The submission step here is intentionally local and simulated, and always reports externalTransmission: false; the natural next step is wiring that same page-owned logic to an actual government backend without loosening any of the guarantees the demo enforces today.
Built With
- api
- gemini
- github
- node.js
- pages
- typescript
- vite
- webmcp