# Voice copilot

The [voice copilot](/copilot) is a browser demo you talk to. A voice model
on OpenAI Realtime listens and answers, and every route, place, restriction
and detour it states comes from a call to MapMap's hosted
[MCP server](/docs/mcp), shown on screen as it happens. Ask it to drive and
MapMap's guidance engine, compiled to WebAssembly, runs the route in the
page with a banner, an ETA and spoken turn instructions. It is for anyone
who wants to hear what a voice interface on MapMap's tools sounds like,
and for teams building one of their own.

> **Availability:** a live demo at [mapmap.ai/copilot](/copilot), free to
> try with no signup, in sessions of up to five minutes. It is not a
> product or an API: there is no hosted voice API for customers. What you
> can build on is the hosted [MCP server](/docs/mcp), which is live, and
> the guidance and voice packages
> [below](#build-your-own).

## Using it

1. Press **Start talking** and allow the microphone. The page asks its own
   server for a short-lived session key (it expires in about a minute and
   is only used to open the session), then connects to OpenAI Realtime
   over WebRTC.
2. Speak. Interrupt it mid-sentence and it stops. The **Try saying** chips
   send a prompt as text once the MCP tool list has loaded.
3. Routes and places are drawn on the map. The **Tool calls** list shows
   every tool the model calls, with its arguments and its result: nothing
   is mocked.
4. Once there is a route, **Drive the route** plays a simulated drive
   along it: the guidance engine is fed position fixes synthesised along
   the route, and turns them into the banner, the ETA, the speed limit and
   the spoken prompts.

A route change goes through two steps: the page computes the new route
and the time difference, the copilot reads the difference back, and only
a clear yes confirms it. A proposal not confirmed within about 25 seconds
expires.

**Two voices.** The turn instructions are spoken in a different voice from
the copilot's, so the engine and the assistant never sound alike. The
engine's words are spoken verbatim, never reworded by a model. Guidance
always wins: critical guidance, then an imminent manoeuvre or warning,
then you, then the copilot, which is turned down while guidance speaks
and holds non-urgent speech within 150 metres or 12 seconds of a
manoeuvre, whichever is further.

## Modes

`?mode=` picks the persona; the control at the top of the page switches it
while no session is running. Anything else opens in fleet mode.

| `mode` | Persona | Try saying |
| --- | --- | --- |
| `fleet` (default) | A businesslike copilot for commercial drivers, with a vehicle chip for the declared truck and load | "Take my tanker from Dover to Birmingham, tunnel code C"; "Can I take this load through a category D tunnel?"; "Why are we going this way?" |
| `consumer` | Plain English for someone walking, cycling or driving a car; prefers walking or cycling routes when they fit | "Walk me home on lit streets"; "Where's the nearest EV charger?"; "Where's the nearest late-night pharmacy?" |
| `codriver` | MapMap Co-driver: short, characterful lines and a full-width map; volunteers at most one remark, and only at session start, drive start or arrival | "Take me to Birmingham"; "Why this way?"; "What's near me?" |

`?fixture=1` is a test affordance: it loads a recorded 1.2 km route in
Cambridge so **Drive the route** works with no voice session at all.

## What it calls

| Part | What it is |
| --- | --- |
| Voice | OpenAI Realtime over WebRTC (model `gpt-realtime` by default). Speech is transcribed in English, and turn-taking uses semantic voice activity detection, so a cough is less likely to count as a turn. |
| Tools | MapMap's hosted MCP server, `https://mcp.mapmap.ai/mcp`, attached to the session by the page's server so the browser cannot change it |
| Page tools | Ten tools the model calls in the browser, because they need the page's own state: `get_navigation_context`, `set_vehicle_profile`, `preview_route_change`, `confirm_route_change`, `cancel_route_change`, `start_drive`, `stop_drive`, `repeat_last_instruction`, `set_guidance_muted` and `clear_map` |
| Route previews | The hosted MapMap routing API through this site's demo key, car or truck, 2 to 4 locations |
| Guidance | MapMap's guidance engine (`GuidanceSession`, the engine in [`@mapmap/core`](/docs/sdks#core-wasm-mapmapcore)), compiled to WebAssembly and run in the page |
| Guidance speech | OpenAI text-to-speech for each engine phrase, cached; the browser's own speech when that is not available |

The MCP tools a session may call are read-only: `route`, `geocode`,
`plan_day`, `reachable_area`, `matrix`, `check_adr_tunnel`,
`search_along_route`, `verify_places`, `elevation`, `reverse_geocode`,
`nearby_places` and `cheapest_fuel_along_route`. The style-publishing and
feedback tools on the same server are never attached to a voice session.
What each tool does is in [MCP server](/docs/mcp#tools).

## What it will not say

The copilot's instructions put one set of rules first in every mode, and
no persona can override them:

- Every route, ETA, restriction, place, price or detour figure must come
  from a tool result or the drive's own state. If it has not looked
  something up, it does not know it. It reads place names, never
  coordinates.
- It speaks British English, and treats a transcript in another language
  as a mis-hearing. Places are assumed to be in the UK unless you say
  otherwise.
- A tunnel code means a dangerous-goods load. It never tells a driver a
  route is clear of tunnels or that a load is cleared to run; for a
  dangerous-goods route it says tunnels must be verified independently
  before dispatch.
- It never claims a traffic-aware ETA or that a route avoids incidents,
  and it has no camera and no view of the road.
- It changes the route only through a preview you agree to.

## Build your own

The copilot is a thin layer: a voice model, MapMap's MCP server as its
tools, and a few page tools for the state only your app holds. To build
the same thing:

**1. Give your voice model the MCP server.** Any model or agent framework
that takes a remote MCP server can call MapMap's tools: point it at
`https://mcp.mapmap.ai/mcp` ([recipes](/docs/agents)). This is the tool
entry the demo's server attaches to each Realtime session, with an API
key in place of the demo's own credential:

```json
{
  "type": "mcp",
  "server_label": "mapmap",
  "server_url": "https://mcp.mapmap.ai/mcp",
  "require_approval": "never",
  "authorization": "snk_…",
  "allowed_tools": [
    "route", "geocode", "plan_day", "reachable_area", "matrix",
    "check_adr_tunnel", "search_along_route", "verify_places", "elevation",
    "reverse_geocode", "nearby_places", "cheapest_fuel_along_route"
  ]
}
```

With your `snk_` key on the MCP connection, every metered call bills to
your account ([how](/docs/mcp#bill-metered-calls-to-your-own-key)); without
one, the hosted server answers for evaluation under fair use. Mint the
model's session on your server, as the demo does, so your OpenAI key never
reaches the browser.

**2. Keep state-changing actions in your app.** The demo's route changes
are page tools that return a proposal with the real time difference, and
only a separate confirm call commits one. The model never edits the route
itself.

**3. Guide the drive on the device.** The guidance engine is published:

- [`@mapmap/core`](/docs/sdks#core-wasm-mapmapcore) has `GuidanceSession`:
  build it from a route response and feed it location fixes. Version 0.4.0
  on npm ships a browser build as well as the Node one.
- [`@mapmap/maps`](/docs/sdks#turn-by-turn-guidance) turns a route's voice
  and banner instructions into steps, a banner and spoken prompts.
- [`@mapmap/voice`](/docs/sdks#voice-guidance-mapmapvoice-beta) (beta) is a
  fixed, multilingual phrasebook for turn-by-turn prompts, played from
  recorded clips. The copilot demo does not use it; it speaks the engine's
  own phrases.

**Run the demo itself.** The demo's source is available by email
([hello@mapmap.ai](mailto:hello@mapmap.ai)); it is not on npm. It needs
`OPENAI_API_KEY` (server-side only), and optionally
`OPENAI_REALTIME_MODEL` and `MAPMAP_MCP_URL` to point it at your own
[self-hosted MCP server](/docs/mcp#run-it-yourself).

## When it is not configured

A deployment without `OPENAI_API_KEY` shows "Demo not configured", the
prompts you would be able to say, and the self-hosting recipe, and its
session endpoint answers `503` with `not_configured`. The guidance voice
falls back to the browser's speech. Without the demo routing key, **Drive
the route** says driving is not available on that deployment rather than
drawing anything.

## Limits

- **A demo, not an API.** There is no hosted voice API, voice SDK or
  copilot package for customers. The page's own session endpoint serves
  this page; it is not a published API.
- **Your speech goes to OpenAI.** Voice runs on OpenAI Realtime, and the
  page says so under the controls. Routing, geocoding and ADR answers come
  from MapMap's MCP server.
- **English, in the UK.** Transcription is pinned to English, and places
  are assumed to be in the UK.
- **The drive is simulated.** Positions are synthesised along the route
  in the browser; the page does not read your device's location.
- **No live traffic.** ETAs and route times are not traffic-aware.
- **Short sessions.** A session ends after five minutes; start another to
  carry on. How many sessions can start from one address in an hour is
  limited.
- **Along-route searches are not among the suggested prompts.** You can
  still ask; the chips leave them out for now.

## Related

- [MCP server](/docs/mcp): connecting, tools, keys and billing
- [Use MapMap from any AI assistant](/docs/agents)
- [SDKs](/docs/sdks): `@mapmap/core`, turn-by-turn guidance in
  `@mapmap/maps`, and `@mapmap/voice`
- [Maps, tiles & Studio](/docs/maps)
- [MapMap Nav](/nav), the turn-by-turn app built on the same platform
