A Model Context Protocol (MCP) server that provides a dynamic map interface. This robust Python server enables AI agents to control a MapLibre GL JS - based map viewer, allowing for real-time visualization of geospatial data.
- MCP & HTTP Support: Implements the Model Context Protocol using
StreamableHTTPServerTransport. - Real-time Updates: Uses Server-Sent Events (SSE) to push map state changes to the browser instantly.
- Interactive Map: Powered by MapLibre GL JS for high-performance vector and raster mapping.
- Tooling: Provides MCP tools to:
- Add/Remove layers (Raster & Vector)
- Set map view (Center & Zoom)
- Filter data
- Style layers
- In-Memory State: Simple, stateless deployment model (ideal for K8s).
-
MCP Server (
server.py): AStarletteapplication that:- Exposes an MCP endpoint at
/mcp(Streamable HTTP). - Exposes an SSE endpoint at
/eventsfor the browser. - Serves the static map viewer at
/. - Maintains map state in-memory.
- Exposes an MCP endpoint at
-
MCP Client (AI Agent): Connects to
/mcpto call tools and modify the map state. -
Map Viewer (Browser): Connects to
/eventsto receive state updates and render them using MapLibre GL JS.
-
Clone and install:
git clone https://github.com/boettiger-lab/mcp-map-server.git cd mcp-map-server python -m venv .venv source .venv/bin/activate pip install -e .[dev]
-
Start the server:
mcp-map-server
-
Open the Map: Navigate to
http://localhost:8081in your browser. -
Connect an MCP Client: Configure your MCP client (e.g., Claude Desktop, Cursor, or a custom script) to connect to
http://localhost:8081/mcp/.
Run the test suite with:
pytestThe tests will automatically start a test server on port 8082.
The server supports MCP prompts to provide AI agents with information about available data layers. This helps agents understand which layers are available, their attributes, and how to use them effectively.
Recommended: Use a Markdown file
You can provide a system prompt as a plain markdown file:
mcp-map-server --prompt-file my-layers.mdSet via environment variable:
This is useful for containerized deployments:
export MCP_MAP_SYSTEM_PROMPT="$(cat my-layers.md)"
mcp-map-serverDirect string argument:
mcp-map-server --prompt "# Available Layers\n\n- wdpa: Protected Areas..."See system-prompt.example.md for a complete example of layer configuration.
-
Deploy:
kubectl apply -f k8s/configmap.yaml kubectl apply -f k8s/deployment.yaml kubectl apply -f k8s/service.yaml kubectl apply -f k8s/ingress.yaml
The ConfigMap
mcp-map-configshould contain your system prompt markdown in thesystem-promptkey.
The MCP Map Server follows a Tool-Centric model. Instead of one shared map, it provides tools that help clients manage their own independent map configurations.
-
Local Private Map (VSCode/Local Agent)
- Run the server locally:
mcp-map-server - View your map at:
http://localhost:8081/ - Everything stays on your machine. Your local AI agent updates your local browser via SSE.
- Run the server locally:
-
Private Session on Public Server
- Visit the shared server with a unique session ID:
https://mcp-map.nrp-nautilus.io/?session=my-private-uuid - Tell your AI agent to use this
session_id. - Only you (and whoever has the ID) will see the updates.
- Visit the shared server with a unique session ID:
-
Stateless/Unhosted (Web Developers)
- For clients like LangChain-js or custom web apps.
- Pass an existing map JSON string as the
stateargument to any tool. - The tool returns the full updated JSON without saving anything to the server's memory.
- Your app can then render this JSON using its own viewer component.
Every map-modifying tool returns the full, updated map configuration in JSON format.
add_layer: Adds a raster (XYZ/Tiles) or vector (MVT/PMTiles) layer.set_map_view: Moves the camera to a specificcenterandzoom.filter_layer: Applies MapLibre filter expressions to an existing layer.set_layer_paint: Dynamically modifies paint properties (colors, opacity, etc.).remove_layer: Deletes a layer by ID.get_map_config: Returns the current session/provided state as JSON.
To use this with MCP-compatible clients like Claude Desktop or VSCode extensions, point them to the server.
Local Development (Recommended):
Local clients like Claude Desktop and VSCode expect StdIO transport when launching a command. The server now defaults to stdio.
Tip
Use the absolute path to the executable in your config to avoid "command not found" (ENOENT) errors. Find it by running which mcp-map-server.
{
"mcpServers": {
"map-server": {
"command": "/home/cboettig/.local/bin/mcp-map-server"
}
}
}Passing CLI Arguments (Transport, Prompts, etc.):
If you need to specify the transport explicitly or provide a custom system prompt file, use the args array.
Important
Arguments must be passed as individual elements in the args array, NOT as part of the command string.
{
"mcpServers": {
"map-server": {
"command": "/home/cboettig/.local/bin/mcp-map-server",
"args": [
"--transport", "stdio",
"--prompt-file", "/path/to/my-layers.md"
]
}
}
}Note: The server defaults to stdio when run as a command.
Using the Shared Production Server:
Web-based or remote clients connect via HTTP.
{
"mcpServers": {
"map-server": {
"url": "https://mcp-map.nrp-nautilus.io/mcp/"
}
}
}MIT
