Inspiration

Instagram makes it easy to save a Reel about somewhere you want to go, then gives you nothing to do with it. Our own folders had about a hundred places across nine countries. When the dates finally got booked, the fastest route from that folder to a real itinerary was still twenty browser tabs, so we never opened it and planned off search results instead.

So we built the conversion. Paste Reel links and a multi-agent pipeline on the OpenAI Agents SDK pulls the places out of the captions, verifies each one exists, checks weather and routes, and groups them into days by geography. Anything that will not verify gets dropped. It takes 60 to 180 seconds.

Then we showed it to people and got this back:

"It's unclear how to navigate the website, where to click, how to choose the reels, how to start generating a trip."

We had spent a sprint treating that as a copy problem. It was not. The tool was not hard to understand, it was hard to operate, and we could either keep redesigning buttons or remove the need to find them. That is what took us to WebMCP.

What it does

Astrail turns saved Instagram Reels into a routed trip on a live 3D map, and you drive it by talking to ChatGPT.

Say "save these reels" and paste some links; it saves them and starts pulling places out. Say "plan me two days in Osaka from those" and it shows an approval card with the cost, runs the pipeline, narrates each stage, and hands back a routed map. Say "add Tokyo Disneyland to day 2" and it asks you on the page, finds the place, adds it, and redraws the route.

Ask why a stop is on your trip and you get one of three answers: the caption quote from the Reel it came from with a link to that Reel, Astrail's reasoning where it suggested the stop, or a note saying you asked for it. Where we cannot source a fact, like opening hours, the space stays empty.

It also remembers how you travel. Tell it once and the next trip recalls it, names what it remembered on the card, and still asks before spending anything.

None of that is the agent working alone. It plans, you approve. It offers what it remembered, you can override it. Before WebMCP those two halves could not meet: you could read the itinerary but not change it, and an agent could describe your trip but never touch it.

How we built it

Seventeen tools registered through document.modelContext.registerTool(), in two scopes. Fourteen in the signed-in app shell, three more only while a trip map is mounted, and six that work with no account on a public sample trail.

The important part is where they run. A backend MCP server can describe a trip. Only WebMCP can move the map the person is looking at. Because execute() runs in the page, a tool already has the loaded trip, the session, and the same React state setters a click uses. Ask for day 2 and the page's own showDay runs, so the camera flies and the day chip lights up as if you had clicked.

The agent inherits our security model instead of bringing its own. Reads run under the same row-level security a human gets, no access token crosses the tool boundary, and every edit to your trip stops for an approval card on the page rather than a question in chat.

Tools address stops by pin number, so "move stop 7 to day 3" works and no UUID ever reaches the agent. Reel captions are text an attacker can write, so every tool whose output can carry one is annotated untrustedContentHint, and the extraction agents run behind input_guardrail tripwires.

We also had a second model reviewing. Every plan and diff went to Codex before it landed, and it caught things we missed, including a bug inside a fix we thought was already correct.

Stack: Next.js 15, React 19 and Mapbox GL on Vercel; FastAPI on Render; Supabase; the OpenAI Agents SDK; mem0; Apify.

What we added during the submission period

Astrail existed before 25 August, as a form. You pasted Reel links, waited, and got back an itinerary you could read but could not change.

Everything in frontend/lib/webmcp/ was written on or after 26 August: the seventeen tools, the registry behind them, their contract tests, the on-page approval cards, the agent activity rail and the WebMCP status chip. So were the five owner-checked FastAPI edit endpoints they call, because until then the itinerary was immutable at every layer, with no endpoint, no frontend mutation and row-level security that was SELECT-only. Two other things were built in the window: the map was rebuilt so a stop that came from a Reel carries that Reel's own cover frame in its pin and links back to the Reel, and /app/trip/demo is new, a finished sample trail that opens signed out with six of the seventeen tools so the app can be judged without an account.

The memory engine is older. It was built between 7 July and 2 August and we do not claim it as challenge work. What is new is that an agent can reach it, and the reason it could not is the first thing under Challenges below. The dated, commit-by-commit split is in docs/webmcp/WHATS-NEW.md.

Challenges we ran into

The worst one was a flaw in our own product that only showed up once an agent was driving.

Astrail looks up what it remembers about you only when the preferences box arrives empty, on the logic that what you typed today beats what you said three trips ago. It saves a new memory only when that box arrives full. Those conditions never overlap. So an agent leaving the field blank could recall forever and never teach it anything, and the manual form, which pre-fills that box from your profile, was quietly switching recall off on the other path. Nobody had noticed because no path had exercised both halves. Three changes fixed it: the planning tool asks how you travel when it has nothing stored, the card names what it remembered before you approve, and a new tool reads the store back.

Chrome's use-webmcp-tool hook cost us a day. It never catches the promise registerTool returns, and since aborting the signal is how a tool unregisters, every navigation threw an unhandled AbortError across the app. We could not patch it from outside, because registerTool is a non-writable property of a native interface, so we wrote our own. About 144 lines.

Making an agent's action feel like your own took longer than expected. Early versions had a tool call an API and then hope the page noticed, which is a second rendering path, and those drift. Now a mutation will not resolve until the UI has caught up.

Accomplishments that we're proud of

WebMCP fixed the thing users actually complained about, which was the whole point of trying it.

Getting Reels in used to be copy, switch tab, paste, repeat, then find a separate button to start extraction. Now you paste four links in one message. A finished trip used to be frozen at every layer, with no endpoint and no frontend mutation. Now five tools edit it, each behind an approval card.

Beyond that, nothing reaches the map unattributed, and a contract test fails if our own copy ever promises a caption quote for a stop that has none, because the false version of that sentence reads better than the true one. Our tests check the README's tool table against the registry too, so a stale claim goes red rather than shipping.

What we learned

None of us had used WebMCP before this. It was announced, we read the spec, and started.

It is a DOM API, not a server. We spent the first evening looking for the deployment story before realising there is not one. Your tools ship with your JavaScript.

Where you register matters as much as what you register. App shell versus trip page is the difference between a tool that always exists and one that appears only when there is something for it to act on.

The description field does more work than the code behind it. It is the only place to teach an agent when to call something, and it is captured at registration, so it cannot say anything dynamic. We rewrote ours constantly.

And the page cannot talk back. When someone clicks a pin, the agent has no idea. That asymmetry shaped more of the design than we expected.

What's next for Astrail

Group trips. Nobody plans a holiday alone and right now Astrail assumes you do. Several people on one trip, each with their own agent, editing the same map. Everything here already points that way, since an agent edit and a human edit are the same event.

Memory that watches rather than only listening. Right now it remembers what you tell it. The trips you actually keep say more: which neighbourhoods, how far you will really walk, whether you fill a day or leave it open.

Flights, so it covers the whole trip. Search and comparison, not booking. There are no payments in Astrail.

Built With

  • apify
  • codex
  • fastapi
  • mem0
  • nextjs
  • openai-agents-sdk
  • render
  • supabase
  • vercel
  • webmcp
Share this project:

Updates