google-maps-mcp
Provides read-only access to Google Maps for place search and details, opening hours, driving/walking/cycling travel times with traffic, turn-by-turn directions, multi-stop route planning and optimization, route matrices, and static map images with markers or route overlays.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@google-maps-mcp how long does it take to drive from San Francisco to Los Angeles right now?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
google-maps-mcp
A read-only MCP server that gives AI assistants Google Maps: how long it takes to get from A to B (driving with traffic, walking, cycling), turn-by-turn directions, multi-stop route planning, places with their opening hours, and map images, without an API key, billing or a Google account. It reads the same data the google.com/maps web page loads when you are signed out.
Results use the field names of Google's official Places API (New) and Routes API, so they read like those APIs' JSON. In clients that support MCP Apps (claude.ai, ChatGPT), routes and places are drawn as interactive cards.
Unofficial. Not affiliated with, endorsed or sponsored by Google. Automated access to google.com/maps is not covered by Google's terms of service: use it for personal, low-volume purposes, at your own risk (see Terms and limits).
Tools
Tool | What it returns | Google requests |
| Places like | 1 |
| One place by its id ( | 1 |
| Like | 1 |
| Like | 1 per pair |
| A multi-stop plan: the fastest order, arrival and leave time per stop, whether each stop is open on arrival, warnings | 1 + up to 5 candidate orders + 1 per stop for hours |
| The same plan as an interactive card | as |
| Place cards with photo, rating, open now, today's hours, holidays, links (including "Reserve"), and a pin map | 1 per place |
| A JPEG like the Static Maps API: an area, lettered pins and/or a route line; roadmap, satellite, hybrid or terrain | the lookups, plus about 10-25 map tiles |
| Daily budgets, breaker, last error; | 0 (or 3) |
Durations are Google's "<seconds>s" strings and distances are meters. Every key is present;
null means Google did not say. Stops are a name or address, a place id from
maps_search_places, or "lat,lng"; times are the local wall-clock time at the stop
(2026-10-29T08:30).
Opening hours. currentOpeningHours covers the next seven days with dates, so holiday
hours land on the right day: periods, weekdayDescriptions, openNow,
nextOpenTime/nextCloseTime (in the place's time zone), and holidays: the holiday Google
attaches to a date, with confirmed: false when Maps only says it "might affect these hours".
Reservations and menus. Where Google shows "Reserve a table", reservationLinks lists the
booking sites: [{"uri": "<the booking page>", "provider": "opentable.com"}], provider being the site's domain as Google names it (OpenTable,
TableCheck, SevenRooms, …), and [] when Google lists none. menuUri is the menu link, or
null. Search results carry them too, at no extra request. Only http(s) links are kept, and
the parameters that merely attribute the visit to Google (rwg_token, utm_*, gclid,
gbraid, wbraid) are removed; everything else, including a site's own src= or ref=,
stays as Google gave it, since it can select the venue or the booking flow. A link says where
to book, not that a table is free.
Turn-by-turn. includeSteps adds Routes API steps per leg (navigationInstruction
{maneuver, instructions} such as "Turn left onto Gertrude-Fröhlich-Sandner-Straße",
distance, time, start point, plus notices like "Toll road") and the grouped segments Maps
lists ("Get on A4"). maneuver is Google's own code where the step carries one (ON_RAMP,
MERGE, ROUNDABOUT_…, TURN_SLIGHT_RIGHT); it is never guessed from the text.
Multi-stop planning. Google's web directions cannot reorder waypoints and a full
travel-time matrix costs a request per pair, so maps_plan_route ranks every order of the
stops by straight-line length, routes the four shortest plus the order given with real Google
directions, and keeps the fastest (savedVsGivenOrder says what that saved). Stays
(dwellMinutes) and traffic shift the arrival times; each stop's openingStatus is open,
closes_during_visit, closed or unknown.
Cards. maps_show_route and maps_show_places return their facts to the model, and MCP
Apps hosts draw them with ui://maps/view.html (src/maps_mcp/view.html): a map built from
Google Maps tiles in your browser (drag, zoom, map/satellite, fit) with the route and lettered
pins, a stop timeline with arrival times and open/closed status, steps per leg and "Open in
Google Maps"; or place cards with photo, rating, today's hours and links. The route line,
steps and photos travel in the result's _meta, so they do not fill the model's context. The
view loads only from www.google.com and lh3-6.googleusercontent.com, connects nowhere, sets
every text as text and opens links through the host.
Related MCP server: Google Maps MCP Server
Quick start
Docker (HTTP)
docker run -d --name maps-mcp -p 127.0.0.1:8000:8000 \
-e MCP_BEARER_TOKEN="$(openssl rand -hex 32)" \
--read-only --tmpfs /state:uid=1000 \
ghcr.io/benjamin-di/google-maps-mcp:latestThe MCP endpoint is http://127.0.0.1:8000/mcp (stateless streamable HTTP with JSON replies)
with Authorization: Bearer <token>; /health is open. MCP_BEARER_TOKEN may hold several
tokens separated by commas. For claude.ai or ChatGPT, put it behind HTTPS with a reverse proxy
they can reach. Mount a volume on /state to keep the daily budgets and breaker across
restarts.
stdio (Claude Desktop, Claude Code, Codex)
# from PyPI, with uv (https://docs.astral.sh/uv/)
claude mcp add maps -- uvx google-maps-keyless-mcp --transport stdio
# from a checkout
claude mcp add maps -- uv --directory /path/to/google-maps-mcp run maps-mcp --transport stdio
# or with Docker
claude mcp add maps -- docker run -i --rm --tmpfs /state:uid=1000 ghcr.io/benjamin-di/google-maps-mcp:latest --transport stdioOutside Docker, state goes to $XDG_STATE_HOME/google-maps-mcp (else
~/.local/state/google-maps-mcp); set MAPS_STATE_DIR to put it elsewhere.
Build the image yourself
The image is two stages: the pinned dependencies (Dockerfile.deps) and the source on top.
docker build -f Dockerfile.deps -t maps-mcp-deps .
docker build -t google-maps-mcp .Command line
maps-mcp [--transport http|stdio] [--host 127.0.0.1] [--port 8000]: HTTP (the default)
listens on 127.0.0.1:8000 (or $MAPS_HOST) and requires MCP_BEARER_TOKEN; the image sets
MAPS_HOST=0.0.0.0.
Use as a library
Other Python programs can search places and read them without MCP, through the same service, pacing (one request at a time), daily budget, breaker, cache and errors as the server:
from maps_mcp.places import MapsError, PlacesClient
async with PlacesClient(state_dir="/var/lib/myapp/maps", daily_request_budget=200, budget_tz="Europe/Vienna") as maps:
found = await maps.search_places("Steirereck, Vienna", page_size=1)
place = await maps.get_place(found["places"][0]["id"])
for link in place["reservationLinks"]:
print(link["provider"], link["uri"])PlacesClient(*, state_dir=None, daily_request_budget=1000, budget_tz="UTC", language="en", min_interval_s=1.0, request_timeout_s=15.0): settings come from these arguments only, never fromMAPS_*variables; out-of-range values raiseConfigError. Withoutstate_dir, state goes to the per-user state directory. Use one client per process and give each process its own state directory (the budget file is not shared safely between processes; pacing is per process).await search_places(text_query, *, latitude=None, longitude=None, radius_meters=None, page_size=5)returns{"places": [...]}exactly asmaps_search_places;await get_place(place_id)returns one place exactly asmaps_get_place(ChIJ…or0x…:0x…).status()returns the budget, breaker and last error without a request;aclose()(orasync with) closes the connection.Every failure raises
MapsErrorwithcode(one ofERROR_CODES, the table under Terms and limits),retryableandnext_step.
Stability: maps_mcp.places (PlacesClient, MapsError, ConfigError, ERROR_CODES,
RETRYABLE_CODES) and the place fields follow semantic versioning from 0.6.0: a minor release
may add fields, error codes or optional arguments; removing or changing one needs a major
release. Other modules are internal. Pin google-maps-keyless-mcp>=0.6,<1.
Configuration
Variable | Default | Meaning |
| (required for HTTP) | Accepted bearer token(s), comma-separated, each at least 32 characters |
|
| HTTP listen address when |
| per-user state dir (image: | Budgets, breaker, Google's consent cookies |
|
| Requests to google.com per day, all tools together |
|
| Map tiles per day for |
|
| The time zone whose midnight resets the budgets |
|
| Minimum seconds between requests (jittered ±30%) |
|
| Per-request timeout |
|
| Language of names and instructions |
| Wien Hauptbahnhof / Albertina | The status check's walk; |
|
| JSON log lines on stderr; tool arguments are never logged, only short hashes |
How it works
Four endpoints on www.google.com, the ones google.com/maps itself calls: /search?tbm=map
(search), /maps/preview/place (place details), /maps/preview/directions (routes, steps
and geometry) and /maps/vt (map tiles). Requests carry no account and no key; Google's
consent cookies are fetched once and kept in the state directory. Parsing comes from
gmaps-scraper, vendored in
src/maps_mcp/vendor/gmaps from a fork that adds this project's contributions, each offered
upstream as a pull request (see NOTICE). Upstream has been inactive since July 2026, so we maintain
that fork: its pull requests stay open as offers, and no new ones are opened until upstream responds.
Refresh the vendored copy with scripts/vendor-gmaps.sh; never edit it by hand.
It is a deliberately small, polite client: one request at a time, about one a second, daily
budgets, results cached in memory (places 6 h, walking and cycling routes 12 h, driving
10 min, or 1 h for a given time), and a breaker that stops all requests for 30 min, then 2 h,
then 8 h when Google answers 429, /sorry or a sign-in wall.
Terms and limits
Google's terms of service do not allow automated access to google.com/maps. This project is for personal, low-volume use; you are responsible for how you use it. If you need guarantees, use Google's paid Maps Platform APIs.
Do not store or redistribute Google's place data, and keep Google's attribution ("Map data © Google") with maps, as the cards and images do.
Google can change its page format at any time. Parsing failures surface as
schema_changed, never as wrong numbers; please open an issue.No walking or driving routes in South Korea (Google's own limit:
condition: ROUTE_NOT_FOUNDwith a note). Data in mainland China is thin. Opening hours are Google's: a good secondary source, not proof.
Error code | Meaning |
| Google pushed back; the breaker is open ( |
| Google's response format changed; the tool cannot read it |
| Network or Google failed after retries |
| The stop, the place id or a route could not be found; the message says which |
| as named |
Development
make bootstrap # uv sync
make check # ruff, format, lock consistency, testsTests never reach Google: the vendored library runs against responses recorded from
google.com/maps (tests/fixtures, recorded and scrubbed by scripts/capture-fixtures; see
tests/fixtures/README.md). tests/test_safety.py guards the boundary: the only host is
www.google.com, and the card view loads only from its declared hosts and connects nowhere.
Contributions: see CONTRIBUTING.md; security problems: SECURITY.md.
Credits
Built on gmaps-scraper (MIT). The directions
request layout was first documented by
ai-ecoverse/skills (skills/gmaps). See NOTICE and
THIRD_PARTY_NOTICES. Licensed under the MIT licence (LICENSE).
Available Tools
9 toolsmaps_compute_routeMaps Compute RouteBRead-onlyIdempotent
Travel time and distance through the stops in order (Routes API computeRoutes shape): {travelMode, routes: [{description, distanceMeters, duration, staticDuration, localizedValues, durationWithoutTraffic, durationRange, departureTime, arrivalTime, legs: [{distanceMeters, duration, staticDuration, startLocation, endLocation, localizedValues}]}], waypoints: [{query, displayName, formattedAddress, placeId, location}], googleMapsUri, condition, note}. duration is in traffic for DRIVE (now or at departureTime/arrivalTime), otherwise typical. includeSteps fills legs[].steps [{distanceMeters, staticDuration, startLocation, navigationInstruction {maneuver, instructions}, localizedValues, notices}] and legs[].segments [{instructions, distanceMeters, staticDuration, firstStepIndex, stepCount}]; includePolyline fills routes[].polyline {encodedPolyline}.
Inputs: origin (required), destination (required), travelMode, arrivalTime, +5 more. Returns: object
maps_compute_route_matrixMaps Compute Route MatrixARead-onlyIdempotent
Duration and distance for every origin x destination pair, at most 25 pairs; each pair is one Google request (Routes API computeRouteMatrix element shape): {travelMode, elements: [{originIndex, destinationIndex, status, condition, distanceMeters, duration, staticDuration, localizedValues}]}. Identical origin and destination cost nothing.
Inputs: origins (required), destinations (required), travelMode, departureTime. Returns: object
maps_get_placeMaps Get PlaceARead-onlyIdempotent
One place by id (Places API Place shape, same fields as maps_search_places), with currentOpeningHours for the next 7 days: dated periods, weekdayDescriptions, openNow, nextOpenTime/nextCloseTime and holidays, plus reservationLinks [{uri, provider}] and menuUri.
Inputs: id (required). Returns: object
maps_plan_routeMaps Plan RouteCRead-onlyIdempotent
Plan a multi-stop route: {travelMode, optimized, order (indices of stops in the chosen order), ordersCompared, savedVsGivenOrder, description, distanceMeters, duration, durationWithDwell, departureTime, arrivalTime, timeZone, stops [{label, role, inputIndex, query, displayName, formattedAddress, placeId, location, arrivalOffset, arrivalTime, dwellMinutes, departureTime, openingStatus {state, text, hours}, rating, category}], legs [{from, to, distanceMeters, duration, staticDuration}], warnings, googleMapsUri}. Without departureTime the plan starts now.
Inputs: stops (required), origin (required), roundTrip, travelMode, +4 more. Returns: object
maps_search_placesMaps Search PlacesBRead-onlyIdempotent
Find places like Google Maps search (Places API searchText shape): {places: [{id, displayName, formattedAddress, location, googleMapsUri, primaryTypeDisplayName, categories, rating, userRatingCount, internationalPhoneNumber, nationalPhoneNumber, websiteUri, priceLevel, priceRangeText, timeZone, currentOpeningHours, hoursStatusText, reservationLinks [{uri, provider}], menuUri}]}. reservationLinks are the booking sites Google lists (provider: the site's domain, e.g. sevenrooms.com), empty when none. Put the city in textQuery or pass latitude/longitude.
Inputs: textQuery (required), latitude, pageSize, longitude, +1 more. Returns: object
maps_show_placesShow placesARead-onlyIdempotent
Show places to the person as cards: photo, rating, category, open now, today's hours, holiday notices, address, phone, website, reserve, directions and Map links, your note, plus a map with lettered pins (claude.ai and ChatGPT draw them). Use it whenever you recommend or compare places; ids come from maps_search_places.
Inputs: items (required), title.
maps_show_routeShow routeARead-onlyIdempotent
Show a route to the person as a card: interactive map with the route and lettered pins, total time and distance, the stops with arrival times and open/closed status, turn-by-turn steps per leg, and an "Open in Google Maps" button (claude.ai and ChatGPT draw it). Same facts as maps_plan_route. Use it whenever you give directions or a route.
Inputs: origin (required), note, title, roundTrip, +6 more.
maps_static_mapMaps Static MapARead-onlyIdempotent
A map image like the Static Maps API: an area (center + zoom), pins and/or a route line, drawn on Google Maps tiles. Without center or zoom the view fits the pins and route. Returns a JSON legend {center, zoom, size, maptype, markers [{label, query, displayName, location, …}], route {travelMode, condition, description, distanceMeters, duration, googleMapsUri}, missingTiles, attribution} and the JPEG.
Inputs: size, zoom, route, center, +2 more.
maps_statusMaps StatusARead-onlyIdempotent
Version, daily request and tile budgets left, breaker, last error and cache size. With check=true, also {canary: {ok, code, checked_at, cached}}: one real route, one place read and one map tile, cached 55 min (5 min after a transient failure); ok is false on any error. Never fails.
Inputs: check. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 9 tools
Most tools map to distinct operations, but maps_compute_route and maps_plan_route both compute multi-stop travel times with substantially overlapping output fields, and maps_show_route is explicitly described as carrying the 'same facts as maps_plan_route,' so an agent can easily pick the wrong one when it only needs data or only needs a card. The descriptions do provide guidance ('Use it whenever you give directions'), which keeps this from being worse than moderate overlap.
All tools share a consistent maps_ prefix and mostly follow verb_noun (get_place, search_places, compute_route, plan_route, show_places). The only deviations are the noun-only maps_static_map and maps_status, which are minor and still unsurprising.
Nine tools is well within a comfortable range and each one earns its place: place lookup/search/rendering, route compute/plan/render, a matrix variant, a static image, and diagnostics. No obviously redundant or filler tools.
The surface covers the core Maps workflows: place discovery and detail, routing (single, multi-stop with optimization and dwell), pairwise matrices, map imagery, and a health/budget check. Minor gaps remain, such as address geocoding/autocomplete as first-class operations and route alternatives, but agents can work around these via textQuery search.
Maintenance
Related MCP Connectors
Routing, geocoding, places, matrix and map tools for location-aware AI workflows.
Render static locator maps (area highlight, places, routes) and search places from AI assistants.
Location tools for Claude and other MCP clients, strongest in the US and Great Britain. Geocode whole lists with a confidence score per row, filter by distance, get road distances and drive-time areas, and plan multi-driver routes with Google Maps links. Check flood zones, crime and live warnings, find nearby places and UK registers (NHS, CQC, food hygiene), and keep shareable maps. Reads and writes Google Sheets. Free: sign in with Google.
Google Maps routes, ETAs, and turn-by-turn steps via the Apify Directions API, hosted MCP.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables location-aware AI agents to search for nearby places, get detailed place information including hours and ratings, and calculate routes with turn-by-turn directions using Google Maps APIs.22MIT
- AlicenseAqualityDmaintenanceEnables AI assistants to access Google Maps services including places search, details, directions, geocoding, and nearby search through natural language.62MIT
- AlicenseNot gradedqualityCmaintenanceProvides geocoding, place search, directions, distance matrix, and elevation data from Google Maps. Enables natural language queries to locate places, get directions, and retrieve map-related information.148 npmMIT
- AlicenseAqualityCmaintenanceProvides AI agents with structured search results, place details, ratings, and contact info from Google Maps without requiring any API keys.22MIT