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.
Install
Section titled “Install”pip install geolens-mcp # or: uvx geolens-mcpuvx 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.
Configure
Section titled “Configure”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. |
Register with an MCP client
Section titled “Register with an MCP client”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:
claude mcp add geolens \ -e GEOLENS_INSTANCE=https://geolens.example.com \ -e GEOLENS_API_KEY=... \ -- uvx geolens-mcpThat 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.
Merge the mcpServers block into claude_desktop_config.json (macOS:
~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\) and
restart Claude Desktop.
If Desktop reports spawn uvx ENOENT, it launched the server with a minimal
PATH. Replace "uvx" in command with the absolute path from which uvx
(where uvx on Windows).
Save the mcpServers block as .cursor/mcp.json in your project, or
~/.cursor/mcp.json to apply everywhere, and restart Cursor.
Codex reads TOML. Add a [mcp_servers.geolens] table to
~/.codex/config.toml:
[mcp_servers.geolens]command = "uvx"args = ["geolens-mcp"]
[mcp_servers.geolens.env]GEOLENS_INSTANCE = "https://geolens.example.com"GEOLENS_API_KEY = "your-api-key"Or register it from the command line:
codex mcp add geolens \ --env GEOLENS_INSTANCE=https://geolens.example.com \ --env GEOLENS_API_KEY=... \ -- uvx geolens-mcpAny client that speaks stdio MCP accepts the plain {command, args, env}
shape of the mcpServers block above; check its docs for the file it reads.
| 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.
Using query
Section titled “Using query”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.
See also
Section titled “See also”- Client SDKs: the Python SDK that
geolens-mcpbuilds 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_datasetsreturns, including semantic ranking - Examples: MCP prompts: prompts to try against the public demo, each naming the tools it drives