Skip to main content
ClaudeWave

One place-search interface for every AI and map provider. MCP + REST + SDK, provider fallback, merge+dedup, zero API key needed.

MCP ServersOfficial Registry0 stars1 forksTypeScriptApache-2.0Updated today
Install in Claude Code / Claude Desktop
Method: NPX · @geowirehq/cli
Claude Code CLI
claude mcp add geowire -- npx -y @geowirehq/cli
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "geowire": {
      "command": "npx",
      "args": ["-y", "@geowirehq/cli"]
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
Use cases

MCP Servers overview

# GeoWire

> **Add real-world places to any AI agent in 5 minutes — no API key required.**
>
> One place-search interface for every AI and map provider.

<p align="center">
  <img src="docs/media/geowire-mcp.gif" alt="geowire MCP server — tools/list and a geocode_address call over stdio" width="760">
</p>

GeoWire is an open-source geo search gateway that sits between AI agents and
map/place data providers (OpenStreetMap, Google, your own data) and exposes them
through a single **MCP server**, **REST API**, and **SDK** — with provider
fallback, multi-provider merge + dedup, cost budgets, and a policy engine that
enforces each provider's caching/attribution terms.

**Status: v0.1 ("It works") — published on npm. MCP · REST · CLI · SDK all functional.**

> **Honest by design:** OpenStreetMap (the zero-key default) is a great
> *geocoder* — strong on place names, addresses, and landmarks — but thin on
> category words ("coffee", "pharmacy"), opening hours, and coverage outside
> Europe. Add a Google key for full business data; GeoWire merges both and tells
> you which source every field came from.

**Contents:** [Why](#why-geowire) · [Quickstart](#quickstart) · [MCP tools](#mcp-tools) · [REST](#rest-endpoints) · [Anatomy of a response](#anatomy-of-a-response) · [Config](#configuration-optional--everything-works-without-it) · [Providers](#providers) · [Recipes & examples](#recipes--examples) · [Roadmap](#roadmap) · [Architecture](#architecture)

## Why GeoWire?

|  | Direct integration | Single-provider MCP | **GeoWire** |
|---|---|---|---|
| Unified place schema | ❌ per-provider code | ❌ | ✅ |
| Provider fallback on failure | ❌ | ❌ | ✅ |
| Multi-provider merge + dedup | ❌ | ❌ | ✅ |
| Cost budgets & routing | ❌ | ❌ | ✅ |
| Works without any API key | ❌ | depends | ✅ (OSM by default) |
| Self-hosted | — | depends | ✅ |
| Your own place data as a provider | ❌ | ❌ | ✅ |
| Transparent provenance (which source, what cost) | ❌ | ❌ | ✅ (every response) |

**Not a Google replacement — it *uses* Google.** The thing no single provider can
do: merge **your own store data + Google + OSM** into one deduped record, with
per-field provenance (your name is authoritative, Google adds ratings, OSM adds
coordinates). Real run below:

<p align="center">
  <img src="docs/media/geowire-merge.gif" alt="GeoWire merging a private store DB, Google, and OpenStreetMap into one record with per-field provenance" width="760">
</p>

## Quickstart

### 1. MCP (Claude Desktop / Cursor) — 30 seconds

Add this to your MCP client config (e.g. Claude Desktop `claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "geowire": { "command": "npx", "args": ["-y", "@geowirehq/mcp"] }
  }
}
```

Then ask: *"Where is the Eiffel Tower?"* or *"Find a Starbucks within 3 km of
37.4979, 127.0276."* Works with **zero API keys** — OpenStreetMap is the default.
Add `"env": { "GOOGLE_MAPS_API_KEY": "..." }` for business listings and hours
(e.g. *"Find a 24-hour pharmacy near me"*). See [more MCP client configs](./examples/mcp-clients.md).

### 2. CLI — one-shot search & server

<p align="center">
  <img src="docs/media/geowire-search.gif" alt="geowire search in the terminal, with source attribution and response time" width="720">
</p>

```bash
npx @geowirehq/cli search "Eiffel Tower"          # terminal search with a results table
npx @geowirehq/cli search "Starbucks" --near 37.4979,127.0276 --radius 3000   # near a coordinate
npx @geowirehq/cli reverse 37.5665,126.9780       # coordinate → nearest place
npx @geowirehq/cli route 37.5665,126.9780 37.4979,127.0276   # driving directions (no key, OSRM)
npx @geowirehq/cli get google:ChIJ...             # one place by reference (getPlace-capable provider)
npx @geowirehq/cli                                # start the REST + MCP server (zero-config)
npx @geowirehq/cli init                           # interactive setup wizard (.env + config)
npx @geowirehq/cli test                           # check provider connections
```

Add `--json` to any command for the full response (results + provenance `meta`).

### 3. Docker — self-hosted server

```bash
docker run -p 4980:4980 geowire/geowire
# then:
curl -X POST http://localhost:4980/v1/places/search \
  -H 'content-type: application/json' \
  -d '{"query":"Starbucks","near":{"latitude":37.4979,"longitude":127.0276},"radiusMeters":3000}'
```

Or with `docker compose up` (see `docker-compose.yml`). API docs at `/docs`.

### 4. SDK (embedded)

```ts
import { createGeoWire } from "@geowirehq/core";
import { createNominatimProvider } from "@geowirehq/provider-nominatim";

const geo = createGeoWire({ providers: [createNominatimProvider()] });
const { results, meta } = await geo.searchPlaces({
  query: "Starbucks",
  near: { latitude: 37.4979, longitude: 127.0276 },
  radiusMeters: 3000,
});
```

Full embedded-SDK guide: [`examples/typescript-sdk.md`](./examples/typescript-sdk.md).

## MCP tools

| Tool | Description |
|---|---|
| `search_places` | Natural-language + coordinate/region place search |
| `get_place` | Details by `provider:providerPlaceId` reference |
| `geocode_address` | Address → coordinates (+ normalized address) |
| `reverse_geocode` | Coordinates → nearest address |
| `get_directions` | Route between waypoints (distance, time, legs) — no key (OSRM) |
| `distance_matrix` | N×M travel distances/times — rank candidates by drive time — no key |
| `analyze_area` | Commercial-area analysis: category density, competition, rating landscape |
| `list_geo_providers` | Active providers, capabilities, status (agent self-awareness) |

Every response includes both a human-readable summary and `structuredContent`
(schema-valid JSON).

## REST endpoints

| Method | Path | |
|---|---|---|
| POST | `/v1/places/search` | search |
| GET | `/v1/places/{ref}` | place details (`provider:id`) |
| GET | `/v1/geocode?address=` | geocode |
| GET | `/v1/reverse-geocode?lat=&lon=` | reverse geocode |
| POST | `/v1/directions` | directions between waypoints (no key) |
| POST | `/v1/distance-matrix` | N×M travel distance/time matrix (no key) |
| POST | `/v1/analyze-area` | commercial-area analysis (density, competition, ratings) |
| GET | `/v1/providers` | list providers |
| GET | `/v1/health` | health check |
| GET | `/metrics` | Prometheus metrics |
| GET | `/docs` | Swagger UI (OpenAPI 3.1) |
| POST | `/mcp` | MCP over Streamable HTTP |

Optional Bearer auth: set `GEOWIRE_API_KEYS=key1,key2`.

## Anatomy of a response

No black box. Every response carries a `meta` block: which providers were
**used / skipped / failed** (and why), dedup counts, cache status, estimated
cost, and per-field sourcing — so you always know where each value came from.

```jsonc
{
  "results": [{
    "id": "gwp_CvWvRZrFtegkJPxP9CW0",
    "name": "경복궁",
    "location": { "latitude": 37.579754, "longitude": 126.9766818 },
    "sources": [{
      "provider": "nominatim",
      "providerPlaceId": "relation/5501517",
      "fields": ["name", "location", "categories", "address"]   // ← what this source contributed
    }],
    "attributions": ["© OpenStreetMap contributors"]
  }],
  "meta": {
    "providersUsed":   [{ "provider": "nominatim", "resultCount": 1, "latencyMs": 2449 }],
    "providersSkipped": [],   // e.g. { provider: "google", reason: "MISSING_CREDENTIALS" | "QUOTA_EXCEEDED" }
    "providersFailed":  [],   // e.g. { provider: "google", reason: "TIMEOUT" }
    "strategy": "first-success",
    "cache": { "hit": false }
    // merging adds:  "dedup": { "before": 3, "after": 1 }
    // paid provider: "estimatedCostUSD": 0.032
  }
}
```

After a merge, `sources[].fields` shows (say) the phone came from Google while
the coordinates came from OSM. Walkthrough: [docs/recipes.md](./docs/recipes.md#4-read-a-response-provenance--transparency).

## Configuration (optional — everything works without it)

`geowire.config.yaml`:

```yaml
providers:
  nominatim: { enabled: true }                       # default ON, no key
  google:    { enabled: true, apiKey: ${GOOGLE_MAPS_API_KEY} }
  kakao:     { enabled: true }                        # env KAKAO_REST_API_KEY (KR)
  naver:     { enabled: true }                        # env NAVER_CLIENT_ID + NAVER_CLIENT_SECRET (KR)
  internal:  { enabled: true, source: ./my-places.csv, priority: 100 }
routing:
  defaultStrategy: merge          # first-success | merge | cost-aware | weighted | fastest
  providerWeights:                # for `weighted`: order by priority·cost·coverage
    priority: 0.5
    cost: 0.3
    coverage: 0.2
budget:
  perRequestMaxUSD: 0.10          # over-budget paid providers are skipped, free ones used
```

Keys come from the environment (`${VAR}`), never committed in plaintext.

## Providers

| Provider | Key? | Capabilities |
|---|---|---|
| `@geowirehq/provider-nominatim` (OpenStreetMap) | none | search, geocode, reverseGeocode |
| `@geowirehq/provider-osrm` (OpenStreetMap routing) | none | route, distanceMatrix |
| `@geowirehq/provider-google` (Maps Platform) | BYOK | search, geocode, reverseGeocode, getPlace, route, distanceMatrix |
| `@geowirehq/provider-kakao` (카카오맵, KR) | BYOK `KAKAO_REST_API_KEY` | search, geocode, reverseGeocode |
| `@geowirehq/provider-naver` (네이버 지역검색, KR) | BYOK `NAVER_CLIENT_ID`+`NAVER_CLIENT_SECRET` | search, geocode |
| `@geowirehq/provider-baidu` (百度地图, CN) | BYOK `BAIDU_MAP_AK` | search, geocode, reverseGeocode |
| `@geowirehq/provider-foursquare` (global POI) | BYOK `FOURSQUARE_API_KEY` | search, getPlace |
| `@geowirehq/provider-internal` (your CSV) | none | search |

Regional providers make Korea (Kakao/Naver) and China (Baidu) coverage
first-class where OSM is thin and Google has gaps — Baidu returns BD-09
coordinates, which GeoWire converts to WGS84 automatically. Merge them all +
your own store data into one deduped record.

### Provider roles — each provider does what it's best at

Providers aren't interchangeable; they're **complementary**. When `merge` combines
duplicates, GeoWire doesn't just pick the highest-prior
ai-agentsgeocodinggeospatialllm-toolsmcpmodel-context-protocolopenstreetmapplacestypescript

What people ask about geowire

What is geowire/geowire?

+

geowire/geowire is mcp servers for the Claude AI ecosystem. One place-search interface for every AI and map provider. MCP + REST + SDK, provider fallback, merge+dedup, zero API key needed. It has 0 GitHub stars and was last updated today.

How do I install geowire?

+

You can install geowire by cloning the repository (https://github.com/geowire/geowire) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.

Is geowire/geowire safe to use?

+

geowire/geowire has not been audited yet by our security agent. Review the original repository on GitHub before using it in production.

Who maintains geowire/geowire?

+

geowire/geowire is maintained by geowire. The last recorded GitHub activity is from today, with 21 open issues.

Are there alternatives to geowire?

+

Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.

Deploy geowire to your cloud

Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.

Maintain this repo? Add a badge to your README

Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.

Featured on ClaudeWave: geowire/geowire
[![Featured on ClaudeWave](https://claudewave.com/api/badge/geowire-geowire)](https://claudewave.com/repo/geowire-geowire)
<a href="https://claudewave.com/repo/geowire-geowire"><img src="https://claudewave.com/api/badge/geowire-geowire" alt="Featured on ClaudeWave: geowire/geowire" width="320" height="64" /></a>

More MCP Servers

geowire alternatives