Skip to content
getgeolens.com

MCP Server

The GeoLens MCP server (geolens-mcp) is a read-only Model Context Protocol server. Point a coding agent (Claude Code, Cursor, Codex, and any other MCP client) at a GeoLens instance and it can discover datasets, inspect schemas, and read features and maps from inside a dev session. It is Apache-2.0 licensed and built on the Python SDK, so every tool maps to a real endpoint in the API reference.

Terminal window
pip install geolens-mcp # or: uvx geolens-mcp

uvx runs the server without a persistent install, which is what the client-registration examples below use.

geolens-mcp is released alongside GeoLens itself, so run the version that matches your instance: GET /api/health reports it. The examples repo publishes the pinned command and explains the trade-off of pinning.

The server reads its target instance and credentials from the environment — the same variable names the CLI uses:

| Variable | Required | Meaning | |---|---|---| | GEOLENS_INSTANCE | Yes | Instance URL, e.g. https://geolens.example.com. The /api suffix is appended automatically if you omit it, and left alone if you include it. The SDKs do not append it, so if one exported value feeds the SDK too, include /api. | | GEOLENS_API_KEY | Recommended | API key, sent as X-Api-Key. Omit for public-only access. See Authentication → API keys for how to obtain one. | | GEOLENS_TOKEN | — | JWT bearer token, used only if GEOLENS_API_KEY is unset. |

Every client needs the same inputs: the command uvx geolens-mcp and the GEOLENS_* variables above in the server’s environment. Most clients read them from an mcpServers block:

{
"mcpServers": {
"geolens": {
"command": "uvx",
"args": ["geolens-mcp"],
"env": {
"GEOLENS_INSTANCE": "https://geolens.example.com",
"GEOLENS_API_KEY": "your-api-key"
}
}
}
}

Where that block goes differs per client, and Codex reads TOML instead. Ready-to-paste files for each client, pointed at the public demo, live in the examples repo under mcp/clients/.

One command registers the server:

Terminal window
claude mcp add geolens \
-e GEOLENS_INSTANCE=https://geolens.example.com \
-e GEOLENS_API_KEY=... \
-- uvx geolens-mcp

That writes to the local scope (this project, this machine). Add -s user to make the server available in every project. For a config that travels with the repository, put the mcpServers block above in a .mcp.json at the project root and commit it. Keep the real key out of that file: reference a variable your shell already exports instead ("GEOLENS_API_KEY": "${GEOLENS_API_KEY}"), or register locally with claude mcp add.

| Tool | What it does | |---|---| | search_datasets | Catalog search by free text (semantic ranking where the instance enables it). Returns dataset records as GeoJSON features. | | get_dataset_schema | A dataset’s columns, geometry type, CRS/SRID, feature count, and extent, plus the source-trust fields origin, source_health, and source_freshness. | | get_features | Bounded GeoJSON features for a dataset (OGC API — Features), with optional bbox. | | list_maps | Saved maps (id, name, visibility, layer count). | | get_map | One saved map’s full metadata, including layers and view state. | | query | One read-only SQL SELECT over data.* tables, through the server’s hardened sandbox. Returns {columns, rows, row_count, truncated}. |

get_features caps results with limit (default 10) and pages with offset, and its bbox is minx,miny,maxx,maxy in WGS84 regardless of the dataset’s own SRID. Raster datasets have no features, so get_features against one errors rather than returning an empty collection; check record_type in get_dataset_schema first. A dataset or map id that is not a UUID is rejected by geolens-mcp itself (Invalid id (expected a UUID)) before any request reaches the instance, which is a different error from a 404.

query is the one tool that is not a GET; it POSTs to the sandbox endpoint and is still strictly read-only. A single SELECT is allowed, over an allowlisted function set (aggregates, math, string, date, JSON, and common PostGIS such as ST_Area, ST_DWithin, ST_Intersects), under a server-side budget: a few seconds of runtime, a repetition cap on self-joins, and a row_limit between 1 and 1000 (default 100). The sandbox rejects writes, other schemas, and unlisted functions with a short reason.

It takes restrict_tables as a required, non-empty list. Every table the query touches must be listed there, and the scope can only narrow what the credential already sees. The usual workflow is search_datasets to find a dataset, then get_dataset_schema for its table_name and columns, then reference it as data.<table_name> in the SQL and list that same table_name in restrict_tables.

query requires credentials with AI-chat permission, so anonymous configurations cannot use it: without one it returns 401 Could not validate credentials. The other five tools work without a credential against public/published data.

  • Client SDKs: the Python SDK that geolens-mcp builds on, and the CLI-vs-SDK-vs-MCP-vs-API decision table
  • CLI & Manifests: the same credential/instance environment variables, for terminal and CI ingestion
  • API Authentication: JWT and API-key details for the credentials above
  • Search & Discovery: what search_datasets returns, including semantic ranking
  • Examples: MCP prompts: prompts to try against the public demo, each naming the tools it drives