Cet article est publié en anglais.
Connecting AI Agents to GeoServer 2.28 Through the MCP Extension
Install the GeoServer MCP extension JAR, check it loaded, call the endpoint with curl, wire up Claude Desktop or LangChain, and lock down access and write tools.
Give AI agents a live view of GeoServer
One extension plus one restart is all it takes for an agent to query your catalog over MCP. You don't run a Python sidecar or an extra Docker container. These notes cover version 0.1.0 of the GeoServer MCP Extension and GeoServer 2.28.x. It ships as a GitHub pre-release JAR, and it's no replacement for the geoserver-mcp package on PyPI.
What the extension does
It's a regular GeoServer plugin. Once the JAR sits in GeoServer and the server has restarted, GeoServer itself speaks MCP at this address:
http://127.0.0.1:8080/geoserver/mcp
Agents send JSON-RPC over HTTP (Streamable HTTP), and GeoServer answers from its own catalog. Results are still filtered by GeoServer's security rules.
Tool names for catalog work (list, get, query, create, delete, publish) are the same ones the Python MCP server uses. The Python package's administrative extras (user management, reload, filesystem uploads) don't come along, which comes up again under common mistakes below.
Write tools are enabled by default. For a read-only endpoint, put mcp.allowWrites=false into the data directory's configuration.
On Windows, write 127.0.0.1 instead of localhost. A few Python MCP clients turn localhost into the IPv6 address ::1 and receive HTTP 503, even when the IPv4 route is fine.
Requirements
- GeoServer 2.28.x on Java 17 or 21
- A GeoServer user (a fresh install ships with
admin/geoserver) - The extension JAR, covered next
Keep this JAR out of GeoServer 2.20.x and 3.x. Version 2.20 runs on Java 11 and won't start, returning HTTP 503. GeoServer 3 moved to Jakarta Servlet, and this build won't load there. If an older GeoServer is still needed for other work, leave it alone and run a separate 2.28 install for the plugin.
Getting the JAR
The file you want is gs-mcp-0.1.0.jar, published as a GitHub release, and the download link is https://download.gis-mcp.com/geoserver-mcp-extension and keep it somewhere handy, such as the Downloads folder. You can also build it or fetch it from the repository at https://github.com/mahdin75/geoserver-mcp.
Installing it
- Open GeoServer and check About & Status, then About GeoServer. The version has to start with 2.28.
- Stop GeoServer.
- Copy
gs-mcp-0.1.0.jarinto theWEB-INF/libfolder of the web app. For the binary/Jetty bundle that's<GEOSERVER_ROOT>/webapps/geoserver/WEB-INF/lib, and for Tomcat it's<CATALINA_BASE>/webapps/geoserver/WEB-INF/lib.
On Windows the final path often looks like this:
D:\geoserver-2.28.5\webapps\geoserver\WEB-INF\lib\gs-mcp-0.1.0.jar
Then start the server again:
Start GeoServer.
There's no web.xml to edit, because GeoServer picks the plugin up by itself.
Checking that it loaded
- Open http://127.0.0.1:8080/geoserver/web/ and log in.
- Go to About & Status, then Modules.
- Look for GeoServer MCP Extension (
gs-mcp).
If the web UI itself returns 503 after the copy, the JAR went into the wrong GeoServer. Remove it, restart, and install into a 2.28.x instance.
Calling the endpoint
The plugin lives at /mcp inside the GeoServer web app, which makes the public URL /geoserver/mcp for a GeoServer mounted at /geoserver. A login is required out of the box, using HTTP Basic with a real GeoServer user. In Windows PowerShell, call curl.exe, because plain curl is a different command.
Initialize
curl.exe -s -u admin:geoserver \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2025-03-26" \
-d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-03-26\",\"capabilities\":{},\"clientInfo\":{\"name\":\"curl\",\"version\":\"1.0\"}}}" \
http://127.0.0.1:8080/geoserver/mcp
List the tools
curl.exe -s -u admin:geoserver \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2025-03-26" \
-d "{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\"}" \
http://127.0.0.1:8080/geoserver/mcp
Expect around 30 catalog tools in the reply, for instance list_workspaces, list_layers, create_workspace and query_features.
List layers
curl.exe -s -u admin:geoserver \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2025-03-26" \
-d "{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"tools/call\",\"params\":{\"name\":\"list_layers\",\"arguments\":{}}}" \
http://127.0.0.1:8080/geoserver/mcp
Three quick sanity checks:
- A POST with
-u admin:geoserverreturns a JSON result. - A POST with no user returns HTTP 401.
- A GET on
/geoserver/mcpreturns HTTP 405.
Connecting an AI client
A client only needs to be able to send JSON by POST to a URL. Claude Desktop and LangChain aren't built into the plugin, so all you do is aim the client at GeoServer.
Claude Desktop
Local MCP servers reach Claude Desktop over stdio, but this plugin is an HTTP service. A small bridge called mcp-remote connects the two, and it needs Node.js so that npx exists.
- Open Settings, then Developer, then Edit Config, which opens
claude_desktop_config.json. On Windows it lives at%APPDATA%\Claude\claude_desktop_config.json, and on macOS at~/Library/Application Support/Claude/claude_desktop_config.json. - Add the server below, keeping any other
mcpServersentries you already have:
{
"mcpServers": {
"geoserver": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://127.0.0.1:8080/geoserver/mcp",
"--allow-http",
"--header",
"Authorization:Basic YWRtaW46Z2Vvc2VydmVy"
]
}
}
}
YWRtaW46Z2Vvc2VydmVy is admin:geoserver in Base64, so swap it out if your password differs from the default. The --allow-http flag is needed because a local GeoServer is plain HTTP and not HTTPS.
- Quit Claude Desktop completely and reopen it.
- Test it with a prompt like "Which workspaces exist on this GeoServer?" or "Make a workspace called demo_mcp, then show the layers inside topp."
When the tools don't appear, first check that the server is up and that the curl POST from earlier succeeds with -u admin:geoserver.
LangChain
Start with the import:
from langchain_mcp_adapters.client import MultiServerMCPClient
Then create the client:
client = MultiServerMCPClient(
{
"geoserver": {
"transport": "streamable_http",
"url": "http://127.0.0.1:8080/geoserver/mcp",
"headers": {"Authorization": "Basic YWRtaW46Z2Vvc2VydmVy"},
}
}
)
tools = await client.get_tools()
When streamable_http gets rejected, try "transport": "http" instead. The URL and Basic header remain the same.
The project ships a smoke test as extension/examples/langchain_mcp_test.py:
pip install -r extension/examples/requirements-langchain.txt
python extension/examples/langchain_mcp_test.py --url http://127.0.0.1:8080/geoserver/mcp
The script has an optional --agent switch that additionally runs a LangChain agent through OpenRouter, for which OPENROUTER_API_KEY must be set. It needs Python 3.10.11 or later (3.11+ works too). Early 3.10.0 builds frequently fail TLS when they connect to OpenRouter.
Locking out anonymous users
Authentication is on by default. You can tune it with an optional mcp.properties file in the GeoServer data directory:
mcp.enabled=true
mcp.path=/mcp
mcp.requireAuthentication=true
mcp.allowWrites=true
mcp.maxFeatures=100
With mcp.requireAuthentication=true, a request without a login gets HTTP 401, and a request with a GeoServer user runs tools. That user still sees and changes only what GeoServer's data security permits.
Keep it true unless anonymous callers really should reach public catalog objects. Setting mcp.allowWrites=false hides write tools from tools/list and rejects them in tools/call. After any change to mcp.properties, restart GeoServer.
Mistakes that trip people up
- Wrong GeoServer series. This JAR only works on 2.28.x, and 2.20.x won't start the web app.
- Wrong Java. GeoServer 2.28 needs Java 17 or 21, and Java 11 can't load the plugin.
- No restart after copying the JAR.
- Missing Authorization header. The default configuration answers 401.
- Using
localhoston Windows. Python MCP clients may go through IPv6 and hit a 503, so usehttp://127.0.0.1:8080/geoserver/mcp. - A workspace called
mcp. Pick another name, because it may collide with the/mcppath. - Expecting administrative tools. Shapefile uploads, SQL views, reloads and user management are all absent from this plugin.
- TLS errors with
--agent. On Python 3.10.0 the GeoServer part of the smoke test may succeed while the OpenRouter call dies, so move to 3.10.11 or 3.11+.
Where the code lives
Source is hosted at https://github.com/mahdin75/geoserver-mcp (look in the extension folder). The 0.1.0 build has its own release page, https://github.com/mahdin75/geoserver-mcp/releases/tag/extension-v0.1.0, and that repository also takes issues and pull requests.
To sum up the loop: fetch the JAR, put it in the WEB-INF/lib of a 2.28 install, restart, then POST to /geoserver/mcp with valid GeoServer credentials.