MCP server
Run the CityParquet MCP server locally from npm or use the hosted endpoint, register it with Claude Code, Codex or any MCP client, and use its five tools.
The server is published on npm as
@cityjson/cityparquet-mcp; its source is under
ai/mcp. It runs
in two ways:
- Locally, over stdio. It runs on your machine, so it can read and write your own files as well as packages on the web. Set it up as below.
- Hosted, over streamable HTTP. It runs on Google Cloud Run, read-only and sandboxed; see The hosted endpoint.
Install
You need Node.js 24 or newer. Your client starts the server with npx, which
downloads the package on first use, so there is nothing to clone or build.
Register it with your client
Claude Code:
claude mcp add --scope user cityparquet -- npx -y @cityjson/cityparquet-mcpCodex:
codex mcp add cityparquet -- npx -y @cityjson/cityparquet-mcpClients configured with an mcpServers JSON file: add the server to
that file. Other clients have their own way to register a stdio server:
give it the command npx and the arguments -y and @cityjson/cityparquet-mcp.
{
"mcpServers": {
"cityparquet": {
"command": "npx",
"args": ["-y", "@cityjson/cityparquet-mcp"]
}
}
}The package carries the documentation the server serves, so it needs no other download.
Let the first start finish
On its first start the server installs httpfs, cityjson, three_d
and spatial into ~/.cityparquet-mcp/extensions, which takes a few seconds. Later
starts load them from there.
Then ask your agent something like “Describe https://cityparquet.open3d.city/data/delft and tell me the total LoD 2.2 volume of its buildings.”
The tools
| Tool | What it does |
|---|---|
cityparquet_docs_outline |
Lists the chapters of the three corpora: spec (the specification and its design decisions), duckdb-cityjson and duckdb-3d (the extensions’ function references). |
cityparquet_docs_search |
Finds the sections that mention a term and returns a snippet of each, for example a column name, a function or a rule. |
cityparquet_docs_read |
Reads one chapter, or one section of it. |
cityparquet_describe |
Describes a package directory or one .parquet file, by URL or local path: its tables, row counts, LoDs, geometry columns and CRS, with notes on anything unusual. |
cityparquet_query |
Runs SQL against DuckDB with cityjson, three_d and spatial loaded. |
cityparquet_query is built to keep results small enough for a model’s
context:
- A script runs one statement at a time. DuckDB expands every
PRAGMAin a batch before running any of it, so aCREATE SCHEMAfollowed by a package pragma would fail if sent together. The tool splits the script, returns one result per statement, and stops at the first error. - Results are bounded. It returns 100 rows by default, and says
truncated: truewhen there were more. Geometry appears as<BLOB 4213 bytes>, and any other value over 256 bytes is replaced by its type and length. So select the columns you need rather thanSELECT *. - Each statement has a deadline, 120 seconds by default. A statement that times out is cancelled, and the server keeps running.
cityparquet_describe reads each file’s footer and the package’s
metadata.json. When the tables of one package state different coordinate
reference systems, it reports each table’s CRS and no package CRS, rather
than taking the first table’s.
The tool names begin with cityparquet_ for now. They may change if this
server is merged with the CityJSON one.
The hosted endpoint
The same five tools are served over streamable HTTP, deployed from the
repository to Google Cloud Run. Register it with the
endpoint’s URL, ending in /mcp:
claude mcp add --transport http cityparquet https://cityparquet-mcp-pg5p2zrr2a-ez.a.run.app/mcp
It differs from a local server in what it may touch:
- Read-only, and no local files. Every engine is sandboxed.
COPY … TO,cityparquet_writeand local paths incityparquet_describeare refused. - Project data hosts only. A query can read
cityparquet.open3d.city,cityjson.open3d.cityandflatcitybuf.open3d.cityover HTTPS and nothing else, soread_parqueton any other URL fails. DuckDB’s network goes through a proxy it is locked to, which admits those hosts only. For other data, run the server locally. - No secrets, and no
spatial. A statement that mentionsSECRETis refused, because a DuckDB secret could route around that proxy, andspatialis not loaded, because its GDAL has an HTTP client of its own. Usethree_dinstead:ST_3DFootprintArea,ST_3DTransform. - Nothing persists between calls. Each call that runs SQL gets a freshly
built engine, discarded afterwards, so a table created in one call does not
exist in the next. Write a whole workflow as one
cityparquet_queryscript. - Bounded. A statement returns at most 1000 rows and runs for at most 60
seconds. When every engine is busy, the endpoint answers 503 with
Retry-After. - Cold starts. Instances stop when idle, and the first request after that waits a few seconds for one to start.
To run the HTTP server yourself, see
ai/mcp/README.md.
Configuration
These apply to the local server. Set them as environment variables, for
example with
claude mcp add … -e CITYPARQUET_MCP_MEMORY_LIMIT=4GB -- npx -y @cityjson/cityparquet-mcp.
| Variable | Default | Meaning |
|---|---|---|
CITYPARQUET_MCP_SANDBOX |
off | 1 locks the engine down: no local files, no further extensions, and limits that cannot be raised again. Local paths in cityparquet_describe are refused too. |
CITYPARQUET_MCP_EXTENSIONS |
httpfs,cityjson,three_d,spatial |
The extensions to load. |
CITYPARQUET_MCP_EXTENSION_DIR |
~/.cityparquet-mcp/extensions |
Where the extensions are installed. Keep it separate from DuckDB’s own ~/.duckdb, which may hold builds for another DuckDB version. |
CITYPARQUET_MCP_MEMORY_LIMIT |
DuckDB’s default | DuckDB’s memory_limit, for example 4GB. A sandboxed engine cannot spill to disk, so raise this when sandboxed. |
What to expect
- Writing needs the sandbox off.
COPY … TOandcityparquet_writewrite local files, which a sandboxed engine refuses. - Package pragmas take local directories.
PRAGMA cityparquet_readfails on a URL. Query a remote package withread_parqueton its files, or download it first. - Invalid solids raise.
ST_3DVolumeraises on a solid that is not closed, manifold and oriented, and real data has some. The skills teach the gated pattern.
To build the server from a clone, or develop it, see
ai/mcp/README.md.