geolens-mcp
OfficialThis is a read-only MCP server for exploring a GeoLens spatial data catalog, datasets, maps, and features, with optional sandboxed SQL querying.
Search the catalog by free text and page through matching datasets with summary metadata.
Inspect a dataset’s schema, columns, geometry, CRS, feature count, extent, source origin, health, freshness, and refresh/check timestamps.
Retrieve bounded GeoJSON features from vector datasets with paging and optional WGS84 bounding-box filtering.
List saved maps and view map summaries, including visibility, view state, basemap, terrain, and layer metadata.
Run one read-only SQL SELECT against accessible
data.*tables, restricted to an allowlisted function set and row/time limits, if credentials have AI-chat permission.
Provides read-only SQL SELECT querying over accessible GeoLens datasets through a hardened SQL sandbox, leveraging PostgreSQL/PostGIS tables and spatial functions such as ST_Area, ST_DWithin, and ST_Intersects.
English · Español · Français · Deutsch · 简体中文
GeoLens is for teams whose spatial data is spread across file shares, PostGIS databases, web services and STAC catalogs. It puts that data in one searchable catalog, records where each dataset came from and checks whether the source is still current. Teams build and share maps in the browser, and QGIS, scripts and AI agents read the same data through OGC API and STAC. It runs on your own servers with Docker Compose, sends no telemetry and is licensed under Apache 2.0.
The demo needs no install or account; sign in with Google, GitHub or Microsoft to use the map builder. Demo data may be wiped at any time.
A closer look
Related MCP server: FastAPI Database MCP Server
How it fits together
flowchart LR
subgraph IN ["Bring data in"]
F["Files<br/>GeoPackage · Shapefile · GeoParquet<br/>GeoTIFF · COPC · 3D Tiles"]
DB["Existing PostGIS tables"]
SVC["Services<br/>ArcGIS · WFS · OGC API Features"]
ST["Remote STAC assets"]
end
subgraph GL ["GeoLens"]
CAT["Catalog<br/>search · metadata · provenance"]
MB["Map builder<br/>styles · 3D · analysis · stories · dashboards · sharing"]
STD["Open APIs<br/>OGC API · STAC · DCAT · tiles"]
end
subgraph OUT ["Use it anywhere"]
WEB["Browsers and embeds"]
GIS["QGIS · ArcGIS · CesiumJS"]
CODE["curl · Python · TypeScript · DuckDB"]
AG["AI agents via MCP"]
end
F & DB & SVC & ST --> CAT
CAT --> MB --> WEB
CAT --> STD --> GIS & CODE & AGOne catalog for scattered data
Upload Shapefile, GeoPackage, GeoJSON, GeoParquet, FlatGeobuf, KML/KMZ, zipped File Geodatabase, CSV, Excel or GeoTIFF (converted to Cloud-Optimized GeoTIFF). 3D Tiles and COPC point clouds are hosted for CesiumJS, QGIS and Potree.
Serve tables already in GeoLens's PostGIS database in place, import WFS, ArcGIS and OGC API Features layers and refresh them on demand, or reference remote STAC assets without copying them.
Draw new datasets in the browser.
Find data with fuzzy search, or by meaning once an embedding provider is configured. Filter by type, place and time, group datasets into collections, edit metadata and restore a dataset's previous version after a replacement.
Know where every dataset came from
Each dataset records where it came from: an uploaded file, a database table, a service, a STAC item or a drawing in the browser. Imported datasets also record when they were last refreshed, and with an update cadence GeoLens marks them fresh, due or overdue. For services and STAC sources, GeoLens also checks that the source still answers, and for services it flags upstream schema changes before they reach your maps. If a service disappears, the imported copy keeps working.
Build and share maps
Point, symbol, heatmap, cluster, line, arrow, fill, 3D extrusion, raster and hillshade layers, with data-driven styles, labels, icons, patterns, filters and popups. Terrain comes from your own elevation models.
Buffer, centroid, clip, dissolve, spatial join, select by location, measure and intersect. Most operations preview on the map, and each result is saved as a new dataset, from the builder or the CLI.
Story maps walk readers through a map scene by scene, with Markdown text, images, buttons and separators. Dashboards put indicators, charts, filters and Markdown notes beside a map. A Map data panel shows the rows behind each layer, as a table or a list.
Public maps and published stories show their title and image when pasted into Slack, Teams or social posts, and maps embed in other sites with private tokens.
The interface is in English, Spanish, French, German and Simplified Chinese.
Use the data from anywhere
Vector datasets are OGC API Features collections, the catalog is OGC API Records and STAC, and
every layer has a tile URL. You can try this against the demo without an account (the second
command needs jq):
# Search the catalog (OGC API Records)
curl "https://demo.getgeolens.com/api/collections/datasets/items?q=volcanic%20eruptions"
# Read the top match with a CQL2 filter (OGC API Features): eruptions of VEI 6 or larger
ID=$(curl -s "https://demo.getgeolens.com/api/collections/datasets/items?q=volcanic%20eruptions&limit=1" | jq -r '.features[0].id')
curl -G "https://demo.getgeolens.com/api/collections/$ID/items" \
--data-urlencode "filter=vei >= 6" -d limit=3QGIS adds the same API as an OGC API Features connection, as the QGIS guide shows. The GeoLens plugin for QGIS adds catalog search, private datasets and edits that sync back to GeoLens.
Standard | Where | Use it with |
OGC API Features, with CQL2 filtering and queryables |
| QGIS, ArcGIS, GDAL/OGR and other OGC API clients |
OGC API Records |
| Catalog search from other portals and tools |
STAC API 1.0 |
| STAC clients such as pystac-client and STAC Browser |
DCAT 3, DCAT-US 3.0 and GeoDCAT-AP as JSON-LD |
| Harvesting into national and EU open-data portals |
Vector tiles and COG raster tiles | a tile URL on every layer | MapLibre, OpenLayers, Leaflet |
3D Tiles and COPC | each 3D dataset's page | CesiumJS, QGIS, Potree |
Data exports as GeoJSON, Shapefile, GeoPackage, CSV, FlatGeobuf, GeoParquet, PMTiles or Cloud-Optimized GeoTIFF.
The geolens CLI publishes files and applies catalog manifests, Python and TypeScript SDKs cover
the API, and a read-only MCP server lets AI agents search the catalog. The
API reference and
SDK guides document them, and the
examples gallery has runnable code for
MapLibre, Leaflet, OpenLayers, the ArcGIS Maps SDK, QGIS and DuckDB.
Optional AI
GeoLens can answer questions about a dataset, edit maps from plain-language requests, draft metadata and search in natural language. It works with any OpenAI-compatible endpoint, including a local server such as Ollama, and with Claude through Anthropic, Microsoft Foundry, Amazon Bedrock or Google Vertex AI. AI stays off until an administrator configures a provider, and every workflow works without it.
Install
You need Git, curl and Docker with the Compose plugin. The Install Guide lists the versions, memory and ports it expects.
curl -fsSL https://getgeolens.com/install.sh | sh # clone, generate secrets, start the stack
cd geolens
grep '^GEOLENS_ADMIN_PASSWORD=' .env # the generated admin passwordOpen http://localhost:8080 and sign in as admin with that password. Each
release includes a SHA256SUMS file for checking
install.sh before you run it. To build from source instead, clone the repository and run
bash scripts/install.sh; the first build takes 5-10 minutes.
For production, read the cloud deployment guide, which also lists what an external database needs. Docker Compose is the supported path, and geolens-deployments has a community-maintained Helm chart and Terraform recipes for AWS ECS Fargate and Azure Container Apps.
The bundled database is backed up daily, and the backup guide covers off-site copies and restores. UPGRADING.md covers upgrades and rollback, RUNBOOK.md covers operations, and the Configuration Reference lists every setting.
Your first dataset
With the CLI installed, publish the sample file from the install directory:
geolens login http://localhost:8080/api # your admin username and password
geolens publish examples/manifests/first-catalog/city-parks.geojson --name "City Parks"geolens publish prints the new dataset's URL. To manage a whole catalog, describe the sources in
a geolens.yaml manifest and run geolens apply; examples/manifests/ has
templates.
To load the demo's maps and datasets, export GEOLENS_ADMIN_PASSWORD from .env and run
python scripts/seed-showcase.py --username admin. The script needs Python 3.10+ and httpx and
downloads public data from about a dozen sources; scripts/README.md has the
sizes and options.
Privacy and access
GeoLens sends no telemetry. Apart from the default basemap tiles and the remote services or STAC sources your users register, it makes outbound calls only for features an administrator turns on. EGRESS.md lists them and explains how to run air-gapped.
Your data stays readable without GeoLens. Vector datasets are ordinary PostGIS tables in a
dataschema, rasters are Cloud-Optimized GeoTIFFs in your own storage (local disk, S3/MinIO or Azure Blob), and the catalog exports through OGC API, STAC and DCAT.Sign-in uses local accounts or OAuth 2.0/OIDC (Google, Microsoft, GitHub or a generic provider), with roles, per-dataset permissions, per-user API keys and an audit log. Self-registration is off by default.
Features released in this repository stay free. EDITIONS.md describes the optional paid support and add-ons.
Known limitations
The supported install, Docker Compose, runs on one host. For high availability, run several replicas of the API, worker, frontend and Titiler against a managed PostgreSQL with automatic failover, shared object storage and one Valkey or Redis cache. With Azure Blob or local storage, API and worker replicas also need a shared staging volume, since only S3 keeps uploads in the bucket. Local storage keeps every file on that volume, so Titiler replicas mount it too. geolens-deployments has a community-maintained Helm chart, Terraform recipes for AWS and Azure, and guides for AWS, Azure, Google Cloud and DigitalOcean. GeoLens itself doesn't cluster the database or read from replicas.
One organization per deployment.
Terrain rendering assumes elevation in meters; other vertical units render exaggerated.
GeoLens's own REST API can change between minor releases (the standards endpoints follow their specifications). The CHANGELOG lists contract changes. When a change breaks callers, the old form keeps working for the later of the next minor release and 90 days, and the CHANGELOG records its removal date. That covers REST routes and fields, the map and dashboard JSON clients write, and CLI commands and flags; the SDKs follow the API, and MCP tool names and arguments aren't covered.
Contributing
Bug reports, fixes, translations and docs are welcome. CONTRIBUTING covers setup and tests, and ARCHITECTURE maps the code. The QGIS plugin, examples and deployments repositories take issues and pull requests too. Ask questions in GitHub Discussions, report bugs in Issues, and report security problems privately as described in SECURITY.md. The roadmap shows what's planned.
Built on
GeoLens is built on these open source projects. Thanks to everyone who maintains them.
PostgreSQL and PostGIS hold the catalog and every vector dataset, and pgvector stores the embeddings behind search by meaning.
GDAL reads the files and services GeoLens imports and writes the formats it exports, and PROJ handles coordinate transformations.
TiTiler serves raster tiles from Cloud Optimized GeoTIFFs.
FastAPI serves the API, and Procrastinate runs background jobs with PostgreSQL as the queue.
MapLibre GL JS draws the maps, deck.gl and loaders.gl render 3D Tiles and point clouds, and Terra Draw handles drawing and editing.
The web app is written in React.
These names belong to their owners, and listing them doesn't mean they endorse GeoLens; see TRADEMARKS.md.
License
GeoLens is licensed under the Apache License 2.0. The GeoLens name, logo and brand
assets are not covered by this license; see TRADEMARKS.md. Sample-data
attribution is in THIRD_PARTY_DATA.md. The web app serves the license notices for the
code it bundles at /third-party-licenses.txt, and the backend image's copyleft notices are in
backend/licenses.
Project policies: editions · support · governance · maintainers · security · release process · egress & air-gap
Available Tools
6 toolsget_dataset_schemaA
Get a dataset's schema and source trust metadata.
Returns columns (name/type/role), geometry type, CRS/SRID, feature count,
spatial extent, and the safe source_origin. source_health is healthy,
missing, inaccessible, or unknown: inaccessible means GeoLens could not
determine whether the source still exists, while unknown means it was never
probed or cannot be probed. source_health_detail is a fixed GeoLens reason
code, not provider text. last_checked_at records the latest probe attempt;
last_refreshed_at records only the latest successful committed refresh.
source_freshness is advisory; overdue means two declared update intervals
elapsed without a successful refresh. Raw provider URLs, origin pointers,
and credentials are excluded. Call this before writing spatial questions so
you know both the available columns and whether the source may be stale.
Args: dataset_id: Dataset id (e.g. from search_datasets).
| Name | Required | Description | Default |
|---|---|---|---|
| dataset_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full disclosure burden and does so richly: it decodes the source_health enum (including the subtle inaccessible vs unknown distinction), clarifies that source_health_detail is a fixed reason code rather than provider text, distinguishes last_checked_at from last_refreshed_at, defines the advisory 'overdue' freshness rule, and confirms raw provider URLs and credentials are excluded.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening sentence front-loads the purpose, and each subsequent sentence carries real semantic content about return fields rather than filler. It is dense and slightly long for a one-parameter read tool, but no sentence is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, no annotations, and a minimal input schema, the description supplies everything an agent needs: what the call returns, how to interpret the trust/freshness fields, and when in the workflow to invoke it. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter with 0% schema description coverage, so the description must compensate. It does, by annotating dataset_id with a concrete source ("e.g. from search_datasets"), which is exactly the guidance the bare string schema lacks.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Get a dataset's schema") and immediately enumerates the returned surface (columns, geometry type, CRS/SRID, feature count, extent, trust metadata), which makes it unmistakable what this tool does versus search_datasets, get_features, or query.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says "Call this before writing spatial questions so you know both the available columns and whether the source may be stale," giving a clear triggering condition. It stops short of naming a specific alternative tool or a when-not-to-use case, so it does not reach the 5 bar.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_featuresA
Get GeoJSON features for a dataset (bounded).
Returns an OGC-API FeatureCollection. Raster datasets have no features and
will error. Results are capped by limit; page with offset. Only the arguments
listed below are supported; anything else is rejected.
Args: dataset_id: Dataset id. limit: Max features (1-200, default 10). offset: Feature offset for paging. bbox: Optional bounding box filter "minx,miny,maxx,maxy" (WGS84).
| Name | Required | Description | Default |
|---|---|---|---|
| bbox | No | ||
| limit | No | ||
| offset | No | ||
| dataset_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses the response shape (OGC-API FeatureCollection), a failure mode (raster datasets will error), pagination behavior (capped by limit, page with offset), and strict argument validation. It omits auth/permission requirements and whether results are ordered, which are the remaining behavioral gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and return type are front-loaded, followed by caveats and then the argument list, which is the right ordering. The "Only the arguments listed below are supported; anything else is rejected" line partially duplicates additionalProperties=false, a minor redundancy in an otherwise tight description.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly explains the return type (OGC-API FeatureCollection) and error conditions, and it documents all four parameters despite zero schema coverage. It is complete enough to call correctly; the main residual gap is that dataset_id's expected form (id vs. slug) is not clarified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does: it gives the units/format for bbox ("minx,miny,maxx,maxy", WGS84), the range and default for limit (1-200, default 10), and the paging role of offset. Only dataset_id ("Dataset id") stays a bare restatement, which is the one weak spot.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource ("Get GeoJSON features for a dataset") with an explicit scope qualifier ("bounded") and a stated return format (OGC-API FeatureCollection). It clearly separates itself from a generic query tool, but it never names or contrasts a sibling (e.g. query) so the differentiation is implicit rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It supplies real usage conditions: raster datasets have no features and will error, results are capped and must be paged with offset, and unsupported arguments are rejected. However, it never names an alternative tool or says when to prefer query/search_datasets over this one, so an agent is left to infer routing on its own.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_mapA
Get a summary of one saved map: name, description, visibility, view state (center, zoom, bearing, pitch), basemap, terrain configuration and layer list.
Each layer has id, dataset_id, dataset_name, dataset_table_name,
dataset_geometry_type, display_name, visible, layer_type and
filter. Styling, popups, labels, column info and sample values are not
included. dashboard_widget_count is the number of dashboard widgets
(0 for none).
Args: map_id: Map id (e.g. from list_maps).
| Name | Required | Description | Default |
|---|---|---|---|
| map_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden, and it does well by disclosing what is deliberately excluded (styling, popups, labels, column info, sample values) so the agent won't expect those fields. It also defines the semantics of dashboard_widget_count ('0 for none'). Missing only auth/permission and pagination context, which is minor for a single-record read.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, followed by a compact field inventory and an explicit exclusion list. The layer-field catalog is a bit list-heavy but every item earns its place as return-shape documentation; no filler sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so describing return values is the description's job, and it does so thoroughly at both the top level and per-layer, plus calls out absent data. An agent can decide to call this and interpret the result without further sources.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter has 0% schema description coverage, so the description must compensate: it documents map_id as a 'Map id' with provenance ('from list_maps'), which is meaningfully more than the bare type in the schema. It doesn't specify the ID format or null/failure behavior, keeping it from a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get a summary of one saved map') and enumerates exactly what the summary contains (name, description, visibility, view state, basemap, terrain, layers). This clearly distinguishes it from list_maps, which is named as the source of map_id, and from dataset-oriented siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear workflow context by telling the agent where map_id comes from ('e.g. from list_maps'), which implicitly scopes this tool to retrieving a single already-known map. It does not explicitly state when not to use it or contrast with get_dataset_schema, so it stops short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_mapsA
List saved maps (read-only metadata: id, name, visibility, layer count).
Args: search: Optional text filter on map name/description. limit: Max results (1-200, default 50). offset: Result offset for paging.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| offset | No | ||
| search | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose the key trait: this is a read-only metadata listing and it enumerates exactly what is returned (id, name, visibility, layer count). It omits auth/permission requirements and whether search is case-insensitive or substring-based, which keeps it out of the top band.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded summary sentence plus a compact, clearly labelled arg list. Every line carries information and nothing is padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple, zero-required-param read tool with no output schema and no annotations, the description covers purpose, all three params, and the returned fields, so an agent can call it correctly. The only real gap is the absence of routing guidance relative to get_map and search_datasets.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate and largely does: it explains that search filters on name/description (the schema only says string), states limit is 1-200 with default 50, and identifies offset as paging. Limit/offset are conventional enough that no further explanation is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List saved maps') and scopes the return to metadata (id, name, visibility, layer count), which clearly separates it from the single-map sibling get_map. It does not name any sibling explicitly, so it stops just short of full differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: listing 'saved maps' suggests browsing rather than fetching a specific map, but there is no explicit when-to-use, when-not-to-use, or pointer to get_map/search_datasets. An agent must infer the routing from the resource name alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
queryA
Run one read-only SQL SELECT against accessible datasets.
Executes through the server's hardened SQL sandbox: a single SELECT over
data.* tables, an allowlisted function set (aggregates, math, string,
date, JSON), and a strict server-side budget (a 5 s statement timeout, a
repetition cap on self-joins, and row_limit rows, at most 1000).
Returns {columns, rows, row_count, truncated} with rows as lists in
column order. Geometry columns come back as hex EWKB; select
ST_AsText(geom) or ST_AsGeoJSON(geom) for readable geometry.
ST_AsGeoJSON(geom, 6) rounds coordinates to six decimals, which suits
display but can make a small polygon invalid.
PostGIS functions allowed: ST_Area, ST_AsGeoJSON, ST_AsText, ST_Buffer,
ST_Centroid, ST_Collect, ST_Contains, ST_Distance, ST_DWithin,
ST_GeometryType, ST_GeomFromGeoJSON, ST_GeomFromText, ST_Intersects,
ST_IsValid, ST_Length, ST_MakeEnvelope, ST_MakePoint, ST_NPoints, ST_Point,
ST_SetSRID, ST_Transform, ST_Union, ST_Within, ST_X, ST_Y. ST_Collect and
ST_Union take two geometries (no aggregate form). The && bounding-box
operator works, as do ::geography / ::geometry and geography(geom).
Requires credentials with AI-chat permission — anonymous configurations
cannot use this tool. Workflow: 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 the same table_name in
restrict_tables. Every table the query touches must be listed there;
the scope can only narrow what your credentials already see. Writes,
other schemas, and unlisted functions are rejected with a short reason
that names the refused function.
Args:
sql: A single SELECT statement over data.* tables.
restrict_tables: Table names (no data. prefix) the query may touch.
Required and non-empty.
row_limit: Max rows to return (1-1000, default 100).
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| row_limit | No | ||
| restrict_tables | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so thoroughly: read-only enforcement, sandbox restrictions, 5-second timeout, self-join repetition cap, row limit, allowed functions, credential requirements, and rejection behavior are all disclosed. It also explains the return shape and geometry encoding.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose and sandbox behavior, and most sentences add operational value. It is longer than typical because of the exhaustive PostGIS function allowlist and detailed edge cases, but that detail is relevant for complex SQL generation rather than pure padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, yet the description specifies the return object's fields, truncation behavior, and geometry encoding. It also covers credentials, table-scoping rules, query restrictions, and the prerequisite workflow, leaving little needed before an agent can call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does: sql is constrained to a single SELECT over data.* tables, restrict_tables requires non-empty table names without the data. prefix and must list every touched table, and row_limit is explained as max rows with a 1–1000 range and default 100.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb and resource: 'Run one read-only SQL SELECT against accessible datasets.' It clearly distinguishes this tool as the SQL execution path, and the workflow references search_datasets and get_dataset_schema as prerequisite siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides a clear end-to-end workflow: use search_datasets, then get_dataset_schema, then reference the table as data.<table_name> and list it in restrict_tables. However, it does not explicitly say when to use this instead of sibling tools like get_features or get_map, so it lacks full when-not/alternative guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_datasetsA
Search the GeoLens catalog for datasets by free text.
Matches title, description, and keywords (semantic ranking is used
automatically when the instance has it enabled). Returns a compact
FeatureCollection (numberMatched, numberReturned, features) where each
feature is a trimmed dataset record: id, bbox, and properties title,
description (cut at 300 characters), record_type, geometry_type,
feature_count, crs, keywords and updated. Use the feature id as the
dataset_id for the other tools; get_dataset_schema has the full detail.
Each feature's properties also include source_origin (upload, postgis,
service, stac, created, or null) and source_freshness (fresh, due,
overdue, or unknown). Freshness is advisory:
due means one declared update interval has elapsed, while overdue means
two have elapsed; neither proves that the content is wrong.
Search does not make a detail request per result. When the catalog summary
has no health/check/refresh value, source_health, source_health_detail,
last_checked_at, and last_refreshed_at are null. Call
get_dataset_schema for populated trust metadata. Raw provider URLs and
credentials are never included in these source-state fields.
Args: query: Search text. limit: Max results (1-200, default 10). offset: Result offset for paging.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| offset | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses semantic ranking, that no per-result detail request is made, that descriptions are truncated at 300 characters, the exact meaning of `due` vs `overdue` freshness (explicitly advisory, not proof of wrongness), null-field conditions for health metadata, and that raw provider URLs and credentials are never returned.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and return shape are front-loaded, and most sentences carry real information. The source-health paragraph is slightly bloated and discusses `source_health`, `last_checked_at`, and `last_refreshed_at` fields that are not even in the enumerated property list, which adds length without a clear payoff for a search call.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must define the return shape, and it does: a compact FeatureCollection with `numberMatched`, `numberReturned`, and a full enumeration of each feature's properties. An agent has everything needed to call this and interpret the response without a follow-up tool call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and its Args block covers all three parameters: query as search text, limit as max results with the 1-200 range and default, and offset as the paging cursor. The coverage is adequate but terse; it does not clarify tokenization, empty-query behavior, or how offset interacts with ranked results.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Search the GeoLens catalog for datasets by free text") and immediately scopes what fields are matched. It also routes the agent onward ("Use the feature `id` as the dataset_id for the other tools; `get_dataset_schema` has the full detail"), which distinguishes it from the sibling that returns full detail.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clear context for when to use it (free-text discovery over the catalog) plus explicit hand-off guidance to `get_dataset_schema` for detail and trust metadata. It stops short of naming when *not* to use it versus siblings like `query`, `list_maps`, or `get_features`, so it is strong but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
v1.25.1- Changed
get_dataset_schema1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
get_features4 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / limit / maximumAdded value: +200 - added
Input schema / properties / limit / minimumAdded value: +1 - added
Input schema / properties / offset / minimumAdded value: +0
- Changed
get_map1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
list_maps4 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / limit / maximumAdded value: +200 - added
Input schema / properties / limit / minimumAdded value: +1 - added
Input schema / properties / offset / minimumAdded value: +0
- Changed
query3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / row_limit / maximumAdded value: +1000 - added
Input schema / properties / row_limit / minimumAdded value: +1
- Changed
search_datasets4 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / limit / maximumAdded value: +200 - added
Input schema / properties / limit / minimumAdded value: +1 - added
Input schema / properties / offset / minimumAdded value: +0
6 tool updates
v0.1.0- First observed
get_dataset_schema - First observed
get_features - First observed
get_map - First observed
list_maps - First observed
query - First observed
search_datasets
TDQS
Scored across 6 tools
Datasets, maps, and SQL each occupy distinct tool territory, and get_map vs list_maps is clearly separated. The only mild overlap is get_features versus query, both of which retrieve row-level data, but the GeoJSON-paging vs analytical-SQL split is well explained.
Five tools follow a predictable verb_noun pattern (search_datasets, get_dataset_schema, get_features, get_map, list_maps), but the bare verb `query` breaks the pattern and is less self-describing.
Six tools is well-scoped for a read-only geospatial catalog/query server; each tool serves a distinct step in the discover-schema-inspect-analyze workflow with no filler.
The read-only surface covers search, schema/trust metadata, feature retrieval, SQL analysis, and map metadata, forming a coherent lifecycle. The notable gap is raster datasets, which have no retrieval path since get_features errors on them, and there is no way to create or modify maps (likely intentional for a read-only server).
Maintenance
Related MCP Connectors
Generate and run high performance queries on open and private spatial data at-scale in the cloud
Read-only optical catalog search plus DiffBeam server, schema, and catalog revision metadata.
ArcGIS Hub — open government geospatial data (search + Feature Service query).
Read your Iceberg tables hosted in Europe: find tables, run read-only SQL, view photos.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides read-only access to PostgreSQL databases with schema inspection, query execution in multiple formats (JSON, CSV, Markdown), and query history tracking with built-in security features.-
- FlicenseNot gradedqualityFmaintenanceProvides read-only SQL query access to Postgres and DuckDB databases via MCP tools, with extensive security hardening for public endpoints.1-
- FlicenseBqualityDmaintenanceProvides read-only query tools over OpenStreetMap data in PostGIS, enabling natural language queries for features, categories, and spatial analysis.7-
- AlicenseNot gradedqualityBmaintenanceEnables browsing Global Forest Watch's catalogue and running read-only SQL queries against dataset versions, covering tree cover loss, deforestation alerts, fire alerts, carbon flux, and more.425 npmMIT