Inspiration

After a flood or fire, people often have to explain what happened over and over again—to the county, the utility company, housing programs, and different relief organizations. When your home is already damaged, even figuring out which form to start with can be overwhelming.

The problem isn't always that nobody wants to help. It's that the help is spread across different websites, forms, and systems that don't really talk to each other.

We started wondering: what if an agent could handle some of that coordination for you, without making decisions on your behalf?

That is what made WebMCP interesting to us. A website can expose specific tools to an agent while still controlling exactly what the agent is allowed to do. The agent can take care of repetitive work, while the resident stays in control of what gets shared, approved, or submitted.

What it does

2030MCP LinkUp is designed for the days after a flood, fire, earthquake, storm, or other disaster.

Instead of entering the same information into multiple systems, you explain what happened once. LinkUp turns that into a simple Situation Map showing what it understood, what information is still missing, and which services may be relevant.

For example, the system may identify that you need temporary housing, utility support, replacement documents, or disaster relief.

The agent can then read provider requirements, organize the information you already provided, and prepare the next step for you.

The important part is that it does not make the final decision.

It cannot decide whether your story is true, approve your case, or submit something on your behalf without your review. You see what the agent plans to do first and choose whether to continue.

How we built it

We built LinkUp with Next.js App Router, TypeScript, and Tailwind CSS.

The WebMCP layer is built around document.modelContext.registerTool. Instead of registering every tool all the time, LinkUp rebuilds the available tool registry from the current signed case state.

That means a tool only becomes available when the user has reached the right step and given the required consent.

We also enforce the same boundaries on the server. Route handlers validate signed session data including the user's role, disaster scenario, and origin. We use strict Zod schemas, state version checks, idempotency keys, packet hashes, expiring grants, and rate limits to prevent replay, tampering, or unintended submissions.

Every action that changes the case is also recorded in a server-side audit log.

For the disaster flows, we created separate provider fixtures for floods, fires, earthquakes, and storms. The provider policy version is selected before evidence is collected, so changing the incident later cannot silently change the rules applied to the case.

Testing was a major part of the project. We currently have 108 Vitest tests covering the WebMCP contract, dynamic tool registration and removal, replay prevention, tamper rejection, and session integrity.

We also run strict TypeScript checks and GitHub Actions with pinned revisions.

Most importantly, we tested the real WebMCP flow in a browser using the native document.modelContext interface. We verified that the send tool appears only after consent and disappears again after it has been used.

For Chrome testing, the project also includes a Chrome 149+ path using chrome://flags/#enable-webmcp-testing.

To keep the demo easy to run, the entire resident session survives serverless cold starts without requiring a database. Case state is stored in signed, Brotli-compressed cookie chunks with strict size limits.

We also test the deployed version with npm run test:golden to make sure a fresh incognito session can complete the full flow from beginning to end.

Challenges we ran into

The hardest part was making "the human is in control" something the system actually enforces.

At first, it is tempting to put instructions in the tool description and say that the agent should ask before doing something important. But that still depends on the model following the instruction.

We wanted the restriction to exist at the system level instead.

So we moved permissions into the tool registry itself. A consequential tool does not exist until the user has explicitly given consent. After a one-time action is used, the tool removes itself from the registry.

That gave us something we could actually test: not just whether the agent behaved correctly, but whether the tool was available at all.

Another challenge was writing tool descriptions for an agent rather than for a person. We added clear authority boundaries such as CONSEQUENTIAL, ONE USE, explicit fields that prevent the agent from implying provider approval, and untrustedContentHint for information that comes from free-text user stories.

Another challenge was keeping a complete resident session working across serverless instances without a database while still staying inside browser cookie limits.

Accomplishments that we're proud of

We're proud that LinkUp actually works as a deployed product, rather than being just a mockup of an agent workflow.

The WebMCP registry changes live as the resident moves through the process. A one-use send tool appears after consent, can be used once, and then disappears.

We also built a read-only audit interface so another agent can inspect what happened without being able to change the case.

And instead of using one generic disaster demo, we built separate provider contracts for floods, fires, earthquakes, and storms so the workflow behaves differently depending on the situation.

What we learned

If a tool should not be available yet, the safest option is not to register it at all.

We also learned that tool descriptions matter much more than we expected. They are not just documentation for developers; they are part of the interface the model uses to understand its authority and responsibilities.

Clear descriptions made the agent much more likely to ask for review instead of acting as if it had approval from a provider.

WebMCP also showed us a different way to think about agent safety. Instead of putting every restriction inside a chat prompt, some of the rules can be enforced directly by the website and its tool lifecycle.

What's next for 2030MCP LinkUp

First, a server-issued human-presence challenge so consequential actions can verify that a real resident is still present.

Second, an encrypted case database for longer-term recovery cases and larger documents.

Third, real provider integrations for housing agencies, utilities, local government, and relief organizations.

The WebMCP contracts are already structured so providers could publish their own requirement and submission tools. The county, housing, and utility portals in our demo are examples of how those provider-owned integrations could work.

The long-term goal is simple: people should not have to rebuild the same disaster story for every organization they need help from. They should explain what happened once, review what gets shared, and stay in control of the process.

Built With

  • codex
  • vercel
Share this project:

Updates

Submission history