gmaps-mcp
Provides tools for searching Google Maps businesses with full profiles, looking up individual places, and getting travel directions with duration and distance for driving, bicycling, walking, and transit.
Click on "Install 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., "@gmaps-mcpfind Italian restaurants in Chicago"
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.
gmaps-mcp
A free Google Maps toolkit, in pure Python, no API key. It hits
Google's own internal endpoints directly — no headless browser — for
business search, single-place lookup, and multi-mode travel directions.
Ships as a CLI (gmaps) and as an MCP server (gmaps-mcp) so any
MCP-capable coding tool can pull Google Maps data straight into a
conversation.
Search and lookup extract full business profiles with asyncio concurrency and export to JSON + CSV; directions returns travel duration and distance between two places. Built to be the strong, fast, self-hosted option — see Roadmap for where this is headed.
Features
Business search & lookup
No API key, no paid service — direct
tbm=mapprotobuf-over-JSON requests.Full profile data per business: name, rating, categories, address (split into street/city/state/postal/country), coordinates, phone, website, operating hours, description, plus code, status (open/closed), attributes (women-led, LGBTQ+ friendly…), photos + thumbnail, derived CID, reviews link, Street View link, Google Maps link.
Free-endpoint limits (honest nulls): review count, price range, reservation/ordering links, owner-claimed flag and payment info are not exposed by Google's free endpoints — stored empty rather than guessed.
Website enrichment: crawls each business's site (deduped by domain) for email addresses and social links (Instagram, Facebook, X/Twitter, LinkedIn, TikTok, YouTube).
Concurrency via asyncio (parallel requests + retries + backoff).
Pagination, whole-country sweep on a lat/lng grid, multi-keyword passes (deduped by feature id), single-entity lookup by feature id / Google Maps URL / name.
JSON + CSV output with normalized fields — machine CSV for scripts, a separate human-readable summary CSV alongside it.
Directions
Travel duration + distance between two places: driving, bicycling, walking, transit — all real, no API key (flying is a separate Google product, not available here).
MCP server (gmaps-mcp): search, lookup and directions tools, same data.
Related MCP server: Google Maps MCP Server
Install
python3 -m venv .venv && source .venv/bin/activate
pip install -e .Optional extras:
pip install -e ".[socks]" # SOCKS proxy support (--proxy socks5://...)
pip install -e ".[mcp]" # the gmaps-mcp server
pip install -e ".[dev]" # tests (pulls in [mcp] too, see Development)MCP server — connect it to your coding tool
gmaps-mcp runs over stdio and exposes three tools: search (keywords,
optionally swept over a country/bbox grid), lookup (one place by
feature id / Google Maps URL / name), and directions (travel duration
between two places — all ground modes, with distance for driving/transit;
see the note below).
Install the package first — pip install -e ".[mcp]" (above). The
gmaps-mcp binary must already be on PATH (or callable via python -m gmaps.mcp_server) before any of the steps below will work: none of these
commands install gmaps-mcp itself, they only register an already-installed
binary with the tool's own config so it knows to launch it.
Claude Code — one line, no file editing:
claude mcp add gmaps -- gmaps-mcp(add --scope user to make it available in every project, not just this one)
Codex CLI:
codex mcp add gmaps -- gmaps-mcpor in ~/.codex/config.toml:
[mcp_servers.gmaps]
command = "gmaps-mcp"Cursor — .cursor/mcp.json (project) or ~/.cursor/mcp.json (global):
{ "mcpServers": { "gmaps": { "command": "gmaps-mcp" } } }DeepSeek Harness (dsh) — MCP servers are mounted as patches in
~/.dsh/profiles/web/cordis.patch.yml:
- insert:
- id: mcp-gmaps
name: '@deepseek-ai/dsh-mcp-client'
config:
serverName: gmaps
transport: stdio
command: gmaps-mcpRestart dsh after saving (dsh web --dump-config | grep -A3 mcp to
confirm it loaded).
OpenCode — add under mcp in your OpenCode config (opencode.json /
opencode.jsonc):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"gmaps": { "type": "local", "command": ["gmaps-mcp"] }
}
}Hermes Agent:
hermes mcp add gmaps --command gmaps-mcpor directly in ~/.hermes/config.yaml:
mcp_servers:
gmaps:
command: gmaps-mcpThen hermes mcp test gmaps to confirm, or /reload-mcp in a running session.
Directions (travel duration + distance between two places)
gmaps --directions "ORIGIN" "DEST" (CLI) and the directions MCP tool
return travel duration for driving, bicycling, walking and transit,
plus real distance for driving and transit — no API key. Under the
hood this queries Google's internal directions endpoint twice, in two
different request shapes, because they aren't interchangeable: one gives
duration for all four ground modes on a consistent, toll-averse route,
but its transit entry is commonly empty; the other gives real distance +
duration for driving and transit (transit's includes actual
departure/arrival times), but its driving route can include tolls — a
different physical route than the first shape's, confirmed live, not
a rounding difference. Because of that: driving's duration always comes
from the consistent (toll-averse) shape, matching bicycling/walking;
driving's distance is added from the other shape only when available,
flagged distance_route_may_differ: true so it's never presented as
describing the exact same trip as the duration. Transit comes entirely
from the distance-carrying shape (no mixing). Flying is not
available — it's a separate Google Flights product, not part of this
endpoint at all, and a null there says nothing about whether a flight
actually exists.
gmaps --directions "Paris, France" "Zurich, Switzerland"CLI usage
# single keyword, full Google Maps profile, save JSON+CSV (default: no website crawl)
gmaps "pizza in Berlin" --out leads
# optionally crawl each business's website for emails + social links
gmaps "pizza in Berlin" --website --out leads_with_contacts
# add emails + socials to an EXISTING results JSON (no Google re-scrape)
gmaps --enrich-file leads.json --out leads_contacts
# faster: skip place-detail enrichment (search fields only)
gmaps "pizza in Berlin" --no-enrich
# 3 pages (≈60 results) of one query
gmaps "restaurants in Berlin" --pages 3
# sweep a whole country on a 30km grid
gmaps "dentist" --country DE --spacing 30 --out germany_dentists
# long sweep: write a partial <out>.checkpoint.json every 50 cells,
# so an interruption never loses the whole run
gmaps "dentist" --country DE --spacing 30 --checkpoint-every 50 --out germany_dentists
# custom bounding box (min_lat min_lng max_lat max_lng)
gmaps "cafe" --bbox 48.0 11.0 49.0 13.0 --spacing 15
# multi-keyword: several terms in one pass, deduped by feature id
gmaps "pizza" --keywords "kebab" "italian restaurant" --out multi_food
# single-entity lookup: full profile by feature id / maps URL
gmaps --lookup "0x47a8...:0x4bff..."
# ... or top-5 candidates by name (disambiguate, then look up by fid)
gmaps --lookup "Joyería Serrano" --top-n 5
# list supported countries
gmaps --list-countries
# tune concurrency / optional proxy (SOCKS needs the [socks] extra, see Install)
gmaps "barber" --country FR --concurrency 8 --proxy socks5://127.0.0.1:1080Run as a module if you prefer: python -m gmaps "pizza in Berlin".
Output
<out>.json — array of full records.
<out>.csv — flat table with columns for every field plus one per social network.
<out>.summary.csv — human-oriented table (written alongside, same rows):
name first, split street/city/state/postal_code/country,
compact hours plus a separate closed_days column, rounded coordinates,
machine ids (query, google_maps_url) at the end. Semicolon-delimited,
plain UTF-8 (no BOM): spreadsheets in comma-decimal locales (FR/DE/MA...)
split CSV on ; and would show a comma file as one column; a comma file
is still written by the machine export above.
Every record carries google_maps_url (a working link to the place).
The machine <out>.csv layout is stable for scripts; the summary is meant to
be read.
Repository structure
gmaps-mcp/
├── src/gmaps/
│ ├── cli.py argument parsing + orchestration (the `gmaps` command)
│ ├── __main__.py thin entry point (python -m gmaps)
│ ├── mcp_server.py the `gmaps-mcp` entry point: search + lookup + directions tools
│ ├── config.py shared headers, user-agent, endpoint URLs, constants
│ ├── client.py async HTTP client (retries, circuit breaker, proxy validation)
│ ├── pb.py protobuf field-selector construction (search, detail, directions)
│ ├── parser.py schema-tolerant structural parser for the protobuf JSON
│ ├── models.py Place / SearchResult dataclasses
│ ├── pipeline.py concurrency, pagination, enrichment, grid sweeps, lookup, directions
│ ├── grid.py country bounding boxes + lat/lng grid
│ ├── webenrich.py website crawl for emails + socials (deduped by domain)
│ └── export.py JSON + CSV writers (machine CSV + human summary CSV)
├── tests/ pytest suite — parser, grid, export, pipeline, features,
│ mcp, directions; all offline (fixtures, stub clients, in-process MCP calls)
├── data/ your scraped output lands here (gitignored)
├── .github/workflows/ CI: install + full suite on Python 3.10–3.12
├── AGENTS.md invariants and gotchas for anyone editing this codebase
├── CONTRIBUTING.md ground rules for contributions
├── llms.txt machine-readable project index (llms.txt v2 spec)
├── pyproject.toml package metadata, dependencies, entry points
├── requirements.txt plain pip-freeze-style mirror of pyproject's deps
└── LICENSE MITDisclaimer — this is gray-zone scraping
This project queries https://www.google.com/search?tbm=map and
https://www.google.com/maps/preview/place — internal, undocumented
Google endpoints, not a published or licensed API. There is no API key
because there is no API: this is the same request your browser makes when
you use Google Maps, replayed programmatically. That distinction matters:
Google's Terms of Service generally prohibit automated access to their services outside of the official APIs. Using this tool may violate those terms; Google can and does rate-limit or block IPs it identifies as scraping (the client's circuit breaker exists because of this, not despite it).
The endpoints are unstable by design — they can change shape, require new headers, or disappear without notice, because Google owes no backward compatibility to a request format it never published.
Data protection law varies by jurisdiction. Business listings are generally public information, but what you may collect, store, and do with scraped personal data (an owner's name in a listing, a phone number) depends on where you and your data subjects are — GDPR, CCPA, and similar regimes may apply.
This is not legal advice. Review the copyright/ToS/data-protection position for your jurisdiction and use case before scraping at any scale. The authors and contributors accept no liability for how this tool is used; see
LICENSE(MIT — provided as-is, no warranty).
If you need guaranteed uptime, an SLA, or unambiguous legal footing, use Google's official Places API instead — it costs money precisely because it buys you those things.
Development
See CONTRIBUTING.md for the ground rules (tests-first, fixtures from real bodies, honest nulls, flag threading).
pip install -e ".[dev]" # install package + pytest (pulls in the mcp extra too)
python -m pytest tests/ -q # run the test suite (72 tests, all offline)Architecture
See Repository structure above for what each file
does. AGENTS.md documents the invariants that aren't obvious from reading
any single file — read it before making structural changes.
Roadmap
Search, lookup and directions all sit on the same family of Google Maps internal endpoints — the pattern for adding a capability here is consistent: find the request shape via a real browser session, confirm it live against several inputs (never trust one), write a structural parser, ship honest nulls for whatever the free endpoint doesn't expose. Natural next additions on that same pattern, roughly in order of how well-trodden the endpoint already looks from this session's exploration:
Geocoding / reverse geocoding — address ↔ coordinates, no full business lookup needed. Likely a thin wrapper around the same place-resolution step
search/lookupalready do.Elevation — a single lat/lng in, a height out; small, self-contained.
Place photos & reviews at scale —
lookupalready returns photo URLs and areviews_link; a dedicatedreviewstool exists at the client layer (MapsClient.reviews) but isn't wired into MCP/CLI yet.Distance for bicycling/walking — currently duration-only (see Directions above); the request shape that carries distance for driving/transit doesn't carry these two modes at all, so this needs a genuinely different endpoint angle, not just a tweak.
Batch directions (many origins → one destination, or a matrix) — useful for "which of these N places is closest," built on top of the existing single-pair
directionsrather than replacing it.
None of these are promised or scheduled — this list exists so a
contributor (human or agent) doesn't have to rediscover where the natural
seams are. See CONTRIBUTING.md for how a new capability should be built
here: tests first, fixtures from real captured bodies, honest nulls.
How it works (briefly)
Google Maps search can be queried at https://www.google.com/search?tbm=map
which returns a large nested JSON array (protobuf-over-JSON) prefixed with an
anti-XSSI marker. Each business is a sub-array anchored on a feature id like
0x47a8...:0x4bff.... The parser decodes the JSON once and then walks the
tree, extracting fields structurally (rather than by brittle fixed indices
or regexes over the raw dump), so it survives schema shifts AND JSON escaping
(names with quotes or accents). Coordinates are embedded in the pb parameter
to pin the map viewport, and pagination is done by incrementing the !8i
offset.
Notes & risks
review_count is not available through the free protobuf endpoints from a residential IP: the
tbm=mapsearch response omits it, the place-detail response omits it, and the reviews endpoint returns 404 for unauthenticated requests. The scraper reports it honestly as null rather than guessing. To capture review counts, feed thefeature_id/google_maps_urlinto a browser renderer (the count is shown on the place HTML page).This works from a residential IP; Google may rate-limit heavy use. The client includes a circuit breaker (pauses after repeated 403/429/503 blockages; timeouts and other errors retry without tripping it) and capped exponential backoff. Use
--concurrency/--respect-delaysensibly for very large sweeps.Proxies: pass a URL string (
--proxy socks5://host:1080). SOCKS additionally needs the[socks]extra; the scraper validates this up front and exits with an install hint instead of failing mid-sweep.The protobuf schema changes over time; the structural parser is designed to degrade gracefully (missing fields stay null) rather than crash. Hours are parsed from locale-dependent weekday blocks (Spanish
lunesand EnglishMondayalike); descriptions only when Google actually publishes an editorial summary for the place — ad lines, internal ids and UI labels are excluded, and a missing description stays null rather than being guessed.The place-detail parser is ad-proof: it skips third-party booking domains (Booking.com, Expedia, OpenTable...) for websites and takes the most-frequent phone, so ad data never leaks into a business record.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Live Google Maps business search, review, and photo data for AI agents over MCP.
Ground your AI applications with trusted geospatial data from Google Maps.
The Google Maps MCP server is a fully-managed server provided by the Maps Grounding Lite API that connects AI applications to Google Maps Platform services. It provides three main tools for building LLM applications: searching for places, looking up weather information, and computing routes with details like distance and travel time. The server acts as a proxy that translates Google Maps data into a format that AI applications can understand, enabling agents to accurately answer real-world location and travel queries.
Give AI assistants access to real-time data. Search the web, compare flights, find hotels, and more.
Related MCP Servers
- AlicenseAqualityBmaintenanceEnables AI assistants to access Google Maps services including places search, details, directions, geocoding, and nearby search through natural language.62MIT
- AlicenseNot gradedqualityDmaintenanceEnables interaction with Google Maps API for geocoding, place search, directions, distance matrices, and elevation data through natural language.MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to search and scrape Google Maps places data (name, rating, address, etc.) directly without an API key.
- 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.13MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/reveredyvs/gmaps-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server