Home / Articles / Connecting AI Agents to GeoServer 2.28 Through the MCP Extension

This article is published in English.

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.

1377 words

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

  1. Open GeoServer and check About & Status, then About GeoServer. The version has to start with 2.28.
  2. Stop GeoServer.
  3. Copy gs-mcp-0.1.0.jar into the WEB-INF/lib folder 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

  1. Open http://127.0.0.1:8080/geoserver/web/ and log in.
  2. Go to About & Status, then Modules.
  3. 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:geoserver returns a JSON result.
  • A POST with no user returns HTTP 401.
  • A GET on /geoserver/mcp returns 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.

  1. 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.
  2. Add the server below, keeping any other mcpServers entries 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.

  1. Quit Claude Desktop completely and reopen it.
  2. 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 localhost on Windows. Python MCP clients may go through IPv6 and hit a 503, so use http://127.0.0.1:8080/geoserver/mcp.
  • A workspace called mcp. Pick another name, because it may collide with the /mcp path.
  • 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.