3DCityDB MCP Server
OfficialThe 3DCityDB MCP Server gives AI assistants direct, natural-language access to semantic 3D city models (CityGML) stored in a 3DCityDB v5 PostgreSQL/PostGIS geodatabase.
Understand the database: retrieve table structures, column details, foreign-key relationships, and SQL best practices/optimization tips.
Discover data model: scan existing CityGML object classes with their full hierarchy, and resolve each class's properties — filtered to what actually exists in the data — including country-aware codelist resolution.
Inspect attributes and context: fetch generic attributes with categorical detection and min/max ranges, available Levels of Detail, CRS/EPSG, bounding box, per-class feature counts, and null-value statistics.
Learn by example: get SQL examples restricted to object classes present in the database.
Query safely: run read-only SQL (SELECT/WITH only, auto-limited to 500 rows, enforced at both application and database layers).
Manage sessions: create/retrieve session context, narrow scope to specific modules or object classes, read conversation history, and log query feedback.
Bootstrap the AI: assemble a complete system prompt in one call, with compact mode and optional SQL examples/guidelines.
Optionally (Docker GUI): 3D viewer with answer highlighting and object selection, a per-user spatial scratchpad, a bathtub flood scene, and one-click CityGML/CityJSON/IFC import.
Provides an optional LangChain agent CLI that uses MCP tools to interact directly with the 3DCityDB database.
Provides integration with Ollama as a local LLM backend for the Gradio chat UI, allowing natural-language querying of the 3DCityDB.
Provides integration with OpenAI's API as one of the supported LLM backends for the Gradio chat UI, allowing natural-language querying of the 3DCityDB.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@3DCityDB MCP Serverfind all buildings taller than 50 meters"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
A Model Context Protocol (MCP) server giving AI assistants direct, natural language access to semantic 3D city models in CityGML managed within a 3DCityDB v5 geodatabase.
It dynamically resolves CityGML object classes, properties, codelists, and generic attributes from the database so the AI can answer both spatial and semantic queries stated in natural language, write and execute SQL queries, and reason about CityGML data — without any manual prompt engineering. By including the MCP server in agentic coding environments, it becomes easy to create software that can read and write complex structured 3D city models compliant to the OGC CityGML standard (and using 3DCityDB V5 as the data repository).
Furthermore, a Chat Assistant is included offering a simple GUI for interactive query asking, reasoning, and answering. It is an agentic AI tool based on LangChain utilising the ReAct pattern for carrying out multi-step reasoning and automated error corrections. The Chat Assistant currently can be configured to work with OpenAI and Anthropic commercial LLMs, any OpenAI-compatible endpoint, as well as with locally running Ollama LLMs. For example, when using the qwen3.8:27b LLM running in Ollama, the Chat Assistant is capable of performing very complex analyses on any kind of stored 3D city model, including multi-step SQL workflows with live reasoning traces, rendered diagrams, and PDF export.
The evaluation of the MCP Server for the accompanying paper was done using 100 queries of 4 different complexity levels. The complete list of the queries can be found here.
Features
The project has two layers with their own feature sets: the MCP server (the model-facing tool provider, usable from any MCP client) and the Chatbot (the browser GUI that wraps the MCP server with a multi-LLM agentic loop, an optional 3D viewer and per-user state).
MCP Server Features
Dynamic schema resolution — walks the CityGML class hierarchy to discover available object classes and their properties
Property filtering — only includes properties that actually exist in the database
Country-aware codelist resolution — qualified
<namespace>:<Class>.<attribute>keys, country selected via the database EPSG code; only codes actually present in the data are exposedGeneric attribute enrichment — automatic categorical detection for generic attributes
Read-only query execution —
run_queryenforces SELECT-only; writes are blocked at the application layer and the database layer, where every pooled connection runs in a read-only transaction (default_transaction_read_only = on) so even a crafted CTE hiding a write is rejected by PostgreSQLPrompt assembly —
assemble_promptorchestrates all tools into a complete system prompt in one callPer-user context into tool calls — every tool call can carry a server-side
_ctx(user / session / turn) that is stripped before dispatch, so per-user tools such as the scratchpad know which user is calling without ever trusting the model
Chatbot Features
Gradio chat UI — browser-based interface with multi-LLM support (Anthropic, OpenAI, Ollama), thinking-level control, live reasoning trace, mermaid/LaTeX rendering, and PDF export
Multi-user, per-tab sessions — each browser tab is an independent session with its own Stop button and its own user identity (a uuid in the browser's
localStorage, no login), so several users — and several tabs of the same user — can chat in parallel without interfering (session layer)Integrated 3D viewer (optional) — embeds the 3DCityDB Web Map Client into the chat UI (fullstack Docker mode, see Option 3b); the model is streamed as 3D Tiles generated on demand by a separate
citydb-3dtilercontainer. Features from an answer are highlighted in 3D and the camera flies to them, and selected viewer objects are passed to the chatbot so questions can refer to them ("these buildings", "the selected ones")Spatial scratchpad (optional) — a per-user "staging area" the chatbot fills with saved, reusable results: featuresets (named sets of buildings, e.g. "the buildings built between 1945 and 1980") and geometries (pins, lines, draped 2D areas, extruded 3D solids, convex hulls) with per-item name, color and opacity. Items appear as a labelled list in the 3D viewer, can be shown, hidden, re-styled, re-flown-to and deleted — and re-queried later with ordinary SQL against a per-user
my_scratchpadview. Enabled byCITYDB_SCRATCHPAD=true; see Spatial scratchpad andscratchpad.mdFlood scene (optional) — a quick "bathtub" flood visualization: a query result with a
flood_level_mcolumn draws a water surface at that height and colours every building red (flooded), green (held back by aprotection_mbarrier) or grey (dry), with an on-screen water-level slider and gauge. Enabled byFLOOD_SCENE=true; seeflood-scene.mdCityGML 1.0-3.0/CityJSON/IFC import — one-click import via the Gradio UI (fullstack Docker mode only);
.ifcfiles are converted to CityGML 3.0 first
Related MCP server: GraphJin
Deployment Options
There are four ways to run the 3DCityDB MCP Server (Option 3b is a 3D-viewer variant of Option 3):
Best for | Claude Code / Claude Desktop power users | Existing 3DCityDB instances | Starting from a | 3D exploration & highlighting of query results |
Requires | Python 3.10+, running 3DCityDB | Docker, running 3DCityDB | Docker only | Docker only (same as Option 3) |
Gradio UI | No (uses your AI client directly) | Yes ( | Yes ( | Yes ( |
CityGML/CityJSON/IFC import | Manual | Manual | Via Gradio UI | Via Gradio UI |
Database | Your own | Your own | Bundled (PostgreSQL + PostGIS + SFCGAL) | Bundled (same as Option 3) |
Chat CLI
The WebGUI-equivalent 3dcitydb-chat CLI is included in the chatbot image used
by Docker Options 2, 3, and 3b. Start one of those stacks first, then run the
CLI in its chatbot container. For example, with the fullstack stack:
docker exec -it production-citydb-agent-1 3dcitydb-chat chatThe same CLI can run without Docker from a source checkout, but it is not part
of the standard PyPI package. Install the project and WebGUI dependencies,
configure the database/provider environment as described under Option 1, then
run these commands from the production directory:
python -m pip install -e ..
python -m pip install -r webui/requirements.txt
python -m webui.cli chatThe local MCP server executable (3dcitydb-mcp) must be on PATH, and the
configured database must be reachable from the machine running the CLI. Unlike
the Docker CLI, a local CLI process uses that machine's environment and
filesystem.
Choose a provider and model explicitly when desired. For example:
docker exec -it production-citydb-agent-1 3dcitydb-chat chat \
--provider ollama --model qwen3.8:27b \
--temperature 0.1 --thinking high --prompt-mode auto --num-ctx 131072Available options also include --base-url, --keep-story /
--no-keep-story, --full-lists / --no-full-lists (also for benchmark; see
Show every row in result tables below; with --no-full-lists the full result is
printed as CSV after the answer), --include-reasoning, and --show-reasoning. By default,
provider reasoning is not displayed; --show-reasoning adds a clearly labeled
reasoning/activity section on stderr. Use /new to clear conversation history
and /bye or /exit to leave the session. Prompt assembly reports each
database-context step and its duration on stdout. Status and context-size
estimates also go to stdout. INFO logs and generation/tool diagnostics between
submitting a question and receiving its answer go to stderr. Pass
--quiet-stderr to suppress stderr output, including INFO logs.
Benchmarking and Validation
Work on support for systematic result quality validation and benchmarking is work in progress. Documentation and usage of the already existing tools are documented
in docs/benchmarking.md.
Option 1: PyPI Package
Install the MCP server as a Python package and connect it to Claude Code, Claude Desktop, or any MCP-compatible client.
Prerequisites
Python 3.10 or later
A running 3DCityDB v5 PostgreSQL instance with PostGIS
Installation
pip install 3dcitydb-mcp-serverOr install from source for development:
git clone https://github.com/tum-gis/3dcitydb-mcp-server.git
cd 3dcitydb-mcp-server
pip install -e .Configuration
Copy the example environment file and edit it:
# Linux / macOS
cp .env.example .env
# Windows (PowerShell)
Copy-Item .env.example .envThen fill in your connection details:
# 3DCityDB PostgreSQL connection
CITYDB_HOST=localhost
CITYDB_PORT=5432
CITYDB_NAME=citydb
CITYDB_USER=postgres
CITYDB_PASSWORD=your_password_here
CITYDB_SCHEMA=citydb
# Query behaviour (optional)
CATEGORICAL_THRESHOLD=20
SAMPLE_VALUES_COUNT=5
# LLM API keys (only needed for the LangChain agent CLI, not for Claude Code/Desktop)
ANTHROPIC_API_KEY=sk-ant-...
# OPENAI_API_KEY=sk-...
# OLLAMA_BASE_URL=http://localhost:11434The server loads .env automatically by searching upward from the working directory.
Verify your installation
3dcitydb-doctorChecks Python version, required packages, database connectivity, PostGIS/SFCGAL extensions, and the 3DCityDB v5 schema. Exits 0 if all critical checks pass.
Connect to Claude Code (recommended)
From the directory containing your .env:
claude mcp add 3dcitydb -- 3dcitydb-mcp
claudeThe MCP server starts automatically when you open a Claude session. Use /mcp inside the session to confirm it is connected.
Connect to Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"3dcitydb": {
"command": "3dcitydb-mcp",
"cwd": "/path/to/your/project"
}
}
}Restart Claude Desktop. The MCP server will be listed in Settings → Developer → MCP Servers.
SSE transport (remote / production)
Run the server over HTTP for remote clients:
3dcitydb-mcp-sse --host 0.0.0.0 --port 8080Clients connect via:
http://your-server:8080/sseModern clients (e.g. VS Code) prefer the Streamable HTTP transport:
http://your-server:8080/mcpHealth check:
http://your-server:8080/health
The repository ships a ready-made .mcp.json that points an
MCP client (e.g. VS Code) at http://localhost:8080/mcp/. With the
fullstack stack running locally, it enables the 3dcitydb-* tools in your
editor without any manual configuration. Adjust the URL if you run the
SSE server on a different host or port.
LangChain agent CLI (optional)
A standalone CLI agent that uses the MCP tools directly:
3dcitydb-agentRequires ANTHROPIC_API_KEY, OPENAI_API_KEY, or OLLAMA_BASE_URL in your .env.
Option 2: Docker — BYOD (Bring Your Own Database)
Run the Gradio chat UI as a Docker container, connected to your existing 3DCityDB instance.
Prerequisites
Docker with Compose (V2)
A running 3DCityDB v5 PostgreSQL instance accessible from the Docker host
⚠️ Spatial function support: The AI agent uses SFCGAL functions (
CG_Volume,CG_3DArea,CG_MakeSolid) for geometry calculations. These require PostGIS to be compiled with SFCGAL support.If your database lacks SFCGAL, volume and 3D area queries will fail silently or return errors. To get full spatial support, use Option 3 (Fullstack) instead — it ships a
3dcitydb-pgimage with PostGIS + pre-patched SFCGAL already enabled. The SFCGAL patch circumvents the much too strict geometry planarity checks normally compiled into SFCGAL (checking for nano meter planarity), so working with 3D geometry works e.g. with volume calculation, 3D surface area calculation as well as 3D boolean operations.You can verify SFCGAL availability on your instance with:
SELECT postgis_sfcgal_version();If this returns an error, many spatial queries will not work.
Quick Start
# 1. Clone the repository (or just download docker-compose.byod.yml + .env.example)
git clone https://github.com/tum-gis/3dcitydb-mcp-server.git
cd 3dcitydb-mcp-server/production
# 2. Copy and edit the environment file
cp .env.example .env # Linux / macOS
# Copy-Item .env.example .env # Windows PowerShellEdit .env with your database connection and at least one LLM API key:
# Your existing 3DCityDB instance
CITYDB_HOST=your-db-host
CITYDB_PORT=5432
CITYDB_NAME=citydb
CITYDB_USER=citydb
CITYDB_PASSWORD=your_password
CITYDB_SCHEMA=citydb
# At least one LLM provider (the UI auto-selects based on what is available)
ANTHROPIC_API_KEY=sk-ant-...
# OPENAI_API_KEY=sk-...
# OLLAMA_BASE_URL=http://host.docker.internal:11434# 3. Pull the pre-built image and start (works on all platforms, no build needed)
docker compose -f docker-compose.byod.yml up -d
# 4. Open the UI
# http://localhost:7860The pre-built image (ghcr.io/tum-gis/3dcitydb-mcp-agent:latest) is pulled automatically from the GitHub Container Registry on first run.
What it includes
Gradio chat UI — natural-language interface to your 3DCityDB
MCP server — spawned automatically as a subprocess inside the container
Auto provider detection — the UI selects Anthropic, OpenAI, or Ollama based on which keys are present in
.env
Gradio UI overview
Tab | What it does |
Chat | Send natural-language questions; the agent writes and executes SQL automatically |
MCP Inspector | Shows the MCP server's self-description and lists all active MCP tools |
System Prompt | Displays the full assembled system prompt sent to the LLM and offers Re-assemble system prompt to rebuild it from the current database contents — useful for debugging |
Note: the Import CityGML / CityJSON / IFC tab is only shown in the fullstack variant (Option 3); BYOD connects to an existing database and has no import tab (see Import CityGML/CityJSON/IFC under Option 3).
While the agent is working, the chat bubble shows live status: Thinking… → Running query… → Interpreting results…. Right next to the chat log, the Agent activity panel streams the full ReAct trace — each thought, tool call, and observation — with per-step timing.
Chat settings (above the input field):
Setting | Options | Description |
Provider / API |
| Auto-selected from |
Model | (populated per provider) | Dropdown with free-text entry possibility; Refresh models re-discovers models from the Ollama endpoint |
Set temperature | checkbox + value (0.0–1.0, default 0.1) | Unchecked = provider default; enable to pin a fixed temperature |
Thinking |
| Reasoning level for thinking-capable models. Ollama uses native |
Prompt mode |
|
|
Keep a distilled summary of how the answer was found | on / off (default on; Ollama + OpenAI) | After each DB turn, distills the successful path (purpose + working SQL + short result) into a compact story carried into later turns. Adds one extra blocking generation per tool-using turn |
Show every row in result tables | on / off (default on; all providers) | On: the answer's table lists every row the query returned (e.g. all building IDs). Off: results with more than 10 rows show 5 example rows and the sentence "5 of N", which answers faster for long lists. Above 10 rows the complete result is attached below the answer as collapsible CSV and JSON in both modes (not sent back to the model). Prompt rules: |
Include all reasoning steps in context | on / off (default off; Ollama + OpenAI) | Feeds each turn's full reasoning trace back into context on later turns. Off by default: the full trace consumes a large share of the context window, and the distilled summary (above) already carries the essential path |
Context window (Ollama) | 8K / 32K / 64K / 128K / 256K (default 128K) | Tokens available to the model; a smaller window uses less memory but is too small for complex queries |
Rendering and export:
Mermaid diagrams are rendered inline in the chat, with a copy toolbar (SVG / PNG / source code) and a visible fallback box if a diagram fails to parse
Inline LaTeX is rendered in chat messages; the agent activity panel shows the unrendered source
PDF export (🖨 button next to the send button) prints the current conversation to a multi-page PDF via the browser's print dialog
Local (Ollama) model support
The Chat Assistant is deliberately built to work with small local models, not just commercial APIs:
Robust tool-call parser — local models frequently emit ReAct actions in non-standard formats (e.g. a full sentence as the action name, extra whitespace, missing arguments). The parser normalises these automatically and repairs common malformations instead of aborting the run.
Model profiling — a built-in registry (
webui/model_profiles.py) classifies known models by empirically observed behaviour (works,sentence-as-tool,wrong-sql,thinking-then-empty,unknown). The class drives a warning line under the model dropdown (e.g. a model known to emit broken SQL is forced into full prompt mode with an explanatory note), so you get an honest assessment of what a model can do before the first query.Endpoint & model discovery — the Refresh models button queries the Ollama endpoint and repopulates the model dropdown, including custom or fine-tuned models.
Native thinking — for Ollama models with a thinking capability (e.g.
qwen3.8:27b,gpt-oss:20b), the Thinking dropdown controls the nativethinkparameter; no prompt engineering needed. However, it seems that many Ollama models do not consider this parameter properly.
See production/docs/local-model-probing.md for the full probing methodology, the per-model results, and how to add a new model profile.
Building locally (optional)
If you want to build the image from source instead of pulling it:
# Linux / macOS
docker compose -f docker-compose.byod.yml up -d --build
# Windows — Docker BuildKit has a known ordering bug on Windows/NTFS.
# Disable it for local builds:
$env:DOCKER_BUILDKIT=0; docker compose -f docker-compose.byod.yml up -d --buildWindows note: The
DOCKER_BUILDKIT=0flag is only needed when building locally. Pulling the pre-built image (docker compose up -dwithout--build) works on Windows without any workaround.
Useful commands
# View logs
docker compose -f docker-compose.byod.yml logs -f
# Stop
docker compose -f docker-compose.byod.yml downOption 3: Docker — Fullstack (Bundled PostgreSQL)
Run everything — PostgreSQL (with PostGIS and SFCGAL), the 3DCityDB schema, the MCP server, and the Gradio UI — in a single Docker Compose stack. No pre-existing database needed. If you also want to see the model in 3D, continue with Option 3b — the 3D viewer after the quick start below.
Prerequisites
Docker with Compose (V2)
A CityGML, CityJSON, or IFC file to import (optional — the database starts empty)
Quick Start
# 1. Clone the repository (or just download docker-compose.fullstack.yml + .env.example)
git clone https://github.com/tum-gis/3dcitydb-mcp-server.git
cd 3dcitydb-mcp-server/production
# 2. Copy and edit the environment file
cp .env.example .env # Linux / macOS
# Copy-Item .env.example .env # Windows PowerShellEdit .env:
# PostgreSQL settings for the bundled database
POSTGRES_DB=citydb
POSTGRES_USER=citydb
POSTGRES_PASSWORD=citydb
SRID=25832 # choose the right EPSG code of the coordinate reference system for the dataset you want to import
# At least one LLM provider
ANTHROPIC_API_KEY=sk-ant-...
# OPENAI_API_KEY=sk-...
# OLLAMA_BASE_URL=http://host.docker.internal:11434# 3. (Optional) Place your CityGML file in the data directory
mkdir -p data
cp /path/to/your/city.gml data/
# 4. Pull the pre-built image and start (works on all platforms, no build needed)
docker compose -f docker-compose.fullstack.yml up -d
# 5. Open the UI
# http://localhost:7860Both images are pulled automatically from the GitHub Container Registry on first run. The first start takes ~60 seconds while PostgreSQL initialises.
Recommended: pre-pull the importer's helper images so the first import doesn't silently block for several minutes:
# citydb-tool (~350 MB) — used for every CityGML/CityJSON import
docker compose -f docker-compose.fullstack.yml --profile importer pull
# ifc-to-citygml3 (~2 GB) — only needed if you plan to import .ifc files
docker compose -f docker-compose.fullstack.yml --profile ifc pull
# citydb-3dtiler (~1.7 GB) — generates the 3D tiles for the optional 3D view (see below)
docker compose -f docker-compose.fullstack.yml -f docker-compose.fullstack.viz.yml --profile tiler pullThese are pulled on demand anyway on first use if you skip this step — it just moves the wait earlier and shows normal docker pull progress instead of Gradio's import log.
Option 3b: add the 3D viewer (optional)
Add the viewer to the fullstack stack by layering docker-compose.fullstack.viz.yml on top of it:
docker compose -f docker-compose.fullstack.yml -f docker-compose.fullstack.viz.yml up -dThe Chat tab then shows the 3DCityDB Web Map Client next to the chat. The client streams the model as 3D Tiles: they are generated on demand by the citydb-3dtiler container (ghcr.io/3dcitydb/citydb-3dtiler), which the stack starts as a sibling of the agent and writes into a shared tiles_data volume served at /tiles. After an import, tick Generate 3D tiles after import, or press 🔄 Refresh 3D tiles above the viewer at any time (e.g. after editing the database directly). When an answer lists objectids, those features are highlighted and the camera flies to them; features without geometry of their own, such as a Room, are expanded to the surfaces they contain (see resolve_highlight_targets below).
Selecting objects for the chatbot. The viewer also supports selection: turn on the ON/OFF toggle in the viewer's selection panel and click features in the 3D scene — a click on a boundary surface, e.g. a wall, opens a small panel offering the picked surface, its containing feature such as the building, and its siblings, so you can add the level you actually mean (Add to selection). The selected features are listed in the panel (removable with −) and appear live as a 🖱 … features selected badge in the chat UI. Press ✓ Finish selecting when done. The chatbot receives the selection as a [VIEWER SELECTION] context block, so questions like "What is the total floor area of these buildings?" or "Wie alt sind die ausgewählten Objekte?" are scoped to exactly the selected objectids — no coordinate or address filtering needed.
The viewer is baked into the citydb-mcp-agent image, so until the published image is updated rebuild it locally with docker compose -f docker-compose.fullstack.yml build citydb-agent.
Spatial scratchpad (optional)
The spatial scratchpad gives the chatbot a place to park intermediate and final results so they survive beyond a single answer and can be inspected in 3D and queried again. Each saved item is either:
a featureset — a named set of
objectids, e.g. "the buildings in Bräugasse" or "the buildings taller than 30 m", shown as coloured buildings in the tiles; ora geometry — a pin, point, line, draped 2D polygon or extruded 3D solid, e.g. "a pin on my house", "a 3D convex hull around these two buildings", or "a 25 m solid from this polygon".
What it is useful for. It turns a chat into a little scratch workspace: ask the chatbot to save
the result of a query ("store the affected buildings in a variable affected_2013"), then in a
later turn reuse it ("how many of affected_2013 are residential?", "show me the buildings
within 100 m of my marker my_house"). Because the saved items are a per-user SQL view
(my_scratchpad), you can also join them against the CityGML schema in ordinary run_query
queries — set differences, proximity, aggregates — without re-running the original, possibly
expensive, query. Typical uses:
stage and compare the results of several analysis steps (set A minus set B, A ∩ B, …);
drop labelled pins / markers / areas / solids into the 3D view to annotate the scene;
give the user a persistent, clickable, fly-to-able list of "my objects" (bottom-right panel) that survives across turns and across page reloads of the same browser.
How it works. The chatbot creates and manages items through four dedicated MCP tools
(save_to_scratchpad, update_scratchpad_item, scratchpad_action, list_scratchpad), which also
work from external MCP clients (Claude Desktop, VS Code). Saving a featureset re-runs the user's
SELECT read-only in the server — the geometry / objectids never pass through the model. Items
are isolated per user (a read-only database role plus a security_barrier view filtered to the
user's id from the session layer, not from the model), capped (100 items, 20k vertices, 100k
objectids per user), and every change is written to a JSONL audit log. The 3D viewer renders each
item according to its class: pins with labels, Point3D spheres, 3D lines as pipes, filled /
draped polygons and solids, and floating markers with a stem down to the terrain.
Note: the scratchpad is stored in the database, so it is available in all Docker options (BYOD included); the 3D display additionally needs the viewer (
ENABLE_VIZ=true, Option 3b). EnablingCITYDB_SCRATCHPAD=trueneeds a bootstrap role withCREATEROLE(the bundled fullstack superuser has it; with a restricted BYOD account a fallback guard is used instead).
Enable it in production/.env:
CITYDB_SCRATCHPAD=true
# Optional: shared scratchpad id for external MCP clients without a web UI session
# CITYDB_SCRATCHPAD_MCP_USER=<default: a fixed uuid>
# Optional: one JSON line per change; empty switches the audit log off
# CITYDB_MCP_AUDIT_LOG=/app/data/audit/scratchpad.jsonlFull reference — data model, class vocabulary (15 geometry classes + FeatureSet), the
2D↔3D/height/extrusion rules, isolation details, and the viewer behaviour — is in
production/docs/scratchpad.md.
Flood scene (optional)
The 3D viewer can also render a quick bathtub flood scenario, triggered from an ordinary
run_query — so it works with any model (including local Ollama) and needs no extra tool. When an
answer contains a constant column flood_level_m (the water level in the data's height system), the
viewer draws a flat water surface at that height and colours every building: red = flooded
(lowest point below the water), green = held back by a protection_m barrier, grey = dry.
A panel offers the affected count, the current level, a level slider, a gauge widget and a
"Hide flood" button. It is a fast first estimate (no flow, no connectivity, no defences), not a
hydraulic model. Requires the viewer (ENABLE_VIZ=true) and buildings with absolute heights.
FLOOD_SCENE=trueSee production/docs/flood-scene.md for the full mechanics, the
gauge/warning-level settings, and the limitations.
Building locally (optional)
# Linux / macOS
docker compose -f docker-compose.fullstack.yml up -d --build
# Windows — disable BuildKit to avoid a known NTFS ordering bug:
$env:DOCKER_BUILDKIT=0; docker compose -f docker-compose.fullstack.yml up -d --buildWindows note: Only needed when building locally with
--build. The defaultdocker compose up -d(pull from the GitHub Container Registry) works on Windows without any workaround.
Import CityGML/CityJSON/IFC
Once the UI is open:
Go to the Import CityGML / CityJSON / IFC tab
Click Refresh to see files in
./production/data/, or use Upload file to add one from your computerSelect your file and click Import
Watch the live log — the import runs using the Docker container
ghcr.io/3dcitydb/citydb-tool. Note, this container is pulled automatically, if it is not available in your Docker environment so far. In this case, please be patient as it might take 30 seconds before the import process really starts.
The data directory is mounted at
./production/data/on the host and/app/data/inside the container.
Importing IFC files: selecting an .ifc file (or overriding the Format selector to ifc) reveals three conversion options before import:
Option | Effect |
Georeference to Oktoberfest / Munich | Use when the IFC model carries no real-world georeferencing of its own. It will be translated to the Theresienwiese in Munich, which is the place where the annual Oktoberfest takes place. |
Skip storeys | Don't create |
Group unrelated doors/windows into a dummy BuildingConstructiveElement | For IFC models where door/window openings aren't properly related to a wall |
The file is first converted to CityGML 3.0 via ghcr.io/tum-gis/ifc-to-citygml3 (written next to the .ifc file as <name>.gml), then imported the same way as any other CityGML file. Like citydb-tool, this image (~2 GB) is pulled automatically on first use if not already present — see the pre-pull commands above to avoid that wait during the import itself.
Coordinate reference system
Set SRID to the EPSG code for your data before the first start. Common values:
Region | CRS | SRID | Dimensionality | Units of measure |
Germany (UTM Zone 32N) | ETRS89 / UTM Zone 32N |
| 2D | (m, m) |
Germany (UTM Zone 33N) | ETRS89 / UTM Zone 33N |
| 2D | (m, m) |
USA (NAD83 / UTM Zone 14N) | NAD83 |
| 2D | (m, m) |
USA (NAD83 / UTM Zone 14N) | NAD83 (US survey feet) |
| 2D | (ft, ft) |
Japan (PLATEAU) | JGD2011 (JGD2024) + JGD2011 vertical (compound) |
| 3D | (°, °, m) |
Global (WGS84) | WGS 84 |
| 2D | (°, °) |
The Netherlands (RD New + NAP height) | RD + NAP height (compound) |
| 3D | (m, m, m) |
Dimensionality is how many coordinates the CRS defines: the German, US and global rows above are 2D (planar easting/northing, or longitude/latitude, with no vertical axis in the CRS definition). A 3D CRS carries heights as part of the coordinate system, and the two 3D rows here are compound CRS — a horizontal part joined to a separate vertical part:
The Netherlands
7415= the planimetric RD New grid (Amersfoort, EPSG:28992) + NAP height (Normaal Amsterdams Peil, EPSG:5709).Japan (PLATEAU)
6697= JGD2011 / JGD2024 geographic lat/lon in degrees (EPSG:6668) + JGD2011 (vertical) gravity-related height in metres (EPSG:6695).
In both, the data already carries x, y and a height.
The US is not automatically in feet. The standard NAD83 / UTM CRS (such as 26914) is in metres — 26914 uses metre units for both easting and northing. The US survey foot version is a separate EPSG code: 32614 is NAD83 / UTM zone 14N in US survey feet (a different zone-numbering scheme, 326xx, and the 1.000000226 US-survey-foot length). US CityGML data is commonly published in either form, so read the CRS from the file header: if it says 26914 / 269xx the units are metres, if it says 326xx the units are US survey feet. (Geographic WGS 84 / NAD83, 4326 / 4269, are in degrees regardless.)
You should name a 3D SRID whenever one is available for your data. However, many CityGML datasets use a compound CRS with separate SRIDs for planimetry and height, and for these combinations a predefined SRID is often not available in PostGIS. In that case, name the SRID of the planimetric coordinates (2D) instead, as in the 2D rows above.
Useful commands
# View logs
docker compose -f docker-compose.fullstack.yml logs -f
# Stop (preserves database volume)
docker compose -f docker-compose.fullstack.yml down
# Stop and delete all data
docker compose -f docker-compose.fullstack.yml down -vConfiguration Reference
All options are set via environment variables (.env file or Docker Compose environment block).
Database connection
Variable | Default | Description |
|
| PostgreSQL host |
|
| PostgreSQL port |
|
| Database name |
|
| Database user |
| (required) | Database password |
|
| 3DCityDB schema name |
| (auto-built) | Full PostgreSQL URL (overrides individual vars) |
Fullstack only
Variable | Default | Description |
|
| Database name for bundled PostgreSQL |
|
| Database user for bundled PostgreSQL |
|
| Database password for bundled PostgreSQL |
|
| EPSG code for the 3DCityDB spatial reference |
|
| Enable SFCGAL extension (required for, e.g., |
3D viewer (only used when ENABLE_VIZ=true)
Default terrain and base map for the 3D view. Both default to Germany-wide, freely licensed sources (basemap.de) and are applied unconditionally — not gated to one region's SRID. Set a *_URL to an empty string to disable that layer, or override all of these for another country.
Variable | Default | Description |
|
| Cesium quantized-mesh terrain endpoint |
|
| Shown in the terrain picker |
|
| Tooltip for the terrain picker entry |
|
| OGC WMS endpoint added as a selectable base map |
|
| WMS layer name |
|
| Shown in the base-layer picker |
|
| Tooltip for the base-layer picker entry |
| (empty) | Only needed for a WMS without CORS — this image does not ship the vendored client's own |
LLM providers
At least one must be configured for the Docker variants. The Gradio UI auto-selects the provider based on what is available (Anthropic → OpenAI → Ollama, in that priority order).
Variable | Description |
| Anthropic API key ( |
| OpenAI API key ( |
| Base URL for the OpenAI provider. Leave empty for models offered by OpenAI. When using a locally running LLM or a remote LLM (not hosted by OpenAI) via its OpenAI-compatible API (e.g., provided by llama.cpp, vLLM, or Ollama) provide the corresponding endpoint URL (e.g. |
| Ollama base URL (e.g. |
|
|
|
|
Query behaviour
Variable | Default | Description |
|
| Max distinct values for CityGML feature attributes before the attribute is considered not as an enumeration but as free text (only applied when no known codelist exists). The values of enumeration attributes are prefetched and added to the system prompt. |
|
| Number of sample values shown per non-categorical attribute |
Country-specific codelists
Code-type properties (core:Code) are resolved against country-specific codelist
definitions. The country is auto-selected from the database EPSG code
(database_srs), falling back to a generic DEFAULT block for unknown countries:
DE (EPSG 25831–25833, 31466–31469, 5650) — ALKIS/AdV:
function(31 codes),usage,roofType(roof form)JP (EPSG 6668–6692, 2443–2461) — J-PLATEAU/MLIT:
class,roofType(29 codes),usageDEFAULT — SIG3D-standard
roofType
Each codelist is keyed by a qualified composite key of the form
<namespace-alias>:<Classname>.<attribute> — e.g. bldg:Building.function.
The alias comes from the 3DCityDB namespace.alias column and the class name is the
concrete feature class. Lookup is exact (case-insensitive); there is no fallback to
bare attribute names, so same-named attributes in different classes (e.g.
bldg:Building.function vs. brid:Bridge.function) never collide. Only codes that
actually occur in the imported data are exposed to the LLM, with no artificial cap.
Codelists are defined in src/citydb_mcp/tools/dynamic_tools.py
(COUNTRY_CODELISTS). Adding a class or country later (e.g. bldg:BuildingPart.*)
is a pure data change — no code changes required.
Ollama tuning (optional)
Variable | Default | Description |
|
| Context window size (tokens) passed to the Ollama model |
|
| Maximum tokens the local model may generate per response |
|
| Timeout in seconds for Ollama requests |
|
| Maximum ReAct tool-call iterations per question |
WebUI story distillation (optional)
The "Keep a distilled summary" feature (chat WebUI) distills each turn's reasoning trace into a compact story. Both knobs apply to the distillation call regardless of provider (Ollama or OpenAI-compatible).
Variable | Default | Description |
|
| Maximum characters of the reasoning transcript fed into the distillation prompt. Tail-preserving: if the trace is longer, the beginning is cut (early exploration) so the final successful queries are always kept |
|
| Maximum tokens the story itself may contain (OpenAI-compatible provider; the Ollama path is fixed at 700) |
Sessions / multiple users (WebUI)
Per-user state (user identity, per-tab Stop, parallel chats) — see
session-layer.md.
Variable | Default | Description |
|
| How many chat turns may run at the same time (Gradio's default would be 1) |
Spatial scratchpad (only used when CITYDB_SCRATCHPAD=true)
Variable | Default | Description |
|
| Master switch for the per-user spatial scratchpad (table + four MCP tools + |
|
| Name of the dedicated read-only role used for |
| derived | Password for that role; if unset it is derived deterministically from |
| fixed uuid | Shared scratchpad user id for external MCP clients that have no web UI session |
| (empty) | Path to a JSONL audit log, one line per scratchpad change; empty switches it off |
Flood scene (only used when FLOOD_SCENE=true)
Variable | Default | Description |
|
| Adds a short |
| (empty) | Comma-separated CityGML function codes that are not buildings, excluded from the flood count and named in the prompt |
| (empty) | Viewer gauge widget: gauge name and its zero in the data's height system |
| (empty) | Comma-separated warning levels (cm above gauge zero) marked on the gauge |
| (empty) | A historic flood reading (cm) and its label, shown on the gauge |
Available MCP Tools
Static (cached per session)
Tool | Description |
| Version of the 3DCityDB MCP server package |
| 3DCityDB v5 table structures and foreign key relationships |
| SQL best practices and optimisation tips for 3DCityDB |
Dynamic (called at session start)
Tool | Description |
| Discover available object classes with full CityGML hierarchy |
| Resolve properties with codelists for a given class |
| Generic attributes with categorical detection |
| SRS, bounding box, feature counts, database statistics |
| Available Levels of Detail in the database |
| SQL examples filtered to existing object classes |
| Expands GML ids (e.g. a Room) to the geometry-owning features a 3D viewer can highlight, plus a WGS84 camera target |
| Containment tree around one picked feature: its ancestors, children, and siblings |
| Summarizes a multi-feature viewer selection: resolved features, per-class counts, tileable ids |
Runtime (per query)
Tool | Description |
| Execute read-only SQL (SELECT/WITH only) against 3DCityDB |
| Session management and state |
| Narrow scope to specific object classes |
| Conversation history for a session |
| Log query feedback |
Assembly
Tool | Description |
| Orchestrates all tools into a complete system prompt in one call |
Spatial scratchpad (only when CITYDB_SCRATCHPAD=true)
Tool | Description |
| Save a result as a named item — a featureset (SELECT with an |
| Change a saved item in place: style (label, colour, opacity, size), class, and height/extrusion (which may rewrite the geometry to match) |
| Act on named items — |
| List the user's items: name, label, kind, class, colour, visibility and count/geometry type |
Note: The 3D viewer tools —
resolve_highlight_targets,get_feature_tree, anddescribe_selection— are only offered when the stack runs with the viewer enabled (ENABLE_VIZ=true, see Option 3b). The four scratchpad tools are only offered whenCITYDB_SCRATCHPAD=true. In deployments where a feature is off, its tools are omitted from the tool list entirely, so they never appear to clients such as the MCP Inspector. The scratchpad additionally exposes a per-usermy_scratchpadSQL view that can be queried with ordinaryrun_querycalls. See Spatial scratchpad.
Architecture
Claude Code / Claude Desktop / any MCP client
│
MCP Protocol (stdio / SSE)
│
┌──────────────┴──────────────┐
│ 3DCityDB MCP Server │
│ assemble_prompt() │
│ scan_objectclasses() │
│ run_query() │
└──────────────┬──────────────┘
│
3DCityDB v5
(PostgreSQL + PostGIS)
Browser ──► Gradio UI (port 7860) [Docker variants only]
│
┌─────────────────────┴────────────────────┐
│ │
Anthropic / OpenAI Ollama (local)
LiteLLM cloud backend LangChain ReAct (langchain-ollama)
(incl. OpenAI-compatible endpoints robust tool-call parser
via OPENAI_BASE_URL) model profiles + native thinking
│ │
└─────────────────────┬────────────────────┘
│
MCP Client (spawns citydb-mcp subprocess)
│
3DCityDB MCP Server
│
3DCityDB v5Citation
This work was developed at the Chair of Geoinformatics, Technical University of Munich (TUM). Main developer: Khaoula Kanna; additional testing and programming: Thomas H. Kolbe.
The accompanying paper, Enabling AI Agents for Semantic 3D City Models through Automated Domain Context Generation, was published in the ISPRS Annals of the Photogrammetry, Remote Sensing and Spatial Information Sciences (Volume XII-4/W1-2026, 21st ISPRS 3D GeoInfo Conference) and can be cited as:
@inproceedings{kanna2026enabling,
author = {Kanna, Khaoula and Kolbe, Thomas H.},
title = {Enabling AI Agents for Semantic 3D City Models through Automated Domain Context Generation},
booktitle = {ISPRS 21st 3D GeoInfo Conference, ISPRS Ann. Photogramm. Remote Sens. Spatial Inf. Sci.},
volume = {XII-4/W1-2026},
pages = {211--218},
year = {2026},
doi = {10.5194/isprs-annals-XII-4-W1-2026-211-2026},
url = {https://isprs-annals.copernicus.org/articles/XII-4-W1-2026/211/2026/isprs-annals-XII-4-W1-2026-211-2026.html},
}Further documentation of implemented web UI internals:
session-layer.md— users, browser tabs and turns: per-tab Stop, parallel chats, a user context passed to MCP tool calls, and per-user data folders with expiry.scratchpad.md— the spatial scratchpad: per-user saved results (building sets, pins, hulls) that the chatbot creates with MCP tools and the 3D viewer shows, isolated by a read-only database role and a per-user view.flood-scene.md— the 3D flood scene: aflood_level_mcolumn in a query result draws a water surface and colours every building red / green / grey, with a level slider and gauge.
Ideas for Future Developments
We (the developers) have a number of ideas for future improvements and extensions of the ChatBot and the MCP server. They are described in these documents:
idea-for-future-multiple-MCP-servers.md— turning the WebUI into a general-purpose agent shell that can connect to several MCP servers configured via.env.idea-for-future-websearch.md— giving the ChatBot the ability to do web searches and to download & inspect files (e.g. specifications) using a self-hosted SearXNG metasearch engine.idea-for-future-Openstreetmap-interface.md— querying OpenStreetMap geodata (Nominatim / Overpass) to enrich 3DCityDB queries with real-world context.idea-for-future-write-access.md— opt-in write access (DML / DDL) to the database for experimentation, off by default.idea-for-future-memory-rag.md— persistent chat memory (question / answer / distilled story) with RAG retrieval of similar past turns via pgvector, off by default.idea-for-future-speech-interaction.md— let users talk to the ChatBot: voice input/output and a wake word ("Hello CityBot") via an optional localcitydb-voicesidecar (offline STT/TTS, English + German, no API keys), off by default.idea-for-future-viewer-hide-objects.md— MCP tools to hide and unhide 3D objects by their objectid in the Webmap Client, so the agent can visually declutter the scene (e.g. hide a building's roof while inspecting its walls).idea-for-future-viewer-screenshot.md— MCP tools to fly the 3D viewer camera and capture screenshots of the viewer, embedded in the generated answer (and the PDF export) while keeping the image bytes out of the LLM context — e.g. "fly to the three tallest buildings one after another and make a screenshot of each".
These new features are already implemented (to full extent or partially):
idea-for-future-spatial-scratchpad.md— a per-user "spatial scratchpad" table + MCP tools to create, store, style, navigate to, visualize (in the 3D viewer) and delete temporary/derived spatial objects (markers, 2D overlays, 3D solids/pipes), isolated via row-level security, off by default. Implemented in a slightly modified form, seescratchpad.md.idea-for-future-session-scoped-chat-cancellation.md— isolate Stop-button cancellation per chat session so concurrent users do not interrupt each other's work. Implemented, seesession-layer.md.idea-for-future-llm-benchmarking.md— a reusable CLI for interactive ChatBot conversations and repeatable multi-LLM benchmarks, including CSV question sets and optional independent answer grading. Partially implemented and documented inbenchmarking.md
License
The 3DCityDB MCP server is distributed under the Apache License 2.0. See LICENCE for details.
Available Tools
14 toolsassemble_promptA
Assembles the complete system prompt by orchestrating all static and dynamic tools. Returns a structured prompt string containing database schema, object classes with resolved properties and codelists, generic attributes, spatial context, and optionally SQL examples and query guidelines. Set include_query_agent_extras=false for non-query agents.
| Name | Required | Description | Default |
|---|---|---|---|
| include_query_agent_extras | No | Include SQL examples and query guidelines (default: true) | |
| compact | No | Compact rendering for local models with small context windows (default: false) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so the description must carry the full burden. It describes the return value and orchestration but does not disclose side effects, safety, or performance characteristics. The read-only nature is implied but not explicit.
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 two sentences with no fluff. First sentence defines purpose and output; second sentence provides key parameter usage. Every word earns its place.
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, the description thoroughly lists the components of the returned prompt and handles both parameters. It covers the essential information for an agent to understand what the tool returns and when to use parameters.
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 coverage is 100% and the description adds meaningful context beyond the schema: include_query_agent_extras is linked to non-query agents, compact is for local models. This adds semantic value.
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 clearly states that the tool 'Assembles the complete system prompt by orchestrating all static and dynamic tools', specifying verb, resource, and scope. It distinguishes from sibling tools (which provide individual components) by being an orchestrator.
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?
The description provides explicit guidance on parameter usage ('Set include_query_agent_extras=false for non-query agents'), but does not explicitly state when to use this tool versus alternatives like get_database_schema. Context implies usage for full prompt assembly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_database_schemaA
Returns the 3DCityDB v5 table structures, column details, and foreign key relationships. Called once and cached.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite no annotations, the description conveys essential behavior: it is a read operation with caching. No contradictions.
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?
A single sentence that efficiently communicates the action and caching behavior. No extraneous information.
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 zero parameters and no output schema, the description fully explains the tool's purpose and return content, making it complete for an agent.
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?
No parameters exist, and schema coverage is 100%. The description adds context on what is returned, exceeding the baseline expectation.
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 specifies the exact resource ('3DCityDB v5 table structures, column details, and foreign key relationships') and action ('returns'), clearly distinguishing it from siblings like 'get_db_context_snapshot'.
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 states 'Called once and cached,' guiding the agent to avoid repeated calls, though no alternative tools or when-not scenarios are mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_db_context_snapshotA
Returns database-level context: coordinate system, EPSG code, bounding box, feature counts per class, available LoDs, null value percentages, and supported spatial operations.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description must carry the full burden. It correctly implies a read operation by naming return items, but does not explicitly state read-only behavior, side effects, performance, or authorization needs. It adds some value beyond the name by detailing outputs, but not enough to fully compensate for missing annotations.
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 a single sentence with no wasted words. It front-loads the purpose ('Returns database-level context') followed by a colon and a succinct list of returned items. Every part is necessary and clearly communicates the tool's output.
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 the tool has no output schema, the description lists all significant return fields, making it relatively complete for a simple retrieval tool. However, it does not mention the format of the returned data (e.g., JSON object) or any edge cases (e.g., when context is unavailable). It provides sufficient information for most scenarios.
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 tool has no parameters, and the input schema is fully covered (100%). The description does not need to explain parameters. The baseline of 4 applies because there are no parameters to document.
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 clearly states the tool returns 'database-level context' and lists specific items (coordinate system, EPSG code, etc.), making the purpose unambiguous. The verb 'returns' and the resource 'database-level context' are specific and distinct from siblings like 'get_database_schema' which returns different information.
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?
The description provides no guidance on when to use this tool versus alternatives such as 'get_database_schema' or 'get_session_context'. There is no mention of prerequisites, limitations, or typical use cases. The agent must infer usage from the tool name and list of return items.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_examplesA
Returns SQL query examples filtered to only include examples for object classes that exist in the database.
| Name | Required | Description | Default |
|---|---|---|---|
| objectclass_ids | Yes | List of available objectclass IDs to filter examples |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must fully convey behavior. It only mentions filtering, but fails to disclose whether the operation is read-only, what happens with invalid IDs, the output format, or any side effects.
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 a single sentence, front-loaded with the action, and contains no unnecessary words. Every word contributes to understanding the tool's purpose.
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 one-parameter tool, the description is minimally complete. However, it lacks details about the return format, error handling, and any constraints on the objectclass_ids, which would be necessary for an agent to invoke it confidently without relying on prior knowledge.
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 input schema fully documents the only parameter (objectclass_ids) with a description similar to the tool's description. The tool description adds no additional meaning beyond what the schema already provides, matching the baseline for high schema coverage.
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 clearly states the tool returns SQL query examples, and specifies a filtering condition to only include examples for existing object classes. This distinguishes it from sibling tools like get_database_schema or run_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?
The description implies when to use: when you need filtered SQL examples. However, it does not provide explicit guidance on when not to use this tool or mention alternatives among the siblings, leaving it to the agent to infer.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_generic_attributesA
Fetches generic attributes (namespace_id=3) with categorical detection. String attributes with few distinct values include all possible values. Numeric attributes include min/max range.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Without annotations, the description discloses key behaviors: categorical detection includes all possible values for strings, and numeric attributes show min/max range. However, it does not mention read-only nature or side effects, which could be inferred but not explicit.
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?
Two sentences, front-loaded with the core purpose, concise and no redundant information. Every sentence adds value.
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 and low complexity, the description sufficiently explains what is returned (all possible values for categorical, min/max for numeric). No missing critical information for the tool's purpose.
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?
Input schema has no parameters (0 count, 100% coverage), so the baseline is high. The description adds no parameter-level details but that's fine since none exist. It explains output behavior which compensates.
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 clearly states the action ('Fetches generic attributes') and specifies the resource with a unique identifier (namespace_id=3), distinguishing it from sibling tools like run_query or get_database_schema.
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?
No explicit guidance on when to use or alternatives. The specialized namespace and categorical detection imply a specific use case, but lack of explicit context or when-not-to-use reduces clarity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_historyC
Returns the conversation history for a session.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so the description must cover behavior. It only states the output type but omits details like ordering, pagination, or performance implications. Does not disclose if it's read-only, which is implied but unconfirmed.
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?
Single sentence, no filler, directly states purpose. Every word earns its place.
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 retrieval tool with no output schema, the description is minimally adequate. However, it lacks contextual details like whether history is ordered chronologically or how limits/errors are handled.
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 session_id has no description in the schema (0% coverage) and the tool description adds no semantic meaning beyond the parameter name. An agent cannot infer format or constraints.
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 clearly states the tool returns conversation history for a session, matching the name. It distinguishes from siblings like get_session_context or get_examples by focusing on history. However, it could be more specific about what 'history' includes.
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?
No guidance on when to use this tool vs. alternatives like get_session_context. No context about prerequisites or when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_lod_configA
Returns available Levels of Detail in the database, with the most common LoD set as default.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description must cover behavioral traits. It only states the tool returns data, which implies a read-only operation, but provides no additional disclosure about side effects, caching, or performance characteristics.
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 a single sentence that is concise and front-loaded, containing no unnecessary information.
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, the description lacks detail on the return format or structure of the LoD data. It mentions a default but does not elaborate, leaving the agent with incomplete information for a simple tool.
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 tool has no parameters, so the description does not add parameter meaning. According to guidelines, baseline is 4 for zero parameters.
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 clearly states the tool returns available Levels of Detail and indicates a default is set. It uses a specific verb 'returns' and a specific resource 'available Levels of Detail', distinguishing it from sibling tools like get_database_schema which focus on different aspects.
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?
No guidance is provided on when to use this tool versus alternatives. The description simply states what it does without offering context on selection criteria, prerequisites, or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_query_guidelinesA
Returns SQL best practices, indexed columns, optimization tips, and expensive operations to avoid for 3DCityDB queries.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description bears full responsibility for behavioral disclosure. It does not mention whether the tool is read-only, requires any authentication, or has side effects. The description only lists what is returned, omitting important behavioral traits like cost or data source.
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 a single sentence of 16 words that directly states the tool's purpose. It is concise and front-loaded with the main action, with no unnecessary words.
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 and no parameters, the description is the sole source of information. It lists the types of information returned but does not specify format (e.g., text, JSON) or provide example content. For a simple reference tool, this is minimally adequate but could be more complete.
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 tool has zero parameters and schema coverage is 100%. The description does not need to add parameter info since there are none. Baseline of 4 is appropriate as no additional meaning is required beyond the schema.
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 clearly states it returns SQL best practices, indexed columns, optimization tips, and expensive operations to avoid for 3DCityDB queries. The verb 'Returns' and specific resource names make the purpose unambiguous, and it is distinct from siblings like get_database_schema.
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?
The description does not explicitly state when to use this tool versus alternatives. While the purpose implies consulting it for SQL guidelines, there is no guidance on when not to use it or which sibling tools to consider instead. The context is implied but not articulated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_session_contextB
Returns or creates the current user session context.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | No | Optional session ID. Creates new session if not provided. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description states the tool 'returns or creates', implying both read and write behavior, but does not disclose side effects, required permissions, or whether creation is idempotent. Since no annotations are provided, the description carries the full burden of transparency, which it fails to meet.
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 a single sentence that efficiently conveys the core function. However, it lacks structural elements like separate sections for behavior or examples, and could benefit from front-loading the primary action.
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 that the tool can both return and create session context, the description omits important information such as the return value format, any error conditions, or how the session context is represented. No output schema exists to fill this gap, so completeness is insufficient.
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 coverage is 100%, but the description adds context: 'Optional session ID. Creates new session if not provided.' This explains the parameter's effect beyond the schema's basic description, aiding in correct usage.
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 clearly states the tool's function: returning or creating the current user session context. However, it does not differentiate this tool from siblings like get_db_context_snapshot or get_history, which might also involve session or context retrieval.
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?
No guidance is provided on when to use this tool versus alternatives. The description does not mention prerequisites, when a session is created versus returned, or how this tool compares to other context-related siblings like get_db_context_snapshot.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_propertiesC
For a given objectclass_id, walks the superclass hierarchy, collects all schema-defined properties, filters against the property table to keep only existing properties, determines value columns and join info, and resolves codelists for Code-type properties. Returns fully enriched PropertyDefinitions.
| Name | Required | Description | Default |
|---|---|---|---|
| objectclass_id | Yes | The objectclass ID to resolve properties for (e.g. 901 for Building) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Without annotations, the description must disclose behavioral traits. It outlines internal steps (walk hierarchy, filter, resolve codelists) but omits side effects, error conditions, or performance implications.
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 a single lengthy sentence that packs many steps. It is not optimally concise or front-loaded; restructuring would improve clarity.
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?
No output schema exists, and the description only vaguely mentions 'Returns fully enriched PropertyDefinitions.' Missing details on return format, errors, and edge cases for invalid inputs.
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 coverage is 100% for the single parameter, so baseline is 3. The description does not add additional meaning beyond the schema's parameter description.
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 clearly states the tool resolves properties for a given objectclass_id by walking the superclass hierarchy and enriching. It is specific and distinguishes from general query tools, though no explicit sibling differentiation is provided.
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?
No guidance on when to use this tool vs alternatives like get_generic_attributes or scan_objectclasses. No when-not or prerequisites mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_queryA
Executes a read-only SQL query against 3DCityDB. Only SELECT and WITH (CTE) statements are allowed. Results are automatically limited to 500 rows.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | SQL SELECT query to execute |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses read-only nature, allowed statements, and the automatic 500-row limit, covering key behavioral traits. It could mention error handling or performance, but the given details are sufficient.
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?
Two sentences, front-loaded with the main action, and every word serves a purpose. No redundancy or verbosity.
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 the tool's simplicity (1 param, no output schema, no annotations), the description covers essential aspects: what it does, allowed queries, result limit. It could mention that queries are executed against a specific database, but that is already stated.
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 coverage is 100% for the single parameter 'sql', and the description adds valuable constraints: only SELECT/WITH queries are allowed and results are limited to 500 rows, enhancing the schema's basic description.
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?
Description clearly states it executes read-only SQL queries against 3DCityDB, specifying allowed statement types (SELECT and WITH), which distinguishes it from sibling tools that perform other database operations.
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?
The description specifies allowed statements and implicitly guides against using it for mutations or unsupported queries. However, it doesn't explicitly compare to sibling tools or provide when-not-to-use scenarios.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scan_objectclassesA
Scans the database for existing object classes (e.g. Building, Vegetation, LandUse). Returns the full class hierarchy with superclass chain, namespace IDs, and schema definitions.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description must carry full behavioral burden. It describes the output but does not disclose performance, authorization requirements, or that it is a read-only operation. Lacks details on side effects or error conditions.
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?
Two concise sentences with no redundant words. Front-loaded with verb and examples, immediate clarity.
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 zero-parameter tool with no output schema, the description adequately covers purpose and output. Lacks detail on output format or structure, but sufficient given simplicity.
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 has 0 parameters (100% coverage automatically). Description adds value by explaining what the tool returns beyond the schema, which only states no parameters. Baseline 4 applies as per guidelines.
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?
Description uses clear verb 'Scans' with specific resource 'existing object classes', provides examples (Building, Vegetation, LandUse), and specifies the return value (full class hierarchy with superclass chain, namespace IDs, schema definitions). Distinguishable from sibling tools like get_database_schema which returns broader schema.
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?
Description implies usage for retrieving object class hierarchy but does not explicitly state when to use this tool versus alternatives like get_database_schema or get_generic_attributes. No guidance on prerequisites or exclusion criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_feedbackC
Logs feedback for a query execution (rating, errors).
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | ||
| query | Yes | ||
| rating | Yes | ||
| execution_time_ms | No | ||
| result_count | No | ||
| error | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the entire burden falls on the description. It only says 'Logs feedback,' which implies a write operation but lacks details on side effects, permissions, rate limits, or data persistence. The description does not clarify whether the operation is reversible or what happens on failure.
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 single-sentence description is concise and front-loaded with the primary action. However, it could include more context without becoming verbose, but remains appropriately sized for a simple tool.
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 the tool has 6 parameters, no output schema, and no annotations, the description is incomplete. It does not explain return values, success/failure signals, or how the feedback is used. The minimal information leaves gaps for an AI agent to correctly invoke the tool.
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 schema has 6 parameters with 0% description coverage. The description mentions 'rating' and 'errors,' but omits session_id, query, execution_time_ms, and result_count. It adds some meaning for the mentioned params but fails to explain the purpose of the others, which is insufficient given the low schema coverage.
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 clearly states the tool's purpose: 'Logs feedback for a query execution (rating, errors).' It uses a specific verb ('Logs') and resource ('feedback for a query execution'), and distinguishes itself from sibling tools (no other tool logs feedback).
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?
The description provides no guidance on when to use this tool versus alternatives. While it implies use after a query execution, it does not specify prerequisites, exclusions, or mention related tools like 'run_query' for context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_module_selectionB
Narrows the user's scope to specific object classes or modules. Affects which properties, examples, and codelists are relevant.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | ||
| objectclass_ids | Yes | Object class IDs to focus on | |
| modules | No | Module names to focus on (e.g. ['building', 'vegetation']) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description bears full responsibility for disclosing behavioral traits. It states the tool 'narrows scope' and 'affects relevancy', but does not clarify whether the selection is additive or overwriting, whether the change is persistent, or what side effects occur. The absence of output schema also leaves return behavior unclear.
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?
Two sentences are concise and front-loaded; the first states the core function, the second elaborates on the effect. No unnecessary words or repetition.
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 the complexity of a mutation tool with no annotations, no output schema, and a required session_id parameter lacking description, the description is incomplete. It does not explain error handling, parameter constraints, or how the tool fits into the broader workflow with siblings like get_session_context or run_query.
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 67% (two of three parameters have descriptions). The description echoes the schema by mentioning 'object classes or modules' but adds no new semantic detail beyond that. The baseline score of 3 is appropriate given moderate coverage and marginal added value.
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 clearly states the tool 'narrows the user's scope to specific object classes or modules' with a specific verb ('narrows') and resource ('object classes or modules'). It is clear but does not explicitly differentiate from sibling tools like get_session_context that also handle session state, though the action (update vs. retrieve) is implied.
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?
The description implies usage when needing to focus on relevant properties, examples, and codelists, but provides no explicit when-to-use, when-not-to-use, or alternatives among sibling tools. No prerequisites (e.g., session must exist) are mentioned.
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.
14 tool updates
v0.2.0- First observed
assemble_prompt - First observed
get_database_schema - First observed
get_db_context_snapshot - First observed
get_examples - First observed
get_generic_attributes - First observed
get_history - First observed
get_lod_config - First observed
get_query_guidelines - First observed
get_session_context - First observed
resolve_properties - First observed
run_query - First observed
scan_objectclasses - First observed
submit_feedback - First observed
update_module_selection
TDQS
Scored across 14 tools
All 14 tools have clearly distinct purposes—retrieving different types of metadata (schema, context, examples, attributes, etc.), executing queries, scanning object classes, updating module selections, and submitting feedback. No two tools overlap in functionality.
Every tool follows the consistent verb_noun pattern using snake_case (e.g., get_database_schema, run_query, submit_feedback). Minor abbreviation ('db' vs 'database') is common and does not break consistency.
14 tools is well-suited for a 3DCityDB query agent—covering metadata retrieval, query execution, configuration, and feedback without excess or deficiency. The count feels appropriate for the domain.
The tool set covers all necessary operations for a read-only query agent: database introspection (schema, context, classes, attributes), query building guidance (examples, guidelines), query execution, session management, and feedback logging. No obvious gaps exist for the stated purpose.
Maintenance
Related MCP Connectors
Text-to-SQL MCP server: read-only queries on PostgreSQL, MySQL and SQL Server with your real schema
Query Postgres, MySQL, SQL Server, Oracle, BigQuery, ClickHouse and Redshift from your AI client.
Mobility, geocoding and nearby urban services for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceEnables natural language and geospatial queries on PostGIS databases, with 32 tools for spatial analysis, geometry operations, and database management.5MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to query databases using natural language, with automatic schema discovery and SQL compilation.865 npm3,227Apache 2.0
- AlicenseAqualityCmaintenanceEnables AI assistants to interact with Autodesk Civil 3D through natural language, supporting tools for surfaces, alignments, profiles, corridors, pipe networks, COGO points, and AutoCAD geometry.93MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to query and visualize ArcGIS Online/Enterprise geospatial data through natural language, performing spatial analysis and map generation.-