io.github.cyanheads/openstreetmap-mcp-server
Geocode, reverse geocode, and run Overpass spatial queries on OpenStreetMap data.
Que pouvez-vous faire avec io.github.cyanheads/openstreetmap-mcp-server ?
- Nominatim requests are spaced 1,050 ms apart to respect its one-request-per-second policy;
OSM_USER_AGENTidentifies the server to both upstreams - Overpass queries are limited per endpoint by
OSM_OVERPASS_MAX_CONCURRENCY, with opt-in failover acrossOSM_OVERPASS_ENDPOINTS(see Overpass endpoint failover) - Overpass tools page with
limitandoffsetand reporttotalFound,truncated, andnextOffset; results are cached for 10 minutes (Nominatim for 60), so re-paging makes no new upstream request - An Overpass response over 64 MiB fails as
result_too_large OSM_NOMINATIM_BASE_URLandOSM_OVERPASS_BASE_URLpoint the server at a self-hosted or mirror instanceeffectiveQuery,effectiveTag, andeffectiveAreaecho what was sent; Overpass responses adddata_timestampandservingEndpoint, and every response carries the ODbLattributionosm_type+osm_idfrom any tool feedopenstreetmap_lookup_objects, and a geocoded relation or way becomes awithinref foropenstreetmap_query_bbox- The Nominatim tools never select by tag, and
tagSelectionCaveatsays so; regex, alternation, and negation go throughopenstreetmap_query_raw
Installation
Ajoutez ceci à la configuration MCP de votre client (Claude Desktop : claude_desktop_config.json ; Cursor : .cursor/mcp.json ; VS Code et les autres utilisent la même forme « mcpServers »).
claude mcp add --transport http openstreetmap-mcp-server 'https://openstreetmap.caseyjhand.com/mcp'
{
"mcpServers": {
"openstreetmap-mcp-server": {
"type": "http",
"url": "https://openstreetmap.caseyjhand.com/mcp"
}
}
}
@cyanheads/openstreetmap-mcp-serverclaude mcp add openstreetmap-mcp-server -e 'OSM_NOMINATIM_BASE_URL=https://nominatim.openstreetmap.org' -e 'OSM_USER_AGENT=openstreetmap-mcp-server/0.7.0' -e 'OSM_OVERPASS_BASE_URL=<OSM_OVERPASS_BASE_URL>' -e 'OSM_OVERPASS_ENDPOINTS=https://overpass-api.de/api/interpreter' -e 'OSM_OVERPASS_MAX_CONCURRENCY=1' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/openstreetmap-mcp-server@0.7.0
{
"mcpServers": {
"openstreetmap-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/openstreetmap-mcp-server@0.7.0"
],
"env": {
"OSM_NOMINATIM_BASE_URL": "https://nominatim.openstreetmap.org",
"OSM_USER_AGENT": "openstreetmap-mcp-server/0.7.0",
"OSM_OVERPASS_BASE_URL": "<OSM_OVERPASS_BASE_URL>",
"OSM_OVERPASS_ENDPOINTS": "https://overpass-api.de/api/interpreter",
"OSM_OVERPASS_MAX_CONCURRENCY": "1",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Variables d'environnement
OSM_NOMINATIM_BASE_URLNominatim API base URL. Override to use a private or mirror instance.OSM_USER_AGENTUser-Agent sent to Nominatim and Overpass. Required by usage policy.OSM_OVERPASS_BASE_URLOverpass API endpoint URL. When set, pins every query to this one endpoint and disables mirror failover; OSM_OVERPASS_MAX_CONCURRENCY sizes it and a |N suffix is rejected. Leave unset to use OSM_OVERPASS_ENDPOINTS.OSM_OVERPASS_ENDPOINTSComma-separated ordered list of Overpass endpoints. A failure advances to the next entry within the same tool call; a single entry means no failover. An entry written url|N gets N slots of its own and adds capacity, for an instance whose operator allows parallel queries, never a public FOSSGIS server; an unsuffixed later entry is failover only. Write a | inside a URL as %7C. Verify a mirror's usage policy, data coverage, and freshness before adding it. Ignored when OSM_OVERPASS_BASE_URL is set.OSM_OVERPASS_MAX_CONCURRENCYConcurrent Overpass queries per endpoint: OSM_OVERPASS_BASE_URL, and every OSM_OVERPASS_ENDPOINTS entry not sized with |N. With no |N entry it is also the most queries in flight across all endpoints. A query waits at most 30 seconds in total for a slot, then fails with pacer_shed and a retryAfter. The default of 1 follows the public FOSSGIS instances, which allow one query in flight per user; raise it only for an instance whose operator allows parallel queries, such as a private or paid one.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
@cyanheads/openstreetmap-mcp-serverclaude mcp add openstreetmap-mcp-server -e 'MCP_TRANSPORT_TYPE=<MCP_TRANSPORT_TYPE>' -e 'MCP_HTTP_HOST=127.0.0.1' -e 'MCP_HTTP_PORT=3010' -e 'MCP_HTTP_ENDPOINT_PATH=/mcp' -e 'MCP_PUBLIC_URL=<MCP_PUBLIC_URL>' -e 'MCP_AUTH_MODE=none' -e 'OSM_NOMINATIM_BASE_URL=https://nominatim.openstreetmap.org' -e 'OSM_USER_AGENT=openstreetmap-mcp-server/0.7.0' -e 'OSM_OVERPASS_BASE_URL=<OSM_OVERPASS_BASE_URL>' -e 'OSM_OVERPASS_ENDPOINTS=https://overpass-api.de/api/interpreter' -e 'OSM_OVERPASS_MAX_CONCURRENCY=1' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/openstreetmap-mcp-server@0.7.0
{
"mcpServers": {
"openstreetmap-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/openstreetmap-mcp-server@0.7.0"
],
"env": {
"MCP_TRANSPORT_TYPE": "<MCP_TRANSPORT_TYPE>",
"MCP_HTTP_HOST": "127.0.0.1",
"MCP_HTTP_PORT": "3010",
"MCP_HTTP_ENDPOINT_PATH": "/mcp",
"MCP_PUBLIC_URL": "<MCP_PUBLIC_URL>",
"MCP_AUTH_MODE": "none",
"OSM_NOMINATIM_BASE_URL": "https://nominatim.openstreetmap.org",
"OSM_USER_AGENT": "openstreetmap-mcp-server/0.7.0",
"OSM_OVERPASS_BASE_URL": "<OSM_OVERPASS_BASE_URL>",
"OSM_OVERPASS_ENDPOINTS": "https://overpass-api.de/api/interpreter",
"OSM_OVERPASS_MAX_CONCURRENCY": "1",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Variables d'environnement
MCP_TRANSPORT_TYPESelects the HTTP transport.MCP_HTTP_HOSTThe hostname for the HTTP server.MCP_HTTP_PORTThe port to run the HTTP server on.MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.MCP_PUBLIC_URLPublic origin override for deployments behind a TLS-terminating reverse proxy (e.g. https://mcp.example.com).MCP_AUTH_MODEAuthentication mode to use: 'none', 'jwt', or 'oauth'.OSM_NOMINATIM_BASE_URLNominatim API base URL. Override to use a private or mirror instance.OSM_USER_AGENTUser-Agent sent to Nominatim and Overpass. Required by usage policy.OSM_OVERPASS_BASE_URLOverpass API endpoint URL. When set, pins every query to this one endpoint and disables mirror failover; OSM_OVERPASS_MAX_CONCURRENCY sizes it and a |N suffix is rejected. Leave unset to use OSM_OVERPASS_ENDPOINTS.OSM_OVERPASS_ENDPOINTSComma-separated ordered list of Overpass endpoints. A failure advances to the next entry within the same tool call; a single entry means no failover. An entry written url|N gets N slots of its own and adds capacity, for an instance whose operator allows parallel queries, never a public FOSSGIS server; an unsuffixed later entry is failover only. Write a | inside a URL as %7C. Verify a mirror's usage policy, data coverage, and freshness before adding it. Ignored when OSM_OVERPASS_BASE_URL is set.OSM_OVERPASS_MAX_CONCURRENCYConcurrent Overpass queries per endpoint: OSM_OVERPASS_BASE_URL, and every OSM_OVERPASS_ENDPOINTS entry not sized with |N. With no |N entry it is also the most queries in flight across all endpoints. A query waits at most 30 seconds in total for a slot, then fails with pacer_shed and a retryAfter. The default of 1 follows the public FOSSGIS instances, which allow one query in flight per user; raise it only for an instance whose operator allows parallel queries, such as a private or paid one.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
Documentation
Tirée du README du projet sur GitHub, actualisée chaque semaine. Les liens ouvrent GitHub.
Sommaire
@cyanheads/openstreetmap-mcp-server
Geocode, reverse geocode, and run Overpass spatial queries on OpenStreetMap data via MCP. STDIO or Streamable HTTP.
6 Tools
Public Hosted Server: https://openstreetmap.caseyjhand.com/mcp
Overview
OpenStreetMap data through Nominatim and the Overpass API. Geocode places and addresses, resolve coordinates to the nearest address, look up known OSM objects, and query features by tag around a point, inside a bounding box, or inside an OSM boundary.
Tools
| Tool | Description |
|---|---|
openstreetmap_search_places | Convert a place name or address to coordinates and structured place data |
openstreetmap_reverse_geocode | Convert latitude/longitude to the nearest address or place name |
openstreetmap_lookup_objects | Fetch address records for known OSM objects by ID |
openstreetmap_query_nearby | Find OSM features within a radius of a point |
openstreetmap_query_bbox | Find OSM features inside a bounding box or an OSM boundary such as a city, park, or region |
openstreetmap_query_raw | Run a raw Overpass QL query for anything the other tools cannot express |
Capability reference
openstreetmap_search_places tool
- Free-form
queryor the structured fieldsstreet,city,county,state,country,postalcode, never both; up to 40 results (limit, default 5; a largerlimitis served as 40 with alimitNotice), narrowed bycountrycodes,layer,featureType, and aviewbox(restricting withbounded: true) - Results carry coordinates, structured
address,boundingbox,importance, andosm_type+osm_id;extratagsadds contact and physical-attribute tags; an empty first page fails asno_results - A full page returns
nextExcludeIdsto pass back asexclude_place_ids; once results run out you get zero results and a notice, not an error
openstreetmap_reverse_geocode tool
lat/lonpluszoomfrom 3 (country) to 18 (building, the default);layerdefaults toaddress,poi- Returns the nearest indexed object with structured
address,osm_type+osm_id, andboundingbox; coordinates with no OSM data fail asno_coverage
openstreetmap_lookup_objects tool
- Up to 500
osm_idsentries, each prefixedN,W, orR(["N240109189"]); a malformed ID fails asinvalid_id_format - The first 50 unique IDs are looked up; the rest come back as
deferred_idsfor the next call - Returns address records for the objects found and lists the rest under
not_found(including objects Nominatim does not index, such as street lamps); anoticecarries anopenstreetmap_query_rawquery to check which exist
openstreetmap_query_nearby tool
lat/lonwithradius_metersup to 50,000 (default 1,000); one primary tag,amenityortag_keywith an optionaltag_value, plus up to five ANDedfilters; up to 500 features per page (a largerlimitis served as 500 with alimitNotice)- A value matches exactly by default;
list_itemmode (tag_value_match, ormatchon a filter) matches one item of a semicolon list, socuisine=pizzaalso findscuisine=pizza;italian - An
amenityvalue that OpenStreetMap tags under another key (amenity: "museum"; museums aretourism=museum) gets anoticenaming the key to retry with - Features carry
osm_type+osm_id, coordinates,distance_meters(to the feature's nearest point), and the full tag set, sorted nearest-first;effectiveTagechoes the filter chain
openstreetmap_query_bbox tool
- One scope per call: the corners
south,west,north,east, orwithinand oneR/Wboundary ref (R237385) built from a geocoding result'sosm_type+osm_id; the same tag filters, list-item matching, stray-amenitynotice, and 500-per-page cap asopenstreetmap_query_nearby effectiveAreaechoes howwithinresolved andareasTimestamphow old the area data is; a ref that maps to no area returns an empty page with a notice- A
westgreater thaneastis a box crossing the antimeridian;southgreater thannorthfails asinvalid_bbox
openstreetmap_query_raw tool
- Any Overpass QL containing
[out:json];[timeout:N]comes fromtimeout_seconds(up to 180, default 30) and[maxsize:268435456](256 MiB) is added when the query sets none; up to 500 elements per page (a largerlimitis served as 500 with alimitNotice) - Returns raw elements (ways carry
nodes[], relationsmembers[]), plustotal_elementsand theeffectiveQueryas sent; malformed QL fails asquery_errorwith Overpass's parse error max_element_bytes(default 20,000, minimum 1,000) withholds an over-budget element'smembers,nodes, orgeometryarrays, listed underwithheld_keys;withheldElementsandwithheldNoticesay how to fetch them
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
OpenStreetMap-specific:
- Nominatim requests are spaced 1,050 ms apart to respect its one-request-per-second policy;
OSM_USER_AGENTidentifies the server to both upstreams - Overpass queries are limited per endpoint by
OSM_OVERPASS_MAX_CONCURRENCY, with opt-in failover acrossOSM_OVERPASS_ENDPOINTS(see Overpass endpoint failover) - Overpass tools page with
limitandoffsetand reporttotalFound,truncated, andnextOffset; results are cached for 10 minutes (Nominatim for 60), so re-paging makes no new upstream request - An Overpass response over 64 MiB fails as
result_too_large OSM_NOMINATIM_BASE_URLandOSM_OVERPASS_BASE_URLpoint the server at a self-hosted or mirror instance
Agent-friendly output:
effectiveQuery,effectiveTag, andeffectiveAreaecho what was sent; Overpass responses adddata_timestampandservingEndpoint, and every response carries the ODbLattributionosm_type+osm_idfrom any tool feedopenstreetmap_lookup_objects, and a geocoded relation or way becomes awithinref foropenstreetmap_query_bbox- The Nominatim tools never select by tag, and
tagSelectionCaveatsays so; regex, alternation, and negation go throughopenstreetmap_query_raw - Names and tag values are escaped in the Markdown output;
structuredContentkeeps the raw text
Getting started
Public Hosted Instance
A public instance is available at https://openstreetmap.caseyjhand.com/mcp — no installation required. It serves Streamable HTTP; each client takes its own config shape.
For Claude Code:
claude mcp add --transport http openstreetmap-mcp-server https://openstreetmap.caseyjhand.com/mcp
For Cline (cline_mcp_settings.json):
{
"mcpServers": {
"openstreetmap-mcp-server": {
"type": "streamableHttp",
"url": "https://openstreetmap.caseyjhand.com/mcp"
}
}
}
For Cursor (mcp.json):
{
"mcpServers": {
"openstreetmap-mcp-server": {
"url": "https://openstreetmap.caseyjhand.com/mcp"
}
}
}
Claude Desktop adds remote servers under Settings → Connectors.
Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"openstreetmap-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/openstreetmap-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"openstreetmap-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/openstreetmap-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"openstreetmap-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/openstreetmap-mcp-server:latest"
]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- No API key. Nominatim and Overpass are public services; for heavy use, point
OSM_NOMINATIM_BASE_URLandOSM_OVERPASS_BASE_URLat your own instances.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/openstreetmap-mcp-server.git
- Navigate into the directory:
cd openstreetmap-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env to override endpoints or the User-Agent as needed
Configuration
| Variable | Description | Default |
|---|---|---|
OSM_NOMINATIM_BASE_URL | Nominatim base URL. A path prefix such as https://maps.example.com/nominatim is supported. | https://nominatim.openstreetmap.org |
OSM_OVERPASS_BASE_URL | Pins every query to one Overpass endpoint and disables failover. | unset |
OSM_OVERPASS_ENDPOINTS | Comma-separated, ordered Overpass endpoints; more than one enables failover. Ignored when OSM_OVERPASS_BASE_URL is set. | https://overpass-api.de/api/interpreter |
OSM_OVERPASS_MAX_CONCURRENCY | Max Overpass queries in flight per endpoint. Public instances allow one per user. | 1 |
OSM_USER_AGENT | User-Agent sent to Nominatim and Overpass. Required by usage policy. | openstreetmap-mcp-server/<package version> |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_SESSION_MODE | HTTP session mode: stateless, stateful, or auto. The server declares stateless in code; an explicit value overrides it. | stateless |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry. | false |
See .env.example for the full list of optional overrides. An invalid value for any OSM_* variable stops the server at startup with a message naming the variable.
Overpass endpoint failover
By default every Overpass query goes to one endpoint, the FOSSGIS-operated main instance. List more in OSM_OVERPASS_ENDPOINTS and a failed call moves to the next entry in order:
OSM_OVERPASS_ENDPOINTS="https://overpass-api.de/api/interpreter,https://overpass.private.coffee/api/interpreter"
- Endpoints that fail repeatedly are skipped for a while (30 seconds, doubling up to 10 minutes)
- When every endpoint fails, the call fails with
rate_limited,upstream_error,overpass_unavailable,endpoints_rejected,endpoints_exhausted, orendpoints_unavailable, with each endpoint's outcome in the message - Endpoints are reported by origin only (
https://overpass-api.de) inservingEndpoint, error messages, and logs - Extra entries are failover only and never add concurrency. For an instance that allows parallel queries, append
|Nto its entry (https://mirror.example/api/interpreter|4) for N slots; write a literal|in a URL as%7C. Never size a public FOSSGIS server - Calls waiting for a slot fail with
pacer_shedand aretryAfterof at least 30 seconds after 30 seconds in line
Adding an endpoint sends your queries to a third party. Check its usage policy on the OSM wiki instance list, confirm it holds global data (a regional instance answers out-of-extract queries with an empty HTTP 200), and expect mirrors to lag the main instance; servingEndpoint and data_timestamp show which host answered and how fresh its data was.
Running the server
Local development
- Build and run the production version:
# One-time build bun run rebuild # Run the built server bun run start:http # or bun run start:stdio - Run checks and tests:
bun run devcheck # Lints, formats, type-checks, and more bun run test # Runs the test suite
Docker
docker run --rm -p 3010:3010 ghcr.io/cyanheads/openstreetmap-mcp-server:latest
# or build locally
docker build -t openstreetmap-mcp-server .
docker run --rm -p 3010:3010 openstreetmap-mcp-server
The image serves HTTP at http://localhost:3010/mcp in stateless session mode and logs to /var/log/openstreetmap-mcp-server. OpenTelemetry peer dependencies are installed by default; build with --build-arg OTEL_ENABLED=false to omit them. Runtime telemetry stays off until you pass -e OTEL_ENABLED=true.
Project structure
| Directory | Purpose |
|---|---|
src/mcp-server/tools | Tool definitions (*.tool.ts) and shared input, formatting, and escaping helpers. Six tools across Nominatim and Overpass. |
src/services/nominatim | Nominatim service: paced API client for search, reverse, and lookup, plus error parsing. |
src/services/overpass | Overpass service: query builder, endpoint failover and executor, element normalizer, error parsing. |
src/config | Server-specific environment variable parsing and validation with Zod. |
tests/ | Unit and integration tests for tools, services, and security. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor logging,ctx.statefor storage - Register new tools in the
createApp()arrays insrc/index.ts - Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
Map data from OpenStreetMap contributors, available under the Open Database License (ODbL).
Questions fréquentes
Qu'est-ce que io.github.cyanheads/openstreetmap-mcp-server ?
Geocode, reverse geocode, and run Overpass spatial queries on OpenStreetMap data.
Comment installer io.github.cyanheads/openstreetmap-mcp-server ?
Il fonctionne comme serveur distant. Dans Claude Code : claude mcp add --transport http openstreetmap-mcp-server 'https://openstreetmap.caseyjhand.com/mcp'. Pour les autres clients, collez la configuration JSON de cette page dans leurs réglages MCP.
Faut-il une clé API pour io.github.cyanheads/openstreetmap-mcp-server ?
Son entrée au registre n'indique aucune clé ni secret obligatoire. Certaines fonctions peuvent tout de même demander un compte auprès du service auquel il se connecte.
io.github.cyanheads/openstreetmap-mcp-server est-il open source ?
Oui. Son code est sur GitHub sous licence Apache-2.0.
Qui maintient io.github.cyanheads/openstreetmap-mcp-server ?
Il est publié par cyanheads. AI.tn le référence sans le maintenir ni le recommander.
Issu du registre MCP officiel. Être listé n'est pas une recommandation : vérifiez le code et les permissions d'un serveur avant de lui donner accès à vos données.