3dcitydb-mcp-server
Health Gecti
- License — License: Apache-2.0
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Community trust — 11 GitHub stars
Code Gecti
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
A Model Context Protocol (MCP) server that gives AI assistants (Claude Code, Claude Desktop, and any MCP-compatible client) direct, natural language access to semantic 3D city models in CityGML managed within a 3DCityDB V5. Also includes an agentic Chatbot application using the MCP server with commercial or locally running LLMs.
3DCityDB MCP Server
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 paper (link coming soon) was done using 100 queries of 4 different complexity levels. The complete list of the queries can be found here.
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 exposed - Generic 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 PostgreSQL - Prompt assembly —
assemble_promptorchestrates all tools into a complete system prompt in one call - 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
- CityGML 1.0-3.0/CityJSON import — one-click import via the Gradio UI (fullstack Docker mode only)
Deployment Options
There are three ways to run the 3DCityDB MCP Server:
| Option 1: PyPI | Option 2: Docker BYOD | Option 3: Docker Fullstack | |
|---|---|---|---|
| Best for | Claude Code / Claude Desktop power users | Existing 3DCityDB instances | Starting from a .gml file |
| Requires | Python 3.10+, running 3DCityDB | Docker, running 3DCityDB | Docker only |
| Gradio UI | No (uses your AI client directly) | Yes (localhost:7860) |
Yes (localhost:7860) |
| CityGML/CityJSON import | Manual | Manual | Via Gradio UI |
| Database | Your own | Your own | Bundled (PostgreSQL + PostGIS + SFCGAL) |
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-server
Or 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 .env
Then 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:11434
The server loads .env automatically by searching upward from the working directory.
Verify your installation
3dcitydb-doctor
Checks 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
claude
The 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 8080
- Clients connect via:
http://your-server:8080/sse - Health check:
http://your-server:8080/health
LangChain agent CLI (optional)
A standalone CLI agent that uses the MCP tools directly:
3dcitydb-agent
Requires 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 PowerShell
Edit .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:7860
The pre-built image (khaoulakanna1/citydb-mcp-agent:latest) is pulled automatically from Docker Hub 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 |
| SQL Inspector | Shows the last SQL query dispatched to the database (below the chat input) |
| MCP Inspector | Lists all active MCP tools and lets you refresh the assembled system prompt |
| System Prompt | Displays the full assembled system prompt sent to the LLM — useful for debugging |
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 | anthropic / openai / ollama |
Auto-selected from .env; can be overridden per session |
| 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 | off / low / medium / high (+ max for OpenAI) |
Reasoning level for thinking-capable models. Ollama uses native think; OpenAI-compatible endpoints use reasoning_effort. Higher levels are slower but more thorough |
| Prompt mode | auto / compact / full |
auto picks compact for small local models; override for complex queries |
| Context window (Ollama) | 8K / 32K / 64K / 128K / 256K (default 64K) | Tokens available to the model; 128K recommended for complex queries |
| Include all reasoning steps in context (Ollama) | on / off (default on) | Feeds each turn's full trace back into context on later turns; increases token usage |
| Add self-summarized "lessons learned" (Ollama) | on / off (default off) | Asks the model to summarize what it learned after each turn and carries that note forward |
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 --build
Windows 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 down
Option 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.
Prerequisites
- Docker with Compose (V2)
- A CityGML or CityJSON 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 PowerShell
Edit .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:7860
Both images are pulled automatically from Docker Hub on first run. The first start takes ~60 seconds while PostgreSQL initialises.
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 --build
Windows note: Only needed when building locally with
--build.
The defaultdocker compose up -d(pull from Docker Hub) works on Windows without any workaround.
Import CityGML/CityJSON
Once the UI is open:
- Go to the Import CityGML/CityJSON tab
- Click Refresh to see files in
./production/data/ - Select 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.
Coordinate reference system
Set SRID to the EPSG code for your data before the first start. Common values:
| Region | CRS | SRID |
|---|---|---|
| Germany (UTM Zone 32N) | ETRS89 / UTM Zone 32N | 25832 |
| Germany (UTM Zone 33N) | ETRS89 / UTM Zone 33N | 25833 |
| USA (NAD83 / UTM Zone 14N) | NAD83 | 26914 |
| Global (WGS84) | WGS 84 | 4326 |
Note that you should name a 3D SRID, if available. However, often the CRS used in CityGML datasets use a compound CRS with separate SRIDs for planimetry and height, and for these combinations often no predefined SRIDs are defined in PostGIS. In this case, just name the SRID of the planimetric coordinates (2D), like in the examples shown 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 -v
Configuration Reference
All options are set via environment variables (.env file or Docker Compose environment block).
Database connection
| Variable | Default | Description |
|---|---|---|
CITYDB_HOST |
localhost |
PostgreSQL host |
CITYDB_PORT |
5432 |
PostgreSQL port |
CITYDB_NAME |
citydb |
Database name |
CITYDB_USER |
citydb |
Database user |
CITYDB_PASSWORD |
(required) | Database password |
CITYDB_SCHEMA |
citydb |
3DCityDB schema name |
DATABASE_URL |
(auto-built) | Full PostgreSQL URL (overrides individual vars) |
Fullstack only
| Variable | Default | Description |
|---|---|---|
POSTGRES_DB |
citydb |
Database name for bundled PostgreSQL |
POSTGRES_USER |
citydb |
Database user for bundled PostgreSQL |
POSTGRES_PASSWORD |
citydb |
Database password for bundled PostgreSQL |
SRID |
25832 |
EPSG code for the 3DCityDB spatial reference |
POSTGIS_SFCGAL |
true |
Enable SFCGAL extension (required for, e.g., CG_Volume, CG_3DArea) |
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 |
Anthropic API key (sk-ant-...) |
OPENAI_API_KEY |
OpenAI API key (sk-...); when using Ollama via the OpenAI-compatible endpoint this value must be ollama |
OPENAI_BASE_URL |
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. http://host.docker.internal:11434/v1/) |
OLLAMA_BASE_URL |
Ollama base URL (e.g. http://host.docker.internal:11434) |
Query behaviour
| Variable | Default | Description |
|---|---|---|
CATEGORICAL_THRESHOLD |
20 |
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. |
SAMPLE_VALUES_COUNT |
5 |
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),usage - DEFAULT — 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 |
|---|---|---|
OLLAMA_NUM_CTX |
65536 |
Context window size (tokens) passed to the Ollama model |
LOCAL_MAX_TOKENS |
16000 |
Maximum tokens the local model may generate per response |
OLLAMA_TIMEOUT |
300 |
Timeout in seconds for Ollama requests |
AGENT_MAX_ITERATIONS |
10 |
Maximum ReAct tool-call iterations per question |
Available MCP Tools
Static (cached per session)
| Tool | Description |
|---|---|
get_server_version |
Version of the 3DCityDB MCP server package |
get_database_schema |
3DCityDB v5 table structures and foreign key relationships |
get_query_guidelines |
SQL best practices and optimisation tips for 3DCityDB |
Dynamic (called at session start)
| Tool | Description |
|---|---|
scan_objectclasses |
Discover available object classes with full CityGML hierarchy |
resolve_properties(objectclass_id) |
Resolve properties with codelists for a given class |
get_generic_attributes |
Generic attributes with categorical detection |
get_db_context_snapshot |
SRS, bounding box, feature counts, database statistics |
get_lod_config |
Available Levels of Detail in the database |
get_examples(objectclass_ids) |
SQL examples filtered to existing object classes |
Runtime (per query)
| Tool | Description |
|---|---|
run_query(sql) |
Execute read-only SQL (SELECT/WITH only) against 3DCityDB |
get_session_context |
Session management and state |
update_module_selection |
Narrow scope to specific object classes |
get_history |
Conversation history for a session |
submit_feedback |
Log query feedback |
Assembly
| Tool | Description |
|---|---|
assemble_prompt |
Orchestrates all tools into a complete system prompt in one call |
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 v5
Citation
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 (to be published by end of September 2026) 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},
year = {2026},
}
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.
License
The 3DCityDB MCP server is distributed under the Apache License 2.0. See LICENCE for details.
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi