** Inspiration **
Planning a public-transit journey often begins with an ordinary sentence, not a perfectly structured form. People may say, “I want to go to Taipei Main Station,” “from here to Tamsui,” or simply “where am I?”
Traditional websites require users to translate that intention into separate fields and controls. Browser agents face the opposite problem: they must inspect the interface, guess what each control means, and hope that the resulting route still matches what the person sees.
Qianshou means “holding hands.” The project explores a more collaborative model: a person expresses an intention naturally, an AI agent performs the structured work through WebMCP, and both continue from the same visible journey on the webpage.
The project is motivated by travelers who benefit from clearer and lower-friction journey planning, including older adults and people with visual impairments. The current pilot does not claim that every suggested route is fully accessible. Missing accessibility information remains explicitly unknown.
** What it does **
Qianshou is a WebMCP-powered journey-planning web application for Taipei and New Taipei City.
A person can describe a journey in natural language without deciding which fields to fill in. Qianshou interprets the request, resolves the places, plans a public-transit route, and presents the journey as readable, step-by-step guidance.
When the request depends on “here” or omits an origin, the page can request a fresh browser location. Ambiguous place names are presented for human confirmation instead of being silently guessed.
The page combines several kinds of journey information:
- Step-by-step walking and public-transit instructions
- Total travel time, walking time, and transfers
- Alternative routes that can be selected after the first result
- Arrival information matched to the route’s first transit leg
- Short-range destination weather
- Explicit data-source and coverage limitations
Qianshou exposes three task-level WebMCP tools:
prepare_accessible_journeyinterprets a natural journey request and prepares the complete result.describe_current_locationobtains a fresh location and describes it in human-readable form.select_journey_alternativeswitches the current journey to an existing alternative and updates the visible result.
The person does not need to tell the agent which tool to use. The tool descriptions provide enough meaning for the agent to select the appropriate action.
Most importantly, a WebMCP action updates the same page the person is viewing. The route is not trapped inside an isolated chat response: the person and the agent share one journey state and can continue from the same result.
** How we built it **
Qianshou is built with Next.js 16, React 19, TypeScript, and native imperative WebMCP.
The three tools are registered in the browser using document.modelContext.registerTool. They expose meaningful travel actions rather than individual buttons or form fields. Both the WebMCP tools and the manual interface reuse the same server-side journey services, so agent actions and human actions produce the same visible application state.
A loopback-only Codex CLI service converts natural-language requests into a strict structured intent. It runs with an explicit schema, timeout, and concurrency limit, without shell, browser, plugin, or project-write access.
Place resolution combines Taiwan transportation data with OpenStreetMap Nominatim. OpenTripPlanner 2.9 calculates journeys using GTFS schedules and OpenStreetMap streets. TDX provides public-transit and arrival information, while Taiwan’s Central Weather Administration supplies short-range destination forecasts.
Arrival information is bound to the selected journey’s actual first transit leg using its stop, route, direction, and transport mode. Switching an alternative route therefore also refreshes the related arrival context.
The application is deployed on Google Cloud Platform with Docker and Nginx. To operate within a small VM, we reduced the routing graph to the relevant service region and applied explicit container memory limits.
** Challenges we ran into **
Natural language contains important spatial ambiguity. “From here to Tamsui” and “from Tamsui to here” use the same word but require the current location in opposite roles. A destination-only request also needs different handling from a fully specified journey.
Place names introduce another challenge. A station, district, landmark, and bus stop can share similar names. Combining duplicate search results without erasing meaningful ambiguity required careful normalization and human confirmation.
Public-transit routing also involves trade-offs. The fastest route may require excessive walking, while minimizing transfers may produce an impractical detour. We evaluate total duration, walking burden, and transfers together, while allowing no more than two transfers.
Real-world data is incomplete. Public feeds do not always contain enough information about station pathways, elevators, stairs, or vehicle accessibility to justify a complete accessibility guarantee. We therefore distinguish confirmed information from unknown data instead of converting missing fields into a positive claim.
Finally, route planning, geocoding, arrival matching, and weather services have different response times and failure modes. The interface needed to preserve a coherent result without fabricating data when an upstream service was unavailable.
** Accomplishments that we're proud of **
- Implemented three working, non-trivial native WebMCP tools.
- Made WebMCP tool calls update the same visible journey used by the human interface.
- Allowed agents to act from natural user intent without requiring users to name a tool.
- Combined place resolution, transit planning, arrival matching, alternatives, and weather in one journey operation.
- Implemented correct semantics for omitted origins, “from here,” “to here,” and “where am I?”
- Preserved human confirmation when a place remains ambiguous.
- Kept exact browser coordinates out of the result returned to the agent.
- Added keyboard navigation, responsive layouts, live regions, reduced-motion support, and itinerary speech.
- Preserved a complete natural-language interface when WebMCP is unavailable.
- Reported unavailable or incomplete data honestly instead of generating a convincing but unsupported route.
** What we learned **
Agent-native does not mean agent-only.
The strongest experience came from giving the agent structured, task-level actions while preserving a complete interface for the person. WebMCP works best when it communicates domain meaning—such as preparing a journey or switching an alternative—rather than exposing a collection of low-level interface controls.
We also learned that tool descriptions are part of the product. They must explain scope, intent, and important boundaries clearly enough for an agent to choose the right action without forcing the user to speak in implementation terms.
Finally, route quality depends on data quality as much as routing algorithms. An explicit “unknown” is more responsible and useful than an unsupported accessibility or availability promise.
** What's next for Qianshou **
- Conduct moderated usability testing with older travelers and people using screen readers.
- Expand verified accessibility-data coverage before making stronger accessibility claims.
- Integrate official operational elevator information where available.
- Add nearby-place discovery for stations, convenience stores, and accessible toilets.
- Improve arrival coverage and multimodal route comparison.
- Continue refining English and Chinese place understanding.
- Expand beyond Taipei and New Taipei only after the data coverage and operating model have been validated.
Built With
- codex
- docker
- gcp
- gtfs
- next.js
- nginx
- node.js
- nominatim
- openai
- openstreetmap
- opentripplanner
- react
- sqlite
- tdx
- typescript
- webmcp
Log in or sign up for Devpost to join the conversation.