chuk-mcp-geocoder
Provides geocoding and place discovery services using OpenStreetMap data via the Nominatim API, including forward/reverse geocoding, bounding box extraction, nearby places, batch geocoding, and administrative boundary lookup.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@chuk-mcp-geocoder Find the coordinates for the Statue of Liberty"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
chuk-mcp-geocoder
Geocoding & Place Discovery MCP Server via Nominatim/OpenStreetMap.
Provides forward/reverse geocoding, bounding box extraction, nearby places discovery, batch geocoding, route waypoints, and administrative boundary lookup — designed to work alongside other MCP geospatial servers (DEM, STAC, etc.).
This is a demonstration project provided as-is for learning and testing purposes.
Tools
Tool | Description |
| Place name to coordinates (lat, lon, bbox, address) |
| Coordinates to place name and address |
| Place name to |
| Find places near a coordinate at multiple scales |
| Administrative hierarchy (country, state, county, city, suburb) |
| Geocode multiple place names in one call |
| Geocode waypoints in order and compute route distances |
| Compute haversine distance matrix between multiple points |
| Server status and cache statistics |
| Full capabilities listing with LLM guidance |
Related MCP server: @cyanheads/openstreetmap-mcp-server
Installation
Using uvx (Recommended - No Installation Required!)
The easiest way to use the server is with uvx, which runs it without installing:
uvx chuk-mcp-geocoderThis automatically downloads and runs the latest version. Perfect for Claude Desktop!
Using uv (Recommended for Development)
# Install from PyPI
uv pip install chuk-mcp-geocoder
# Or clone and install from source
git clone <repository-url>
cd chuk-mcp-geocoder
uv sync --devUsing pip (Traditional)
pip install chuk-mcp-geocoderUsage
With Claude Desktop
Option 1: Use the Public Server (Easiest)
Connect to the hosted public server at chuk-mcp-geocoder.fly.dev:
MacOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%/Claude/claude_desktop_config.json
{
"mcpServers": {
"geocoder": {
"url": "https://chuk-mcp-geocoder.fly.dev/mcp"
}
}
}Option 2: Streamable HTTP URL (Local)
Run the server locally and connect via HTTP:
{
"mcpServers": {
"geocoder": {
"url": "http://localhost:8010/mcp"
}
}
}Then start the server:
uvx chuk-mcp-geocoder httpOption 3: Run Locally with uvx
{
"mcpServers": {
"geocoder": {
"command": "uvx",
"args": ["chuk-mcp-geocoder"]
}
}
}Option 4: Run Locally with pip
{
"mcpServers": {
"geocoder": {
"command": "chuk-mcp-geocoder"
}
}
}Standalone
Run the server directly:
# With uvx (recommended - always latest version)
uvx chuk-mcp-geocoder
# With uvx in HTTP mode
uvx chuk-mcp-geocoder http
# Or if installed locally
chuk-mcp-geocoder
chuk-mcp-geocoder httpOr with uv/Python:
# STDIO mode (default, for MCP clients)
uv run chuk-mcp-geocoder
# or: python -m chuk_mcp_geocoder.server
# HTTP mode (for web access and streamable HTTP)
uv run chuk-mcp-geocoder http
# or: python -m chuk_mcp_geocoder.server http
# HTTP mode with custom host/port
uv run chuk-mcp-geocoder http --host 0.0.0.0 --port 9000STDIO mode is for MCP clients like Claude Desktop and mcp-cli. HTTP mode runs a web server on http://localhost:8010 for HTTP-based MCP clients.
Usage with MCP CLI
uv run mcp-cli --server geocoder,dem,stacThen ask:
"Get the elevation profile for Mersea Island"
The LLM will use bbox_from_place or geocode to resolve the location, then pass coordinates to the DEM server.
Configuration
Environment Variable | Description | Default |
| Contact email for Nominatim API | (none) |
| Custom Nominatim instance URL |
|
| Force stdio transport mode | (auto-detect) |
Development
Setup
# Clone the repository
git clone <repository-url>
cd chuk-mcp-geocoder
# Install with uv (recommended)
uv sync --dev
# Or with pip
pip install -e ".[dev]"Running Tests
make test # Run tests
make test-cov # Run tests with coverage
make coverage-report # Show coverage reportCode Quality
make lint # Run linters
make format # Auto-format code
make typecheck # Run type checking
make security # Run security checks
make check # Run all checksBuilding
make build # Build package
make publish-test # Upload to TestPyPI for testing
make publish-manual # Manually upload to PyPI (requires PYPI_TOKEN)
make publish # Create tag and trigger GitHub Actions releaseArchitecture
Follows the same 5-layer pattern as chuk-mcp-dem:
core/nominatim.py — Async HTTP client with rate limiting and LRU cache
core/geocoder.py — Async manager with validation and typed dataclass results
models/responses.py — Pydantic v2 response models (
extra="forbid",to_text())constants.py — All configuration, messages, and metadata
tools/*/api.py — MCP tool registration with
@mcp.tool()decorators
Public Server
A public instance is hosted at chuk-mcp-geocoder.fly.dev for easy access:
URL:
https://chuk-mcp-geocoder.fly.dev/mcpProtocol: MCP over HTTPS (Streamable HTTP)
Free to use: No API key required
Always up-to-date: Running the latest version
Simply add it to your Claude Desktop config:
{
"mcpServers": {
"geocoder": {
"url": "https://chuk-mcp-geocoder.fly.dev/mcp"
}
}
}Data Source
All geocoding data comes from OpenStreetMap via the Nominatim API.
Data license: ODbL 1.0
API rate limit: 1 request/second (public API)
Results are cached in-memory (1 hour TTL)
License
Apache-2.0
Available Tools
10 toolsadmin_boundariesA
Get administrative boundary hierarchy for a location.
Returns the full admin hierarchy from country down to neighbourhood
for the given coordinates.
Args:
lat: Latitude (-90 to 90)
lon: Longitude (-180 to 180)
output_mode: "json" (default) or "text"
Returns:
Administrative boundaries from largest to smallest
Inputs: lat (required), lon (required), output_mode.
batch_geocodeA
Geocode multiple place names in one call.
Each query is processed sequentially to respect Nominatim rate limits.
Individual failures don't abort the batch.
Args:
queries: JSON array of place names (e.g. '["Boulder, CO", "Denver, CO"]')
limit: Maximum results per query (default 1)
output_mode: "json" (default) or "text"
Returns:
Per-query results with coordinates, or error for failed queries
CRITICAL — LLM retry guidance:
If any query in the batch fails, re-run only the failed queries
with simplified names using the single geocode tool. Nominatim
works best with simple place names — remove landmarks, qualifiers,
and descriptive words before retrying.
Inputs: queries (required), limit, output_mode.
bbox_from_placeA
Get a bounding box for a place, suitable for DEM/STAC tools.
Returns bbox as [west, south, east, north] in EPSG:4326, compatible
with dem_fetch, stac_search, dem_slope, and other geospatial tools.
Args:
query: Place name to get bbox for (e.g. "Palm Jumeirah, Dubai")
padding: Fractional padding to expand bbox (0.1 = 10% on each side, default 0.0)
output_mode: "json" (default) or "text"
Returns:
Bounding box [west, south, east, north], center point, and approximate area
CRITICAL — LLM retry workflow when no results are found:
If the query returns no results, you MUST retry automatically — do
NOT ask the user. Simplify the query progressively:
1. Remove specific landmarks/features, keep the broader place.
"Strood Causeway, Mersea Island" → "Mersea Island"
2. Drop region/country qualifiers if still no results.
"Mersea Island, Essex, UK" → "Mersea Island"
3. Try alternative or official names for the place.
4. If using a broader place, consider adding padding to cover the
area of interest (e.g. padding=0.1 for 10% expansion).
Always retry at least twice before reporting failure.
Inputs: query (required), padding, output_mode.
distance_matrixA
Compute haversine distance matrix between multiple points.
Pure computation — no API calls needed. Accepts points as either
[lat, lon] pairs or {"name": ..., "lat": ..., "lon": ...} objects.
Args:
points: JSON array of points. Each point is either:
- [lat, lon] pair (auto-named "Point 1", "Point 2", ...)
- {"name": "Label", "lat": 40.0, "lon": -105.0}
output_mode: "json" (default) or "text"
Returns:
NxN distance matrix in metres between all point pairs
Inputs: points (required), output_mode.
geocodeA
Forward geocode a place name to coordinates.
Searches the OpenStreetMap/Nominatim database for places matching
the query and returns coordinates, bounding boxes, and address details.
Args:
query: Place name or address to search for (e.g. "Boulder, Colorado")
limit: Maximum results (1-50, default 5)
countrycodes: Comma-separated ISO 3166-1 country codes to filter (e.g. "us,gb")
language: Preferred response language (e.g. "en", "de", "fr")
output_mode: "json" (default) or "text"
Returns:
List of matching places with coordinates, bbox, and address details
CRITICAL — LLM retry workflow when no results are found:
Nominatim works best with simple, well-known place names. Specific
or compound names (e.g. "Strood Causeway, Mersea Island, UK") often
return nothing.
If the query returns no results, you MUST retry automatically — do
NOT ask the user. Follow this cascade:
1. Remove qualifiers and landmarks — keep only the core place name.
"Strood Causeway, Mersea Island, UK" → "Mersea Island, UK"
"Portland Harbor, Maine" → "Portland, Maine"
2. Simplify further — drop region/country qualifiers.
"Mersea Island, UK" → "Mersea Island"
"Portland, Maine" → "Portland"
3. Use countrycodes to narrow broad queries (e.g. countrycodes="gb").
4. If the place is near a well-known location, geocode that instead
and report the approximate area.
5. Try alternative or official names — "The Strood" instead of
"Strood Causeway", etc.
Always retry at least twice with progressively simpler terms before
telling the user the location could not be found.
Inputs: query (required), limit, language, output_mode, +1 more.
geocoder_capabilitiesB
Get full server capabilities.
Returns the complete list of tools, Nominatim API details,
and LLM-friendly usage guidance.
Args:
output_mode: "json" (default) or "text"
Returns:
Full server capabilities including tool lists and guidance
Inputs: output_mode.
geocoder_statusA
Get geocoder server status.
Returns server version, Nominatim URL, cache stats, and tool count.
Args:
output_mode: "json" (default) or "text"
Returns:
Server status information
Inputs: output_mode.
nearby_placesA
Find places near a coordinate.
Discovers nearby places at different scales (buildings, streets,
suburbs, cities) using reverse geocoding at multiple zoom levels.
Args:
lat: Latitude (-90 to 90)
lon: Longitude (-180 to 180)
limit: Maximum number of results (default 10)
categories: Comma-separated OSM categories to filter (e.g. "natural,tourism")
output_mode: "json" (default) or "text"
Returns:
List of nearby places with distances, sorted by proximity
Inputs: lat (required), lon (required), limit, categories, +1 more.
reverse_geocodeA
Reverse geocode coordinates to a place name and address.
Looks up the nearest place for the given coordinates and returns
the display name, structured address, and bounding box.
Args:
lat: Latitude (-90 to 90)
lon: Longitude (-180 to 180)
zoom: Detail level 0-18 (18=building, 10=city, 3=country, default 18)
language: Preferred response language (e.g. "en", "de", "fr")
output_mode: "json" (default) or "text"
Returns:
Place name, address components, and bounding box
Inputs: lat (required), lon (required), zoom, language, +1 more.
route_waypointsA
Geocode waypoints in order and compute route distances.
Resolves each waypoint to coordinates, then computes haversine
distances between consecutive points.
Args:
waypoints: JSON array of place names in route order
(e.g. '["Boulder, CO", "Denver, CO", "Aspen, CO"]')
output_mode: "json" (default) or "text"
Returns:
Resolved waypoints, leg distances, total distance, and bounding box
CRITICAL — LLM retry guidance:
If a waypoint fails to resolve, simplify its name and retry the
entire route. Remove landmarks, qualifiers, and descriptive words.
Use the single geocode tool to test problematic names first.
Inputs: waypoints (required), output_mode.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 10 tools
Most tools have distinct purposes, but bbox_from_place and geocode overlap slightly (both take place names) and batch_geocode is a batch version of geocode. Descriptions clarify differences, so agents can likely distinguish them.
All names use snake_case and are descriptive, but they mix verb phrases (geocode, reverse_geocode), noun phrases (geocoder_status, admin_boundaries), and compound expressions (bbox_from_place, nearby_places). No single consistent pattern.
10 tools is appropriate for a geocoding server, covering forward/reverse geocoding, batch operations, bbox extraction, nearby places, admin boundaries, routing, and distance computation without being excessive.
Covers core geocoding operations well. Minor gaps: no explicit search by category or type, but nearby_places and admin_boundaries provide related functionality. The retry workflows in descriptions enhance completeness.
Maintenance
Related MCP Connectors
Geocode, reverse geocode, and run Overpass spatial queries on OpenStreetMap data.
Geocode, reverse geocode, and run Overpass spatial queries on OpenStreetMap data.
Geocode, reverse-geocode, autocomplete, route and search places.
Geocoding, static maps and privacy-safe area maps from OpenStreetMap data. Hard caps, no overage.
Related MCP Servers
- AlicenseAqualityFmaintenanceAn MCP server providing geocoding and place discovery services via Nominatim and OpenStreetMap. It enables users to perform forward and reverse geocoding, extract bounding boxes, and find nearby places or administrative hierarchies.10Apache 2.0
- AlicenseNot gradedqualityAmaintenanceGeocode, reverse geocode, and run Overpass spatial queries on OpenStreetMap data via MCP.802 npm9Apache 2.0
- AlicenseAqualityDmaintenanceProvides location-based services and geospatial data from OpenStreetMap, enabling geocoding, route directions, nearby place search, and neighborhood analysis through natural language.12MIT
- AlicenseAqualityCmaintenanceEnables LLMs to geocode and reverse geocode places, find nearby points of interest, search categories within an area, get turn-by-turn routing, suggest meeting points, and analyze neighborhoods, commutes, schools, EV charging, and parking through OpenStreetMap data services. It also serves place and map tile resources over stdio, SSE, or Streamable HTTP transports.12MIT