CNG MCP Server
Model Context Protocol (MCP) server for CNG Sandbox. Exposes datasets, stories, connections, and validation as composable tools for agents.
What is MCP?
MCP is a protocol that lets applications (agents, CLI tools, SDKs) discover and interact with tools and resources in a standardized way. This server makes the CNG Sandbox accessible to any MCP-compatible client.
Installation
pip install cngstorytelling-mcp
This installs the cng-mcp command. To run against your own instance, see the self-hosting guide.
Quick Start
1. Start the Server
# Default API URL (http://localhost:8086)
cng-mcp --workspace-id <8-char-id>
# Custom API URL
cng-mcp --api-url http://your-sandbox.com --workspace-id <8-char-id>
The server communicates over stdio. Connect with any MCP client.
The ingestion API requires an X-Workspace-Id header on workspace-listing endpoints (/api/datasets, /api/connections, /api/stories). Pass --workspace-id (or set SANDBOX_WORKSPACE_ID) so the server can forward it — without it, listing endpoints return 400.
2. Use with Claude Desktop / Code
Add to your MCP client config:
{
"mcpServers": {
"cng-sandbox": {
"command": "cng-mcp",
"args": ["--api-url", "http://localhost:8086", "--workspace-id", "abcd1234"]
}
}
}
Tools
read_datasets
List all datasets in your workspace with IDs, types, and bounds.
read_story
Get a story's metadata and chapters.
Input: story_id (string)
create_story
Create a new story. Input:
title(string)description(string)chapters(array): each withtitle,narrative,map_state, andlayer_config(containingdataset_idorconnection_id)map_state:{ center: [lng, lat], zoom, bearing, pitch, basemap }plus optional 3D fields:terrain:{ enabled: bool, exaggeration: number }— 3D terrain relief. Ignored when the chapter has a bound data layer (data can't drape on terrain in v1); use terrain on scene-setting chapters only.globe:bool— globe projection with atmosphere; works with data layers.buildings:bool— extruded 3D buildings (OpenFreeMap).- Omit these for a flat 2D map. Portable/archival HTML exports ignore 3D fields and render flat.
- Chapter
typemay be"flyover": a scroll-scrubbed 3D camera flight. Flyover chapters add:keyframes(array, >= 2 to fly):{ center: [lng, lat], zoom, bearing, pitch, caption? }— the camera path, interpolated smoothly in reader scroll order.captionis markdown shown as the camera passes that keyframe.scroll_length(number, default 1): scroll distance multiplier (~one viewport height per keyframe segment at 1).layer_configis optional; as with other chapters, terrain is ignored when a data layer is bound. The best flyovers are terrain/buildings scene-setters with no data layer.map_statepose fields are ignored — keyframe 0 is the entry camera. Compute keyframes from dataset bounds for an easy orbit: fixcenter/zoom/pitch, sweepbearingacross ~180° in 5 steps.
update_story
Modify an existing story.
Input: story_id, updates (object with changed fields)
read_connections
List external tile source connections.
create_connection
Create a new external tile source connection. Input:
name(string)url(string)connection_type(string): one ofzarr,cog,pmtiles,xyz_raster,xyz_vector,geoparquet,copcbounds(array, optional):[west, south, east, north]min_zoom/max_zoom(integer, optional)tile_type(string, optional): tile image format (e.g.png,webp)band_count(integer, optional)rescale(string, optional): range as"min,max"config(object, optional): additional tiler configgeozarr_attrs(object, optional): GeoZarr-spec attributes
validate_layer_config
Check if a layer configuration is valid before creating a chapter.
Input: dataset_id, optional colormap, rescale_min/rescale_max, and color_mode (elevation/intensity/classification/rgb) for point-cloud (copc) layers. Provide either a colormap (raster) or a color_mode (copc).
Ingestion & export
get_job_status
Get the status of a conversion job by job ID (pending/converting/ready/failed).
Input: job_id (string)
ingest_url
Ingest a remote geospatial file (GeoTIFF, GeoJSON, Shapefile .zip, NetCDF, HDF5) into a dataset. Waits for conversion to finish and returns the dataset ID.
Input: url (string); optional wait (boolean, default true), timeout (number, default 600)
discover_remote
List geospatial files at a remote URL or S3 prefix before connecting them.
Input: url (string)
connect_remote_temporal
Register remote COGs as a temporal (date-stepped, time-slider) or mosaic dataset. Discovers files at the URL if an explicit file list is not given; waits for the job to finish.
Input: url (string); optional mode (temporal or mosaic, default temporal), files (array of {url, filename}), timeout (number)
upload_story_asset
Upload a local image or CSV file as a story asset (for image chapters and CSV chart chapters). Returns the asset ID and URL.
Input: file_path (string), kind (image or csv); optional story_id (string)
update_connection_colormap
Set the preferred colormap for a raster connection (cog/xyz_raster/raster pmtiles).
Input: connection_id (string), colormap (string); optional reversed (boolean)
update_connection_categories
Update category labels/colors for a categorical connection.
Input: connection_id (string), categories (array of {value:int, label?:str, color?:'#RRGGBB'})
delete_connection
Delete an external tile source connection by ID.
Input: connection_id (string)
export_story_interactive
Build and download a story's self-contained interactive HTML bundle (.zip) to a local path. Stories with zarr layers, flyover chapters, or scrolly chapters needing snapshots return an error.
Input: story_id (string), output_path (string)
Resources
cng://datasets— Catalog of available datasetscng://story-templates— Pre-built templates agents can referencecng://colormaps— Valid colormap names
Development
cd mcp
uv sync --extra dev
uv run pytest tests/ -v
See CONTRIBUTING.md and ARCHITECTURE.md.
Troubleshooting
"Connection refused" on localhost:8086
Verify sandbox stack is running: docker compose ps. If not, start it: docker compose up -d.
"Unknown colormap" validation error
List valid colormaps via the cng://colormaps resource and pick one.
Server doesn't discover tools
Run with debug logging: cng-mcp --log-level DEBUG. Check for tool registration messages.
"ModuleNotFoundError: No module named 'cng_mcp'"
Install in editable mode from the mcp/ directory: pip install -e mcp/.
Metadata
Release files for cngstorytelling-mcp 2.15.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| cngstorytelling_mcp-2.15.0.tar.gz | 81.1 kB | With provenance | Details for cngstorytelling_mcp-2.15.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cngstorytelling_mcp-2.15.0-py3-none-any.whl | Python 3 | none | any | Details for cngstorytelling_mcp-2.15.0-py3-none-any.whl |
Total release size: 105.3 kB
Release files / cngstorytelling_mcp-2.15.0.tar.gz
| Download URL | cngstorytelling_mcp-2.15.0.tar.gz |
|---|---|
| Size | 81.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
be8b50b95d4c10d550f6a98733668d9ca20a78b5a281abb3abcc37f4571ad739
|
|
BLAKE2b-256 checksum How to use checksums |
f055d6bba85411cc5e26ecf6d3885dea062398793daf9d26970ea72e5071a222
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency logRelease files / cngstorytelling_mcp-2.15.0-py3-none-any.whl
| Download URL | cngstorytelling_mcp-2.15.0-py3-none-any.whl |
|---|---|
| Size | 24.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ad80461be164deb52fd63f83f7777ab6a76535772552f6614037f179105c63a9
|
|
BLAKE2b-256 checksum How to use checksums |
2c3de414192daea770184d28378ea64d51745792bf9a8afb13b940becc364c80
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency logSecurity for cngstorytelling-mcp 2.15.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for cngstorytelling_mcp-2.15.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.