A TypeScript Model Context Protocol (MCP) server that exposes Google Maps Platform APIs as tools for LLMs. Gives AI assistants real, structured map data — directions, transit routes, place search, address validation, photos, elevation, and more — instead of guessing from training data. Works with Claude Desktop and any other MCP-compatible client. 15 tools across three categories: Transport: HTTP
Add this skill
npx mdskills install apurvaumredkar/google-maps-mcpComprehensive MCP server exposing 15 Google Maps APIs with excellent documentation and multiple deployment options
A TypeScript Model Context Protocol (MCP) server that exposes Google Maps Platform APIs as tools for LLMs. Gives AI assistants real, structured map data — directions, transit routes, place search, address validation, photos, elevation, and more — instead of guessing from training data.
Works with Claude Desktop and any other MCP-compatible client.
15 tools across three categories:
| Category | Tools |
|---|---|
| Maps | Static map image URL, embed URL (iframe), elevation data, Street View image URL |
| Routes | Turn-by-turn directions (drive/walk/cycle/transit), distance matrix, multi-stop route optimization |
| Places | Geocoding / reverse geocoding, place details, text search, nearby search, autocomplete, photos, address validation, timezone |
Transport: HTTP Streamable (stateful sessions, SSE keep-alive) — the modern MCP transport, compatible with mcp-remote and all HTTP-capable clients.
Minimal footprint: only two runtime dependencies (@modelcontextprotocol/sdk, zod). All Google Maps calls use Node.js built-in fetch against REST APIs — no Google SDK required.
Go to APIs & Services → Library and enable:
| API | Used by |
|---|---|
| Maps Static API | maps_static_map |
| Street View Static API | maps_street_view |
| Maps Embed API | maps_embed_url |
| Elevation API | maps_elevation |
| Geocoding API | places_geocode |
| Time Zone API | places_timezone |
| Places API (New) | places_details, places_text_search, places_nearby_search, places_autocomplete, places_photos |
| Address Validation API | places_address_validation |
| Routes API | routes_compute, routes_matrix |
| Route Optimization API | routes_optimize (optional) |
You can restrict the key to these APIs and to your server's IP for production use.
docker run -d \
--name google-maps-mcp \
-p 127.0.0.1:3003:3003 \
-e GOOGLE_MAPS_API_KEY=your_key_here \
-e MCP_AUTH_TOKEN=your_secret_token \
ghcr.io/apurvaumredkar/google-maps-mcp:latest
Verify:
curl http://localhost:3003/health
# {"status":"ok","service":"google-maps-mcp"}
No install required — run directly with npx:
GOOGLE_MAPS_API_KEY=your_key_here \
MCP_AUTH_TOKEN=your_secret_token \
npx mcp-server-google-maps
# google-maps-mcp listening on port 3003
Or install globally:
npm install -g mcp-server-google-maps
GOOGLE_MAPS_API_KEY=your_key_here MCP_AUTH_TOKEN=your_secret_token mcp-server-google-maps
Set PORT= to change the default port (3003).
git clone https://github.com/apurvaumredkar/google-maps-mcp.git
cd google-maps-mcp
npm install
npm run build
Create a .env file (or export the vars):
GOOGLE_MAPS_API_KEY=your_key_here
MCP_AUTH_TOKEN=your_secret_token
# Optional — only needed for routes_optimize:
GOOGLE_CLOUD_PROJECT_ID=your_project_id
Start the server:
GOOGLE_MAPS_API_KEY=... MCP_AUTH_TOKEN=... npm start
# google-maps-mcp listening on port 3003
Add to your docker-compose.yml:
services:
google-maps-mcp:
build: .
container_name: google-maps-mcp
restart: unless-stopped
ports:
- "127.0.0.1:3003:3003"
environment:
- GOOGLE_MAPS_API_KEY=${GOOGLE_MAPS_API_KEY}
- MCP_AUTH_TOKEN=${MCP_AUTH_TOKEN}
- GOOGLE_CLOUD_PROJECT_ID=${GOOGLE_CLOUD_PROJECT_ID:-}
| Variable | Required | Description |
|---|---|---|
GOOGLE_MAPS_API_KEY | Yes | Your Google Maps Platform API key |
MCP_AUTH_TOKEN | No | Secret token clients must send in the X-Api-Key header. Omit for local-only use; set when exposing the server over a network or proxy. Generate with openssl rand -hex 32 |
PORT | No | HTTP port (default: 3003) |
GOOGLE_CLOUD_PROJECT_ID | No | Required only for routes_optimize (Route Optimization API) |
The server exposes a single endpoint: POST/GET http://localhost:3003/mcp
If MCP_AUTH_TOKEN is set, all requests must include the header:
X-Api-Key:
If MCP_AUTH_TOKEN is not set, no header is required (suitable for local-only use).
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"google-maps": {
"command": "npx",
"args": [
"mcp-remote",
"http://localhost:3003/mcp",
"--header",
"X-Api-Key: your_secret_token"
]
}
}
}
Windows + WSL: if the server runs inside WSL, use the full node path:
{ "mcpServers": { "google-maps": { "command": "wsl", "args": [ "--", "/home/user/.nvm/versions/node/v25.2.1/bin/node", "/home/user/.nvm/versions/node/v25.2.1/bin/mcp-remote", "http://localhost:3003/mcp", "--header", "X-Api-Key: your_secret_token" ] } } }
maps_static_map — Static Map ImageReturns a direct image URL for a static map.
| Parameter | Type | Default | Description |
|---|---|---|---|
center | string | required | Address or lat,lng |
zoom | integer | 13 | Zoom level 0–21 |
size | string | 640x480 | Image dimensions WxH in pixels |
maptype | enum | roadmap | roadmap | satellite | terrain | hybrid |
markers | string | — | Marker spec e.g. color:red|48.8566,2.3522 |
path | string | — | Path spec for drawing routes |
format | enum | png | png | jpg | gif |
scale | enum | 1 | 1 = standard, 2 = HiDPI/retina |
language | string | — | BCP 47 language code for labels |
region | string | — | ISO 3166-1 alpha-2 region code |
maps_embed_url — Maps Embed URLReturns an iframe-ready embed URL.
| Parameter | Type | Description |
|---|---|---|
mode | enum | place | directions | search | view | streetview |
q | string | Place/search query (place, search modes) |
center | string | lat,lng for view/streetview mode |
zoom | integer | Zoom level |
origin / destination | string | For directions mode |
waypoints | string | Pipe-separated waypoints |
maptype | enum | roadmap | satellite |
maps_elevation — Elevation DataReturns elevation in metres above sea level.
| Parameter | Type | Description |
|---|---|---|
locations | string | Pipe-separated lat,lng pairs |
path | string | Pipe-separated lat,lng path |
samples | integer | Number of samples along path (2–512) |
maps_street_view — Street View ImageReturns a direct Street View panorama image URL.
| Parameter | Type | Default | Description |
|---|---|---|---|
location | string | — | Address or lat,lng |
pano | string | — | Specific panorama ID (overrides location) |
size | string | 640x480 | Image size WxH |
heading | number | — | Camera heading 0–360° |
pitch | number | — | Camera pitch -90° to 90° |
fov | number | 90 | Field of view 10–120° |
source | enum | — | outdoor to exclude indoor panoramas |
routes_compute — Compute RouteTurn-by-turn directions with real-time traffic.
| Parameter | Type | Default | Description |
|---|---|---|---|
origin | string | required | Address or lat,lng |
destination | string | required | Address or lat,lng |
travel_mode | enum | DRIVE | DRIVE | WALK | BICYCLE | TRANSIT | TWO_WHEELER |
intermediates | string[] | — | Waypoints between origin and destination |
departure_time | string | — | ISO 8601 datetime for traffic-aware routing |
avoid_tolls | boolean | false | Avoid toll roads |
avoid_highways | boolean | false | Avoid highways |
avoid_ferries | boolean | false | Avoid ferries |
units | enum | METRIC | METRIC | IMPERIAL |
compute_alternative_routes | boolean | false | Return up to 3 alternatives |
routes_matrix — Route Distance MatrixCompute travel time/distance between multiple origins and destinations simultaneously.
| Parameter | Type | Default | Description |
|---|---|---|---|
origins | string[] | required | Up to 25 addresses or lat,lng strings |
destinations | string[] | required | Up to 25 addresses or lat,lng strings |
travel_mode | enum | DRIVE | DRIVE | WALK | BICYCLE | TRANSIT |
departure_time | string | — | ISO 8601 datetime |
units | enum | METRIC | METRIC | IMPERIAL |
routes_optimize — Optimize Multi-Stop RouteOptimizes stop order to minimize total travel. Requires GOOGLE_CLOUD_PROJECT_ID.
| Parameter | Type | Description |
|---|---|---|
vehicle_start | string | Start location — must be lat,lng (geocode first if needed) |
vehicle_end | string | End location (defaults to start) |
visits | object[] | Array of { address, label?, duration_minutes? } — addresses must be lat,lng |
travel_mode | enum | DRIVING | WALKING |
places_geocode — Geocode / Reverse GeocodeConvert addresses ↔ coordinates.
| Parameter | Type | Description |
|---|---|---|
address | string | Address to geocode |
latlng | string | lat,lng for reverse geocoding |
region | string | ISO 3166-1 alpha-2 region bias |
components | string | Component filter e.g. country:FR|postal_code:75001 |
places_details — Place DetailsFull details for a place by its Google Place ID.
| Parameter | Type | Description |
|---|---|---|
place_id | string | Google Place ID |
fields | string | Comma-separated field mask (has sensible default) |
language_code | string | Response language |
places_text_search — Search Places by TextFind places matching a natural language query.
| Parameter | Type | Description |
|---|---|---|
query | string | e.g. "best ramen in Tokyo" |
location_bias_lat/lng | number | Bias results toward this location |
location_bias_radius_m | number | Bias circle radius |
max_results | integer | 1–20, default 10 |
min_rating | number | Minimum average star rating (0–5) |
open_now | boolean | Only currently open places |
included_type | string | Filter by place type e.g. restaurant |
price_levels | enum[] | PRICE_LEVEL_FREE … PRICE_LEVEL_VERY_EXPENSIVE |
places_nearby_search — Search Nearby PlacesFind places near a coordinate within a radius.
| Parameter | Type | Description |
|---|---|---|
latitude / longitude | number | Center of search |
radius_m | number | Search radius in metres (max 50,000) |
included_types | string[] | Place type filters |
excluded_types | string[] | Place types to exclude |
max_results | integer | 1–20, default 10 |
rank_preference | enum | DISTANCE | POPULARITY |
places_autocomplete — Place AutocompletePredict place names from partial input.
| Parameter | Type | Description |
|---|---|---|
input | string | Partial text to complete |
location_bias_lat/lng | number | Bias toward this location |
included_primary_types | string[] | Type filter |
country_codes | string[] | ISO 3166-1 alpha-2 country filter |
include_query_predictions | boolean | Also return query predictions |
places_photos — Place PhotosGet photo URLs for a place.
| Parameter | Type | Default | Description |
|---|---|---|---|
place_id | string | required | Google Place ID |
max_photos | integer | 3 | Max photos to return (1–10) |
max_width_px | integer | 1200 | Max photo width in pixels |
max_height_px | integer | 900 | Max photo height in pixels |
places_address_validation — Validate AddressValidate and standardize a postal address.
| Parameter | Type | Description |
|---|---|---|
address_lines | string[] | Address lines |
region_code | string | ISO 3166-1 alpha-2 country code |
locality | string | City/town |
administrative_area | string | State/province |
postal_code | string | Postal code |
enable_usps_cass | boolean | USPS CASS validation (US only) |
places_timezone — Get TimezoneGet IANA timezone and UTC/DST offset for any coordinates.
| Parameter | Type | Description |
|---|---|---|
latitude / longitude | number | Location |
timestamp | integer | Unix timestamp for DST calculation (defaults to now) |
language | string | Response language |
src/
├── index.ts # Raw Node.js HTTP server, auth, stateful session management
├── server.ts # McpServer instantiation + tool registration
├── maps-client.ts # Typed fetch wrappers for all Google Maps REST APIs
└── tools/
├── maps.ts # 4 tools: static map, embed, elevation, street view
├── routes.ts # 3 tools: compute route, matrix, optimize
└── places.ts # 8 tools: geocode, details, text search, nearby, autocomplete,
# photos, address validation, timezone
Key design decisions:
node:http instead of Express — required for correct interop with the MCP SDK's internal Hono-based request handling. Express pre-consumes the request body stream in a way that breaks StreamableHTTPServerTransport.mcp-remote and SSE keep-alive require sessions to persist across requests. Sessions are keyed by Mcp-Session-Id header and cleaned up on transport close.X-Api-Key check happens on the header before any body stream is touched, so rejected requests drain cleanly.?key= query param; new APIs (Places v1, Routes v2, Address Validation) use X-Goog-Api-Key header.npm run dev # TypeScript watch mode (tsc --watch)
npm run build # Compile to dist/
npm start # Run compiled server
docker compose build google-maps-mcp
docker compose up -d google-maps-mcp
# Health check (no auth required)
curl http://localhost:3003/health
# MCP initialize (auth required)
TOKEN=your_secret_token
curl -s -X POST http://localhost:3003/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "X-Api-Key: $TOKEN" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1"}},"id":1}'
# List tools (use session ID from Mcp-Session-Id response header)
SESSION=
curl -s -X POST http://localhost:3003/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "X-Api-Key: $TOKEN" \
-H "Mcp-Session-Id: $SESSION" \
-d '{"jsonrpc":"2.0","method":"tools/list","id":2}'
Windows/WSL gotcha: if your
.envfile has Windows CRLF line endings, extract values withtr -d '\r':TOKEN=$(grep MCP_AUTH_TOKEN .env | cut -d= -f2 | tr -d '\r')
Install via CLI
npx mdskills install apurvaumredkar/google-maps-mcpGoogle Maps MCP is a free, open-source AI agent skill. A TypeScript Model Context Protocol (MCP) server that exposes Google Maps Platform APIs as tools for LLMs. Gives AI assistants real, structured map data — directions, transit routes, place search, address validation, photos, elevation, and more — instead of guessing from training data. Works with Claude Desktop and any other MCP-compatible client. 15 tools across three categories: Transport: HTTP
Install Google Maps MCP with a single command:
npx mdskills install apurvaumredkar/google-maps-mcpThis downloads the skill files into your project and your AI agent picks them up automatically.
Google Maps MCP works with Claude Code, Claude Desktop, Cursor, Vscode Copilot, Windsurf, Continue Dev, Gemini Cli, Amp, Roo Code, Goose. Skills use the open SKILL.md format which is compatible with any AI coding agent that reads markdown instructions.