50,000 free calls a month, card-free. Get an API key →

news / mcp-server · raw .md
Agents7 min readMapMap engineering
A central hub node with twelve tool spokes radiating outward, each ending in a different geometric fitting.

Seventeen MCP tools, one URL, no key to connect

Note, updated 2 August 2026. The server exposed seventeen tools when this was written. It exposes 32 today. The tools named below are all still live; the list has grown since. See /docs/mcp for the current set.

MapMap ships an MCP server, sn-mcp, that exposes seventeen tools to any MCP client: routing, search along a route, day planning, reachability, ADR tunnel compliance, geocoding, matrix, optimisation, errand ordering, map correction, integration feedback and map styling, each with a full JSON Schema and a structured output. You can point an agent at the hosted endpoint https://mcp.mapmap.ai/mcp with no API key and no install, or run the same binary yourself over stdio or streamable HTTP against your own deployment. One of the seventeen, check_style_contrast, lets an agent audit the accessibility of a map it just designed, which is the part we think matters most.

What are the seventeen tools?

Seventeen tools, grouped by what they talk to. Coordinates are {lat, lon} objects rather than positional arrays, distances are metres and durations are seconds throughout.

ToolWhat it does
routeTurn-by-turn route, costing auto or truck. The truck profile {height_m, width_m, length_m, gross_weight_t, hazmat, tunnel_code} merges dimensional and ADR costing. Returns {distance_m, duration_s, summary, maneuvers[], geometry_polyline6, applied_adr}.
check_adr_tunnelThe ADR 8.6.4 tunnel-entry decision on its own: {tunnel_code?, hazmat, tunnel_category} returns decision, reason, explanation and the worst-case forbidden category list. No network, answers instantly.
geocodeForward geocoding: {query, limit?, focus?} returns candidates with name, label, lat/lon, type and address parts.
matrixMany-to-many travel matrix: {origins[], destinations[], costing, truck?} returns durations_s[i][j] and distances_m[i][j]. Null cells are unreachable pairs.
optimise_routesMulti-vehicle, multi-stop VRP over a matrix computed by our own engine, so costing truck means every optimised route respects dimensional and ADR restrictions. Fair-use cap: more than 200 unique locations returns a tool error asking you to split the problem.
order_stopsThe single-vehicle case, which is what agents actually ask for. start plus stops (1 to 100 entries of {location, label?, service_s?}), optionally an end or round_trip: true. Returns the stops in visit order with arrival offsets.
search_along_routePlaces along a route priced by the real extra travel time of stopping at each, never a straight-line guess. Returns candidates sorted by detour with detour_minutes, detour_km and an along-route position.
plan_dayTurns an itinerary into one navigable multi-stop route: geocodes free-text stop names, optionally reorders them with the VROOM solver, and returns per-leg times, arrival estimates and the full geometry.
reachable_areaReachability contours (isochrones) from an origin within one or more travel-time budgets, returned as a GeoJSON FeatureCollection, one feature per contour.
report_map_issueQueues a first-party map correction for review, never an automatic OSM edit: a located observation such as road_closed or wrong_speed_limit, appended to the deployment's review queue.
submit_integration_retroFiles a short retro after an integration session: what worked, what fought you. Delivered to the deployment's feedback queue so the platform improves from real agent experience.
list_style_layersLists every palette slot, skeleton layer id and source-layer a theme can restyle. Local lookup, no network, no configuration.
get_styleFetches a hosted style's latest theme document and compiled style URL. Public read, unmetered.
create_styleCreates a hosted style from a theme document (metered publish).
set_paletteRecolours a style by setting palette slots, published as a new immutable version (metered publish).
set_layer_paintOverrides one paint property on one layer, for example road width or opacity (metered publish).
check_style_contrastAudits a theme's palette against WCAG 2.1, across both light and dark variants. Pass a hosted style_id or an inline theme. Advisory only.

Invalid inputs and upstream failures come back as MCP tool errors with actionable messages, naming the exact environment variable to set where that is the cause, so an agent can correct itself rather than guess.

How does an agent connect?

Give it the URL. The hosted server speaks streamable HTTP at https://mcp.mapmap.ai/mcp, needs no key to connect and runs on fair use.

Claude Code:

sh
claude mcp add --transport http mapmap https://mcp.mapmap.ai/mcp

Claude Desktop, in claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):

json
{
  "mcpServers": {
    "mapmap": { "type": "http", "url": "https://mcp.mapmap.ai/mcp" }
  }
}

Cursor, in .cursor/mcp.json:

json
{
  "mcpServers": {
    "mapmap": { "url": "https://mcp.mapmap.ai/mcp" }
  }
}

Codex, in ~/.codex/config.toml:

toml
[mcp_servers.mapmap]
url = "https://mcp.mapmap.ai/mcp"

VS Code in Copilot agent mode uses .vscode/mcp.json with a servers key, and Windsurf uses ~/.codeium/windsurf/mcp_config.json with serverUrl. Both take the same URL. The MCP connection guide has the exact file for each, plus the Claude API MCP connector, which takes the URL directly with no local process at all.

