Skip to main content
Glama

maps-mcp

An MCP server that gives AI assistants map capabilities (geocoding, places, routing, distance matrices, isochrones and static maps) from several providers behind one coherent tool surface.

Status: early development. The server skeleton runs over stdio and streamable HTTP and exposes a ping tool. No provider adapters yet. The backlog is in Issues and the design questions are in Discussions.

Planned provider coverage

Area

Providers

Google Maps Platform

Places (New), Routes, Geocoding, Address Validation (later: Solar, Area Insights, Route Optimization, Isochrones)

OpenStreetMap

Nominatim (geocode, reverse, lookup), Overpass (POI and feature queries)

Open-source routing engines

OSRM, Valhalla, OpenRouteService, GraphHopper

Other open geocoders and tiles

Photon, Pelias, static map rendering

Related MCP server: mapsi-mcp

Approach

  • Stack: Python 3.11+ and FastMCP 4.1.4 (fastmcp, built on the official mcp Python SDK). Tools and provider calls are async throughout.

  • Transports: stdio (default, for local MCP clients) and streamable HTTP (for remote use), both from the start.

  • One tool surface: provider-agnostic tools (geocode, search_places, get_directions, ...) with an explicit provider option and configurable fallbacks. This is still an open design question, so join the discussion.

  • Policy-aware: each adapter respects the provider's usage policy and terms (rate limits, caching, attribution).

  • Scrum, epics first: work is organised as epics, stories and spikes. See CONTRIBUTING.md.

Running the server

uv run maps-mcp                                      # stdio (default)
uv run maps-mcp --transport http                     # streamable HTTP on http://127.0.0.1:8000/mcp
uv run maps-mcp --transport http --host 0.0.0.0 --port 9000
uv run maps-mcp --version

Option

Environment variable

Default

Notes

--transport

MAPS_MCP_TRANSPORT

stdio

stdio, http or streamable-http (the last two are the same)

--host

MAPS_MCP_HOST

127.0.0.1

HTTP only. Local only by default

--port

MAPS_MCP_PORT

8000

HTTP only

Command-line options win over environment variables. The HTTP endpoint is served at /mcp.

Security: the HTTP transport has no authentication yet (tracked in #84). It binds to 127.0.0.1 by default. Do not expose it beyond localhost or a trusted network until auth lands.

The ping tool

ping takes no arguments and returns the server version and the enabled providers, identically on both transports:

{ "version": "0.1.0", "providers": [] }

providers is empty until the provider registry lands.

Connecting MCP clients

Replace /absolute/path/to/maps-mcp with your checkout.

Claude Code, stdio:

claude mcp add maps-mcp -- uv run --directory /absolute/path/to/maps-mcp maps-mcp

Claude Desktop, stdio (~/Library/Application Support/Claude/claude_desktop_config.json on macOS). Claude Desktop does not inherit your shell PATH, so use the absolute path from which uv:

{
  "mcpServers": {
    "maps-mcp": {
      "command": "/opt/homebrew/bin/uv",
      "args": ["run", "--directory", "/absolute/path/to/maps-mcp", "maps-mcp"]
    }
  }
}

Claude Code, streamable HTTP (start the server first with uv run maps-mcp --transport http):

claude mcp add --transport http maps-mcp http://127.0.0.1:8000/mcp

or in a project .mcp.json, here for a hosted deployment:

{
  "mcpServers": {
    "maps-mcp": {
      "type": "http",
      "url": "https://maps-mcp.example.com/mcp"
    }
  }
}

Claude Desktop, streamable HTTP: add a remote server under Settings, Connectors, Add custom connector. That route goes through Anthropic's cloud, so the URL must be publicly reachable (and, until #84 lands, unauthenticated, so do not do this with real deployments yet). For a server on your own machine, bridge it to stdio with mcp-remote:

{
  "mcpServers": {
    "maps-mcp": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://127.0.0.1:8000/mcp"]
    }
  }
}

MCP Inspector

# stdio: the Inspector launches the server itself
npx @modelcontextprotocol/inspector uv run maps-mcp

# streamable HTTP: start the server in one terminal ...
uv run maps-mcp --transport http
# ... then open the Inspector, pick "Streamable HTTP" and enter http://127.0.0.1:8000/mcp
npx @modelcontextprotocol/inspector

For a non-interactive check, use the Inspector CLI mode:

npx @modelcontextprotocol/inspector --cli .venv/bin/maps-mcp --method tools/call --tool-name ping
npx @modelcontextprotocol/inspector --cli http://127.0.0.1:8000/mcp --transport http --method tools/call --tool-name ping

Development

Requires Python 3.11+ and uv (brew install uv on macOS, see the uv docs for other platforms).

uv sync                      # install the project and dev tools into .venv
uv run ruff check .          # lint (add --fix to autofix)
uv run ruff format .         # format
uv run mypy                  # type-check (strict)
uv run pytest                # tests
uv run maps-mcp              # run over stdio (see "Running the server" for HTTP)

Before opening a PR, make sure all of these are clean:

uv run ruff check . && uv run ruff format --check . && uv run mypy && uv run pytest

Add dependencies with uv add <pkg> (or uv add --dev <pkg>) and commit the updated uv.lock.

Contributing

Start with Discussions for ideas and design questions, then pick up an issue labelled ready. Details are in CONTRIBUTING.md.

License

MIT. The licence choice is open for discussion before the first release.

Available Tools

1 tool
pingPingA

Check that the server is up. Returns the server version and the enabled providers.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription
versionYes
providersYes

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden, but it does disclose the useful behavioral fact that this is a non-mutating probe returning version and provider info. It omits auth requirements, whether the call can fail/timeout, and any rate limits, which is a real gap for a tool with zero annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the action and followed by the return content. Nothing superfluous.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values needn't be spelled out, and the description still previews them. For a simple probe tool this is nearly complete; only failure/auth behavior is unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes no parameters, so there is nothing for the description to disambiguate; baseline 4 applies. The description correctly implies a parameterless call.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Check that the server is up') and adds what the call yields (server version, enabled providers). An agent knows exactly what this tool does without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied by 'Check that the server is up' — a health/verification call. There are no sibling tools to differentiate from and no explicit guidance on when to prefer it, so 3 is the honest ceiling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev0.1.0
    • First observedping

TDQS

A3.6/5.0

Scored across 1 tool

Disambiguation5/5

There is only one tool, so there is no possibility of confusing it with another. Its purpose (health check) is stated unambiguously.

Naming Consistency4/5

The single name `ping` is a clean, lowercase verb with no competing conventions to clash with. There is no multi-tool pattern to evaluate, so consistency is only trivially satisfied.

Tool Count1/5

A server named maps-mcp exposes exactly one trivial health-check tool. This is an extreme mismatch between the implied mapping domain and the actual one-tool surface.

Completeness1/5

The surface contains no mapping operations at all — no geocoding, routing, place search, or map retrieval. Only a liveness probe exists, leaving any real workflow impossible.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Geospatial API tools for AI agents — geocoding, reverse geocoding, routing, isochrone, distance matrix, static maps, H3 hexagons, elevation, GPS map-matching, point-in-polygon, address normalisation, timezone lookup, and batch geocoding. Built on OpenStreetMap infrastructure. Cost-effective alternative to Google Maps API.
    18
    13 npm
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Enables AI agents to become geospatially intelligent assistants with tools for location search, smart routing, round trip planning, reverse geocoding, isochrone analysis, route visualization, geofence management, and interactive map display.
    8
    13 npm
    7
    Apache 2.0