What it is
When the Grand River comes up, help is a group chat: forty unread messages, a spreadsheet nobody updates, and a volunteer with a truck who doesn't know where to go. Highwater is one map. Requests and volunteers are pins. The coordinator drags pins, bumps urgency and marks things done by hand. The dispatch agent reads the same board through WebMCP, logs what comes in, matches the nearest suitable volunteer, draws the dispatch line, and broadcasts what's still unmet.
Live: https://highwater-six.vercel.app · Code: https://github.com/chinesepowered/highwater
Why this is a strong fit for WebMCP
Dispatch is a shared-state problem. An agent that only sees a screenshot of a map cannot know that the coordinator just moved Jamal's truck to the far side of the closed bridge. Highwater exposes the board as eleven structured tools registered with document.modelContext.registerTool:
get_situation, get_stats, add_request, add_offer, find_volunteers_for, match, unmatch, update_request, update_volunteer, broadcast, focus_map
add_request accepts a street name and places it on the map through a small gazetteer, so the agent can work from raw text messages. find_volunteers_for returns capable volunteers nearest-first with distance in km and availability, and match draws the dispatch line. Every human edit (a dragged pin, an urgency click) changes the same model the tools read; every agent edit lands in the event feed with a 🤖 mark.
How it creates a better experience
- Paste, don't transcribe. Three incoming texts become two requests, one volunteer, two matches, dispatch lines on the map, and a broadcast for what is still unmet. Eight tool calls, one paste.
- Human corrections are first-class. Drag Priya's boat across the river because the bridge closed, say "Priya is stuck", and the agent re-reads the board, sees her new position, releases her, and re-matches the seniors' residence to the accessible van. The map flies to it with
focus_map. - Triage you can see. Urgency 1–5 colours the pins; open-and-urgent requests sort to the top; stats show people waiting and volunteers free.
What people and agents can do together that was hard before
Before: one exhausted coordinator reading messages aloud while someone else types into a sheet, and matching by memory. Now: the coordinator keeps judgment and local knowledge (which bridge is closed, who is reliable) and expresses it by moving pins and setting urgency; the agent keeps the bookkeeping and the distance math, and never acts on stale state because it reads the board before every action.
How WebMCP is implemented
lib/webmcp.ts: registry that callsdocument.modelContext.registerTool(..., { signal })for each tool and unregisters viaAbortControlleron unmount. Native browser-agent calls and in-page agent calls share oneexecutepath and one activity log.lib/tools.ts: the eleven tools with JSON Schema inputs and read-only / destructive annotations.lib/aid.ts: the shared store (requests, offers, events, map focus), haversine distances, the street gazetteer, and match/unmatch bookkeeping. Dragging a Leaflet marker calls the same store the tools mutate.components/AidMap.tsx: react-leaflet map with draggable pins, dispatch polylines, and a fly-to controller driven byfocus_map.components/AgentPanel.tsx+app/api/agent/route.ts: a Gemini function-calling loop that discovers the registered tools and dispatches through WebMCP, with a model fallback chain for free-tier limits.
Tested in Chrome 153 with chrome://flags/#enable-webmcp-testing (DevTools → Application → WebMCP lists all eleven tools) and with the in-page Gemini dispatch agent.
Fictional scenario and people; not an emergency service.
Stack
Next.js 16 · Leaflet + react-leaflet (CARTO / OpenStreetMap tiles) · Tailwind 4 · Gemini function calling · WebMCP · Vercel
Built With
- gemini
- leaflet.js
- next.js
- react
- react-leaflet
- tailwind
- typescript
- vercel
- webmcp
Log in or sign up for Devpost to join the conversation.