Skip to main content
Glama
adityak74

Google Maps MCP Server

by adityak74
README.md
# Google Maps MCP Server

<div align="center">

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge)](https://opensource.org/licenses/MIT)
[![Python 3.11+](https://img.shields.io/badge/Python-3.11%2B-blue?style=for-the-badge&logo=python&logoColor=white)](https://python.org)
[![FastMCP 4.0](https://img.shields.io/badge/FastMCP-4.0%2B-green?style=for-the-badge&logo=fastapi&logoColor=white)](https://github.com/jlowin/fastmcp)
[![Playwright](https://img.shields.io/badge/Playwright-Chromium-red?style=for-the-badge&logo=playwright&logoColor=white)](https://playwright.dev)
[![MCP Compatible](https://img.shields.io/badge/MCP-Standard%20Server-6366f1?style=for-the-badge)](https://modelcontextprotocol.io)
[![CI Status](https://img.shields.io/badge/CI-Passing-brightgreen?style=for-the-badge&logo=githubactions&logoColor=white)](https://github.com/adityak74/google-maps-mcp/actions)

<p align="center">
  <b>Production-ready, 100% open-source Model Context Protocol (MCP) server for Google Maps.</b><br>
  Search places, read place details, extract reviews, photo feeds, business updates, and reviewer histories with zero API keys and zero Google Cloud billing.
</p>

[Quick Start](#-quick-start) •
[Features](#-features) •
[Tool Reference](#-tool-reference) •
[Client Setup](#-client-configuration) •
[Architecture](#-architecture) •
[Contributing](#-contributing)

</div>

---

## 🌟 Features

- 🆓 **100% Free & Open Source**: No Google Cloud project, no Google Places API billing, and no third-party subscription keys (like HasData) required.
- ⚡ **Built on Latest FastMCP 4.0**: Full compliance with the official Model Context Protocol specifications (stdio & streamable HTTP).
- 🧩 **Complete HasData Schema Parity**: Standardized JSON data output matching HasData's Google Maps tool contracts (`localResults`, `placeResults`, `reviews`, `topics`, `photos`, `posts`, `contributor`).
- 🛡️ **Anti-Bot & Stealth Engine**: Automatic GDPR / cookie consent dismissal, user-agent emulation, and WebGL canvas stealth to prevent automated session blocking.
- 🎯 **Direct Place & Query Resolution**: Gracefully resolves both broad regional keyword searches and direct place URL / single-business matches.
- 🍪 **Optional Session Persistence**: Full support for `STORAGE_STATE` / cookies to bypass Google Maps "Limited View" restrictions for signed-in sessions.

---

## ⚖️ How It Compares

| Feature | Official Google Places API | HasData MCP (Hosted) | **This Open Source MCP** |
| :--- | :---: | :---: | :---: |
| **Price** | Paid (Pay per call / Google Cloud) | Paid (HasData subscription / credits) | **100% Free** |
| **API Keys Required** | Yes (GCP Project & Billing) | Yes (`HASDATA_API_KEY`) | **None** |
| **Source Code** | Closed | Closed Source (Hosted endpoint only) | **Full MIT Open Source** |
| **FastMCP Version** | Custom / Older | Remote Proxy | **FastMCP 4.0+ Native** |
| **Review Topics & Clustering** | ❌ (Limited) | ✅ Yes | ✅ **Yes** |
| **Contributor Review History** | ❌ No | ✅ Yes | ✅ **Yes** |
| **Self-Hosted Privacy** | ❌ Hosted by Google | ❌ Proxy through HasData | ✅ **Runs locally on your machine** |

---

## 🏗️ Architecture

```mermaid
flowchart LR
    subgraph Client["MCP Client (Claude Desktop / Cursor / Claude Code)"]
        LLM[LLM / Chat Model]
    end

    subgraph MCP["Google Maps MCP Server (FastMCP 4.0)"]
        Router[FastMCP Tool Router]
        Models[Pydantic HasData Schemas]
        
        subgraph Extractors["Async Extractors"]
            E1[search_places]
            E2[get_place_details]
            E3[get_place_reviews]
            E4[get_place_photos]
            E5[get_place_posts]
            E6[get_contributor_reviews]
        end
        
        BrowserMgr[BrowserManager Singleton]
    end

    subgraph Web["Google Maps"]
        GMap[(Google Maps Live Web)]
    end

    Client <-->|stdio / JSON-RPC| Router
    Router --> Extractors
    Extractors --> Models
    Extractors <--> BrowserMgr
    BrowserMgr <-->|Playwright Chromium Stealth| GMap
```

---

## 🚀 Quick Start

### 1. Installation via `uv`

We recommend [uv](https://github.com/astral-sh/uv) for fast, isolated Python execution.

```bash
# Clone the repository
git clone https://github.com/adityak74/google-maps-mcp.git
cd google-maps-mcp

# Install dependencies and Chromium browser
uv sync
uv run playwright install chromium
```

### 2. Verify Installation

Run the test suite to ensure everything is operating cleanly:

```bash
uv run pytest -v
```

---

## 💻 Client Configuration

### Claude Desktop

Add the server to your `claude_desktop_config.json` (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS or `%APPDATA%\Claude\claude_desktop_config.json` on Windows):

```json
{
  "mcpServers": {
    "google-maps": {
      "command": "uv",
      "args": [
        "--directory",
        "/ABSOLUTE/PATH/TO/google-maps-mcp",
        "run",
        "google-maps-mcp"
      ]
    }
  }
}
```

### Cursor

Add to your project's `.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "google-maps": {
      "command": "uv",
      "args": [
        "--directory",
        "/ABSOLUTE/PATH/TO/google-maps-mcp",
        "run",
        "google-maps-mcp"
      ]
    }
  }
}
```

### Claude Code CLI

```bash
claude mcp add google-maps -- uv --directory /ABSOLUTE/PATH/TO/google-maps-mcp run google-maps-mcp
```

### Windsurf / Codeium

Add to `~/.codeium/windsurf/mcp_config.json`:

```json
{
  "mcpServers": {
    "google-maps": {
      "command": "uv",
      "args": [
        "--directory",
        "/ABSOLUTE/PATH/TO/google-maps-mcp",
        "run",
        "google-maps-mcp"
      ]
    }
  }
}
```

---

## 🛠️ Tool Reference

All 6 tools return clean, structured JSON conforming to HasData's schema definitions.

### 1. `google_maps_search`
Search Google Maps for places matching a keyword query, ranked as Google Maps ranks them.

- **Parameters**:
  - `q` (*str*, required): Search term (e.g. `"best coffee in Seattle"`, `"plumber near me"`).
  - `ll` (*str*, optional): Geographic center pin and zoom as `@lat,lng,zoomz` (e.g. `"@47.6062,-122.3321,14z"`).
  - `hl` (*str*, optional, default: `"en"`): Two-letter interface language code.
  - `gl` (*str*, optional, default: `"us"`): Two-letter country region code.
  - `start` (*int*, optional, default: `0`): Pagination offset.

```json
{
  "localResults": [
    {
      "position": 1,
      "title": "Taj Palace",
      "address": "92 THF Blvd, Chesterfield, MO 63005",
      "rating": 4.4,
      "phone": "(636) 728-1000",
      "type": "Indian restaurant",
      "website": "https://tajpalacestl.com/",
      "gpsCoordinates": { "latitude": 38.6671397, "longitude": -90.5892454 }
    }
  ],
  "pagination": { "start": 0, "count": 1, "hasMore": false }
}
```

---

### 2. `google_maps_place_details`
Retrieve comprehensive listing information for a specific place.

- **Parameters**:
  - `placeId` (*str*, optional): Google Maps place identifier or direct place URL.
  - `dataId` (*str*, optional): Feature data ID (hex representation).
  - `query` (*str*, optional): Fallback search query if ID is not known.
  - `hl` (*str*, optional, default: `"en"`): Language code.

```json
{
  "placeResults": {
    "title": "Taj Palace",
    "address": "92 THF Blvd, Chesterfield, MO 63005",
    "rating": 4.4,
    "phone": "(636) 728-1000",
    "type": "Indian restaurant",
    "website": "https://tajpalacestl.com/",
    "images": [
      "https://lh5.googleusercontent.com/p/AF1Qip...=w400-h300-k-no"
    ]
  }
}
```

---

### 3. `google_maps_reviews`
Scrape the review feed for a place with sorting, review topics, and pagination.

- **Parameters**:
  - `placeId` (*str*, optional): Place ID or URL.
  - `dataId` (*str*, optional): Feature data ID.
  - `sortBy` (*str*, optional, default: `"mostRelevant"`): `"mostRelevant"`, `"newestFirst"`, `"ratingHigh"`, or `"ratingLow"`.
  - `topicId` (*str*, optional): Filter reviews mentioning a specific topic chip.
  - `num` (*int*, optional, default: `20`): Maximum number of reviews to extract.

```json
{
  "placeInfo": { "title": "Taj Palace" },
  "topics": [
    { "id": "lunch_buffet", "keyword": "lunch buffet", "mentions": 42 },
    { "id": "chicken_tikka", "keyword": "chicken tikka", "mentions": 28 }
  ],
  "reviews": [
    {
      "rating": 5.0,
      "snippet": "Outstanding Indian food and attentive service!",
      "date": "2 weeks ago",
      "user": { "name": "Sarah Miller", "contributorId": "106033685843245983748" },
      "response": { "snippet": "Thank you Sarah, we hope to see you again soon!" }
    }
  ]
}
```

---

### 4. `google_maps_photos`
Retrieve photo feeds categorized by section (`All`, `Menu`, `Atmosphere`, `Inside`, etc.).

- **Parameters**:
  - `placeId` (*str*, optional) / `dataId` (*str*, optional).
  - `categoryId` (*str*, optional): Category tab filter (e.g. `"Menu"`).
  - `limit` (*int*, optional, default: `20`): Maximum photos to return.

```json
{
  "categories": ["All", "Menu", "Inside", "Vibe"],
  "photos": [
    {
      "image": "https://lh5.googleusercontent.com/p/AF1Qip...=w1080-h720",
      "thumbnail": "https://lh5.googleusercontent.com/p/AF1Qip...=w400-h300"
    }
  ]
}
```

---

### 5. `google_maps_posts`
Retrieve updates, announcements, offers, and posts published by the business listing.

- **Parameters**:
  - `placeId` (*str*, optional) / `dataId` (*str*, optional).
  - `limit` (*int*, optional, default: `10`): Maximum posts to return.

```json
{
  "posts": [
    {
      "snippet": "Join us for our Weekend Grand Buffet starting this Saturday at 11:30 AM!",
      "date": "3 days ago"
    }
  ]
}
```

---

### 6. `google_maps_contributor_reviews`
Retrieve reviews written by a specific reviewer across all locations they evaluated. Ideal for reviewer credibility and local guide network analysis.

- **Parameters**:
  - `contributorId` (*str*, required): Contributor ID or profile link.
  - `num` (*int*, optional, default: `20`): Maximum reviews to return.

```json
{
  "contributor": {
    "name": "David Kim",
    "level": "Level 6 Local Guide",
    "points": 1450,
    "contributions": "Level 6 Local Guide · 1,450 points"
  },
  "reviews": [
    {
      "placeInfo": { "title": "Artisan Bakery" },
      "rating": 5.0,
      "snippet": "Best sourdough loaf in town.",
      "date": "1 month ago"
    }
  ]
}
```

---

## 🔒 Advanced: Authentication & Google Maps Limited View

In 2024–2026, Google introduced a **"Limited View"** for unauthenticated browser sessions in certain geographical regions or unverified IPs. In this mode, Google temporarily restricts public review feeds behind a sign-in prompt.

To bypass this restriction and access full review feeds unconditionally:

1. **Save Authenticated Cookies / Storage State:**
   Use Playwright CLI to log into your Google account once and export your cookies:
   ```bash
   uv run playwright codegen --save-storage=google_state.json https://www.google.com/maps
   ```
2. **Pass Environment Variable:**
   Provide the path to `STORAGE_STATE` in your client config or shell:
   ```bash
   export STORAGE_STATE="/absolute/path/to/google_state.json"
   ```
   Or inside your MCP client config:
   ```json
   "env": {
     "STORAGE_STATE": "/absolute/path/to/google_state.json"
   }
   ```

---

## 🧪 Testing & Development

Run all test suites including models, utilities, extractors, and server tool registrations:

```bash
# Run pytest with coverage/verbose reporting
uv run pytest -v

# Run only extractor DOM tests
uv run pytest tests/test_extractors.py -v

# Run in headed mode for visual browser debugging
HEADLESS=false uv run pytest tests/test_browser.py -v
```

---

## 🤝 Contributing

Contributions, issues, and feature requests are welcome!
Feel free to check the [issues page](https://github.com/adityak74/google-maps-mcp/issues).

1. Fork the Project
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Commit your Changes (`git commit -m 'feat: add some amazing feature'`)
4. Push to the Branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request

---

## 📄 License

Distributed under the MIT License. See [`LICENSE`](LICENSE) for more information.

---

<div align="center">
  <sub>Built with ❤️ by <a href="https://github.com/adityak74">Aditya Karnam</a> and the open-source MCP community.</sub>
</div>

TDQS

A3.5/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a distinct aspect of Google Maps data: place search, individual place details, reviews, photos, posts, and contributor review history. Even though place_details can accept a query, its purpose as a single-place lookup is clearly separated from the ranked search tool.

Naming Consistency4/5

All tools share the google_maps_ prefix and use snake_case, making the namespace cohesive. Some names are noun-based (reviews, photos, posts) while others are verb- or resource-oriented, but the overall pattern is predictable and readable.

Tool Count5/5

Six tools is a well-scoped set for a Google Maps place-data server. Each tool covers a meaningful, distinct retrieval use case without unnecessary overlap or bloat.

Completeness3/5

The set thoroughly covers place discovery and place-specific content feeds, but notable Google Maps capabilities like geocoding, directions, and place autocomplete are missing. As a read-only place information server it is fairly complete, but as a general Google Maps MCP server it has gaps.

Maintenance

ActivityMaintained
ResponsivenessNo issues