To run it yourself, sn-mcp takes --transport stdio for a desktop client or serves streamable HTTP on port 8200 at /mcp under the self-host distro's mcp compose profile. Each upstream is one environment variable: VALHALLA_URL powers route, matrix, optimise_routes and order_stops, VROOM_URL powers the two optimisation tools, PHOTON_URL powers geocode, and STUDIO_URL powers the hosted style tools, with STUDIO_API_KEY needed only for the three publishes (style reads work without it). All are optional at startup. The server boots regardless and warns on stderr for each missing upstream, keeping stdout clean for the protocol.

Why is check_style_contrast the interesting one?

Because it closes a loop that was otherwise open: an agent could already design a map, but it could not tell whether anyone could read it. set_palette lets an agent recolour a style in one call. Nothing stopped it choosing mid-grey labels on a mid-grey landuse fill and publishing a map that looks fine in a thumbnail and is illegible at speed.

check_style_contrast gives the agent the same audit a designer would run. It takes a hosted style_id or an inline theme document (exactly one of the two, never both), resolves the palette and measures every audited pair against WCAG 2.1 thresholds:

Pair kindThresholdWCAG success criterion
text4.5:1SC 1.4.3 Contrast (Minimum), AA
graphics3:1SC 1.4.11 Non-text Contrast

The maths is implemented to the WCAG 2.1 definitions of relative luminance and contrast ratio, not approximated. Both the light and the dark palette are checked, because a theme carries both and a palette override that fixes one often breaks the other.

The output is shaped for an agent rather than a report reader:

json
{
  "passes": false,
  "findings": [
    {
      "variant": "dark",
      "kind": "text",
      "foreground": "textPrimary",
      "background": "background",
      "description": "place-label text on the map background (halo-free worst case)",
      "ratio": 3.12,
      "threshold": 4.5,
      "passes": false
    }
  ]
}

Failing pairs sort first, so the agent sees what to fix without scrolling. Each finding names the palette slots involved, which are the exact slots to pass back to set_palette. Generate a theme, audit it, correct the two slots that failed, publish. No human in the loop, and no human needed to notice the map was unreadable.

The audit is advisory by design. It never blocks a publish and it never fails a compile. We think a tool that refuses to ship your map because a boundary line missed 3:1 by a tenth would get routed around within a week, and an advisory one that agents actually call is worth more than a gate they learn to avoid.

What does it cost, and what is metered?

Most of it is not metered at all, because most of it never touches the gateway.

  • The routing, matrix, geocoding and optimisation tools talk directly to the engines inside your deployment (VALHALLA_URL, VROOM_URL, PHOTON_URL). Those calls are not API-key metered.
  • check_adr_tunnel, list_style_layers and check_style_contrast on an inline theme are fully local. They need no upstream and no network.
  • get_style is a public read and unmetered.
  • The three style publishes (create_style, set_palette, set_layer_paint) authenticate with STUDIO_API_KEY and meter against that key at the Standard price class: 0.05p per call, falling to 0.03p beyond 1M calls a month and 0.02p beyond 10M.

What does not work yet?

Four things, and you will hit them in this order.

The hosted endpoint is for evaluation, not production. It is live and open, but geocode and optimise_routes answer with tool errors until their upstreams are enabled on the hosted deployment, and order_stops needs the same VROOM solver so it behaves the same way. Style publishes are metered and may be unavailable. For production traffic, use the REST API with your own snk_ key, or run the server yourself.

The sn-mcp binary is not on a package registry. You build it from the source distribution (source access on request) or run it from the self-host distro's Docker image. There is no npx sn-mcp, and we are not going to pretend otherwise.

The HTTP /mcp endpoint is unauthenticated. Anyone who can reach the port can call every tool, including metered style publishes if STUDIO_API_KEY is set in the server's environment. Run it inside your trust boundary, restrict it by network policy or add auth at your reverse proxy, and terminate TLS there exactly as you would for the gateway. Pass --allowed-host (repeatable) in production so Host-header validation defends against DNS rebinding. Omit it and validation is off, and the server warns you at startup.

order_stops and check_style_contrast are newer than the rest. They landed after the original ten and the compose file still ships with VROOM_URL commented out, so order_stops is off until you uncomment the sidecar.

Try it

Add the hosted endpoint to your client with one command and ask your agent to plan a truck-legal route through the Dartford Crossing with a hazmat load. Full per-client setup, the environment-variable table and the self-host paths are in the MCP connection guide.

The tools are half the story. Agent skills carry the how-to knowledge that tools cannot, covering truck and ADR patterns, web SDK integration and migrating from Mapbox: see the agent skills write-up. For why we built the platform this way round, with the agent as a first-class caller rather than an afterthought, read maps for AI: what agent-native navigation requires. Everything an agent needs to find, price and key the platform without a human is on the agents page.

Routing derives from OpenStreetMap. Credit "© OpenStreetMap contributors" when you render or republish it.