mcp-geo-server
Provides integration with local or cloud Ollama models as the LLM backend for the agent, enabling natural language processing of geospatial requests to drive GeoServer operations.
Click on "Install 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., "@mcp-geo-serverhow many features are in topp:states?"
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.
mcp-geo-server
An intelligent MCP (Model Context Protocol) server that lets you drive a
GeoServer instance in natural language. It is built with the Microsoft
Agent Framework: an LLM-backed agent is given the GeoServer operations as
tools and exposed as a single MCP tool via agent.as_mcp_server(). The LLM
backend is pluggable — local Ollama, Ollama Cloud, or Anthropic
Claude. Any MCP client sends a request like "how many features in
topp:states?" and the agent decides which GeoServer operations to call.
Under the hood the agent can: manage workspaces, PostGIS datastores, feature types, layers and SLD styles via the REST API, and query/edit data via the OGC services (WMS, WFS GetFeature → GeoJSON, WFS-T insert/update/delete). It ships with a small Leaflet web UI and a Docker stack (GeoServer + PostGIS + Ollama) for local development.
The same async core (GeoServerClient + the geo_* tool functions) is shared by
the agent and the web UI — there is exactly one place that talks to GeoServer.
Prerequisites
Python 3.11+
Docker + Docker Compose (for the local GeoServer/PostGIS stack)
Related MCP server: AnythingLLM MCP Server
1. Start the stack (Docker)
make build # build the app image + pull GeoServer/PostGIS/Ollama
make ollama-pull # download the LLM model into the Ollama container (once)
make docker-up # start everythingThe Compose project is named mcp-geo-server; containers are named coherently:
Service | Container | Endpoint |
|
| http://localhost:9000/mcp — intelligent MCP server (streamable-HTTP) |
|
| http://localhost:8000 — Leaflet test UI |
|
| http://localhost:8080/geoserver (admin / |
|
| http://localhost:11434 — local LLM backend |
|
|
|
GeoServer runs with CORS_ENABLED=true so the browser UI can call OGC services
directly. PostGIS has a healthcheck and GeoServer waits for it. The mcp agent
talks to GeoServer and Ollama over the internal Compose network.
2. Install
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev,webui]"
cp .env.example .env # then edit as needed3. Configuration (environment variables)
Variable | Default | Meaning |
| — (required) | Base URL, e.g. |
| — (required) | REST username |
| — (required) | REST password |
| (none) | Workspace used when a tool omits one |
|
| SRS used when publishing without one |
|
| HTTP timeout (seconds) |
|
| Retry attempts on connect/timeout/502/503/504 |
|
| Linear backoff factor (seconds × attempt) |
|
| Verify TLS certificates |
|
| Where generated maps / downloaded PNGs are saved |
|
| Port for the test UI |
|
| Agent LLM backend: |
|
| Local Ollama endpoint ( |
|
| Ollama model (must support tool calling); cloud model id for |
|
| Ollama Cloud endpoint ( |
| (none) | Ollama Cloud API key (required for |
| (none) | Anthropic API key (required for |
|
| Claude model ( |
|
| MCP transport: |
|
| Bind host when transport is |
|
| Port when transport is |
Secrets are never hardcoded — everything is read from the environment.
4. The intelligent MCP server (Microsoft Agent Framework)
The MCP server is an agent, not a flat list of tools. server.py builds a
GeoServer agent (agent.py: a chat client + the geo_* functions as tools) and
exposes it with agent.as_mcp_server(). The MCP client therefore sees one
tool, geoserver-agent, that takes a natural-language task.
Choosing the LLM backend (GEO_LLM_PROVIDER)
Provider | Value | Needs | Notes |
Local Ollama |
| the | Default. No API key; run |
Ollama Cloud |
|
| Hosted models at |
Anthropic Claude |
|
| Uses |
Examples:
# Ollama Cloud
GEO_LLM_PROVIDER=ollama-cloud OLLAMA_API_KEY=sk-... OLLAMA_MODEL=gpt-oss:120b mcp-geo-server
# Anthropic Claude
GEO_LLM_PROVIDER=anthropic ANTHROPIC_API_KEY=sk-ant-... mcp-geo-serverFor Docker, set the same variables in your shell (or .env) before make docker-up; the mcp service forwards them. With ollama-cloud/anthropic the
local ollama container is not needed.
Run it over either transport (selected by GEO_MCP_TRANSPORT):
# stdio (for MCP clients that spawn the process, e.g. Claude Desktop)
mcp-geo-server
# streamable-HTTP (long-lived, visible container) at http://localhost:9000/mcp
GEO_MCP_TRANSPORT=http mcp-geo-serverIn Docker the mcp service runs it over HTTP. Example MCP client call:
from mcp.client.streamable_http import streamablehttp_client
from mcp import ClientSession
async with streamablehttp_client("http://localhost:9000/mcp") as (r, w, _):
async with ClientSession(r, w) as s:
await s.initialize()
res = await s.call_tool("geoserver-agent",
{"task": "How many features are in topp:states?"})
print(res.content[0].text)For a stdio MCP client (claude_desktop_config.json), point command at
mcp-geo-server and set the GEOSERVER_* / OLLAMA_* env vars.
5. Run the test UI
uvicorn webui.app:app --reload --port 8000Open http://localhost:8000. The sidebar has a form for each operation (create workspace / PostGIS datastore, publish a feature type, create + assign a style, run a WFS query) plus a connection-status indicator. The map uses an OpenStreetMap basemap and shows selected layers as WMS overlays; the "Carica come GeoJSON" button fetches features via WFS and draws them with popups.
6. Tests
pytest # unit + behavioural (no GeoServer needed)
GEO_RUN_INTEGRATION=1 pytest tests/integration # live round-trip vs real GeoServertests/test_formatting.py,test_styles_helpers.py,test_ogc_helpers.py,test_map_template.py— pure helpers / template rendering.tests/test_tools_behaviour.py— every tool driven with aFakeClient, asserting on the request bodies / params / WFS-T XML (no network).tests/integration/test_live.py— status + create/list/delete workspace round-trip; skipped unlessGEO_RUN_INTEGRATION=1.tests/evals/geo_eval.xml— read-only eval questions against GeoServer's standard sample data (e.g.topp:stateshas 49 features). Confirm the expected answers on your live instance.
Agent tools (28 geo_* functions)
These are the tools the agent calls internally to fulfil a request (they are not
exposed individually over MCP — the agent is). make tools lists them.
Tool | Kind | Description |
| read | Version + connectivity ( |
| read | List workspaces |
| read | Get one workspace |
| write | Create workspace (optionally default) |
| destructive | Delete workspace ( |
| read | List datastores in a workspace |
| read | Get one datastore |
| write | Create a PostGIS datastore |
| destructive | Delete datastore ( |
| read | List feature types (or available tables) |
| write | Publish a table as a layer (recalculates bbox) |
| read | List layers |
| read | Get one layer |
| read | Layer bounding boxes + SRS |
| idempotent | Set default style / enabled flag |
| destructive | Delete layer (+ feature type cleanup) |
| read | List styles |
| read | Get style SLD |
| write | Create style from SLD string/file |
| idempotent | Replace style SLD |
| idempotent | Assign style to layer (default/extra) |
| destructive | Delete style ( |
| read | WMS GetCapabilities |
| read | Build WMS GetMap URL (optionally download PNG) |
| read | WFS GetCapabilities |
| read | WFS GetFeature → GeoJSON (bbox or CQL) |
| write | WFS-T delete / update / raw |
| read | Generate a Leaflet HTML map (OSM + WMS overlays) |
The agent's instructions (agent.py) tell it to treat delete_* as
destructive and only run them on explicit request.
Resilience knobs
Retry with linear backoff on connect errors, timeouts, and HTTP 502/503/504 — controlled by
GEOSERVER_RETRIESandGEOSERVER_RETRY_BACKOFF.Actionable errors: 401/403/404/405/409/500 are translated into messages with a suggested fix.
OGC exceptions:
ServiceExceptionReport/ServiceException(which arrive with HTTP 200) are detected and raised with the response body.Logging on the
mcp_geo_serverlogger (setGEO_LOG_LEVEL=DEBUG).
Project layout
src/mcp_geo_server/ core: config, client, formatting, agent (Agent Framework),
server (MCP stdio/http), tools/ (geo_* functions), templates/
webui/ FastAPI backend (app.py) + static Leaflet UI (static/index.html)
tests/ unit, behavioural, integration, evals
Dockerfile app image (web UI + MCP agent)
docker-compose.yml GeoServer 2.28.0 + PostGIS 16-3.4 + Ollama + webui + mcpThis server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/agent-engineering-studio/mcp-geo-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server