One place-search interface for every AI and map provider. MCP + REST + SDK, provider fallback, merge+dedup, zero API key needed.
claude mcp add geowire -- npx -y @geowirehq/cli{
"mcpServers": {
"geowire": {
"command": "npx",
"args": ["-y", "@geowirehq/cli"]
}
}
}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-priorWhat 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.
[](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
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
The fastest path to AI-powered full stack observability, even for lean teams.
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface