cesium-mcp-runtime
English | δΈζ
MCP Server that enables AI Agents to control a Cesium globe in real-time via the Model Context Protocol.

Release channel: latest uses the stable MCP SDK v2 and supports both
MCP 2025-11-25 and 2026-07-28 from the same stdio/HTTP entry.
If you only want to try the "AI + Cesium" feel,
examples/browser-agent is the recommended
starting point β zero backend, runs in three minutes. See
Which mode should I use?.
Architecture
AI Agent <--MCP stdio--> cesium-mcp-runtime <--WebSocket--> Browser (cesium-mcp-bridge)
AI Agent <--MCP HTTP---> cesium-mcp-runtime <--WebSocket--> Browser (cesium-mcp-bridge)
The runtime acts as a bridge between MCP-compatible AI clients (Claude Desktop, VS Code Copilot, Cursor, etc.) and a browser running CesiumJS. It translates MCP tool calls into WebSocket commands that cesium-mcp-bridge executes.
The npm package ships its browser Bridge bundle locally. The built-in Viewer at http://localhost:9100/ therefore does not depend on an unpkg fallback; CesiumJS itself is still loaded from the official Cesium CDN.
For ordinary MCP users this is a one-package setup: run cesium-mcp-runtime and use the built-in Viewer. Install cesium-mcp-bridge separately only when developing a custom CesiumJS page.
Two transport modes are supported:
| Transport | Use Case | Protocol |
|---|
| stdio (default) | Local AI clients (Claude Desktop, VS Code, Cursor) | Standard I/O |
| http | Remote/cloud MCP clients (Dify, custom backends) | Streamable HTTP |
Install & Run
npx -y cesium-mcp-runtime
npm install -g cesium-mcp-runtime
cesium-mcp-runtime
Then open http://localhost:9100/ to use the built-in Viewer. No separate Bridge installation is required for this default path.
Streamable HTTP Mode
For remote/cloud MCP clients like Dify:
npx -y cesium-mcp-runtime --transport http --port 3000
Environment variable alternative:
MCP_TRANSPORT=http MCP_HTTP_PORT=3000 npx -y cesium-mcp-runtime
In HTTP mode, all 62 Cesium command tools are enabled by default (no dynamic toolset discovery needed).
MCP Client Configuration
Network access
Runtime binds to 127.0.0.1 by default, including its HTTP and WebSocket ports.
Local native MCP clients and pages served from localhost continue to work.
Pages opened directly as file:// must instead be served by a local HTTP server.
| Variable | Purpose |
|---|
CESIUM_HOST | Bind address, default 127.0.0.1. Non-loopback addresses require CESIUM_AUTH_TOKEN. |
CESIUM_AUTH_TOKEN | Shared connection secret. When set, all APIs and WebSocket connections require authentication, including local clients. |
CESIUM_ALLOWED_HOSTS | Comma-separated exact hostnames without ports, in addition to loopback and the bind address. No wildcards. |
CESIUM_ALLOWED_ORIGINS | Comma-separated exact HTTPS page origins. Loopback HTTP/HTTPS origins are allowed by default. No wildcards. |
For remote access, use HTTPS/WSS through a reverse proxy and configure the public hostname and Viewer origin explicitly. For example, set CESIUM_HOST=0.0.0.0, CESIUM_ALLOWED_HOSTS=maps.example.com, CESIUM_ALLOWED_ORIGINS=https://maps.example.com, and a generated CESIUM_AUTH_TOKEN in the server environment. Preserve the public Host header and WebSocket upgrades in the proxy.
MCP HTTP and REST clients send Authorization: Bearer <token>. The built-in Viewer asks for the connection token when authentication is enabled; it keeps the token in the page only. Custom browser bridges authenticate with WebSocket subprotocols:
const encoded = btoa(String.fromCharCode(...new TextEncoder().encode(token)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
const ws = new WebSocket('wss://maps.example.com/?session=demo', [
'cesium-mcp', `cesium-token.${encoded}`,
])
Do not put credentials in query strings. Reverse proxies must not log Authorization or Sec-WebSocket-Protocol headers. The Viewer HTML and Bridge script are public assets; protected APIs and WebSocket upgrades still require the token. Secondary local Runtime instances must use the same token to relay to an existing instance. Browser session IDs select a Viewer; they are not credentials.
Claude Desktop
{
"mcpServers": {
"cesium": {
"command": "npx",
"args": ["-y", "cesium-mcp-runtime"],
"env": {
"CESIUM_WS_PORT": "9100",
"DEFAULT_SESSION_ID": "default"
}
}
}
}
VS Code (Copilot)
In .vscode/mcp.json:
{
"servers": {
"cesium": {
"command": "npx",
"args": ["-y", "cesium-mcp-runtime"],
"env": {
"DEFAULT_SESSION_ID": "default"
}
}
}
}
Cursor
In .cursor/mcp.json:
{
"mcpServers": {
"cesium": {
"command": "npx",
"args": ["-y", "cesium-mcp-runtime"]
}
}
}
Tools are organized into 12 toolsets. By default, 4 core toolsets are enabled (30 tools). Additional toolsets can be activated via environment variable or dynamically by the AI agent at runtime. Shared titles, behavior annotations, localized descriptions, defaults, input validation, advertised output schemas, and structured results are generated from the canonical JSON Schemas in cesium-mcp-contracts. Tool calls also retain text content for older clients.
| Toolset | Tools | Default | Description |
|---|
view | 8 | Yes | Camera view controls + viewpoint bookmarks + scene export |
entity | 10 | Yes | Core entity operations + batch, query & property inspection |
layer | 9 | Yes | Layer management (GeoJSON, schema, style, basemap) |
interaction | 3 | Yes | Screenshot, highlight & measurement |
camera | 4 | β | Advanced camera controls (orbit, lookAt) |
entity-ext | 7 | β | Extended entity types (box, cylinder, wall, etc.) |
animation | 8 | β | Animation system (waypoints, clock, tracking, lighting) |
tiles | 7 | β | 3D Tiles, Gaussian Splats, terrain, imagery services, CZML & KML |
trajectory | 1 | β | Trajectory playback |
heatmap | 1 | β | Heatmap visualization |
scene | 3 | β | Scene options, post-processing & Runtime-only Ion credentials |
geolocation | 1 | β | Geocoding β convert address/place name to coordinates (Nominatim/OSM) |
{
"mcpServers": {
"cesium": {
"command": "npx",
"args": ["-y", "cesium-mcp-runtime"],
"env": {
"CESIUM_TOOLSETS": "all"
}
}
}
}
CESIUM_TOOLSETS value | Result |
|---|
| (not set) | Default 4 toolsets (30 tools + 2 meta-tools) |
view,entity,camera,animation | Only specified toolsets + 2 meta-tools |
all | All 62 command tools, no meta-tools |
When not in all mode, two meta-tools are always available so the AI can discover and activate additional capabilities on demand:
| Tool | Description |
|---|
list_toolsets | List all toolset groups with enabled status and tool names |
enable_toolset | Dynamically enable a toolset β new tools become immediately available |
View
| Tool | Description |
|---|
flyTo | Fly to coordinates (lon, lat, height, heading, pitch, roll, duration) |
setView | Set camera position instantly |
getView | Get current camera state |
zoomToExtent | Zoom to bounding box (west, south, east, north) |
Entity
| Tool | Description |
|---|
addMarker | Add a marker at coordinates |
addLabel | Add text labels to the map |
addModel | Add 3D model (glTF/GLB or Ion asset) |
addPolygon | Add polygon with styling |
addPolyline | Add polyline with styling |
updateEntity | Update entity properties |
removeEntity | Remove entity by ID |
Layer
| Tool | Description |
|---|
addGeoJsonLayer | Add GeoJSON with styling (choropleth, category, etc.) |
listLayers | List all layers |
removeLayer | Remove layer by ID |
setLayerVisibility | Toggle layer visibility |
updateLayerStyle | Change layer color/opacity/width |
setBasemap | Switch basemap |
| Tool | Description |
|---|
lookAtTransform | Orbit-style camera aim at a position (heading/pitch/range) |
startOrbit | Start orbiting the camera around current center |
stopOrbit | Stop orbit animation |
setCameraOptions | Configure camera controller (enable/disable rotation, zoom, tilt) |
| Tool | Description |
|---|
addBillboard | Add an image icon at a position |
addBox | Add a 3D box with dimensions and material |
addCorridor | Add a corridor (path with width) |
addCylinder | Add a cylinder or cone |
addEllipse | Add an ellipse (oval) |
addRectangle | Add a rectangle by geographic bounds |
addWall | Add a wall along positions |
| Tool | Description |
|---|
createAnimation | Create time-based animation with waypoints (moving entity along path) |
controlAnimation | Play or pause the current animation |
removeAnimation | Remove an animation entity |
listAnimations | List all active animations |
updateAnimationPath | Update animation path visual properties |
trackEntity | Follow an entity with the camera |
controlClock | Configure Cesium clock (time range, speed, animation state) |
setGlobeLighting | Enable/disable globe lighting and atmospheric effects |
| Tool | Description |
|---|
load3dTiles | Load 3D Tiles from URL or Ion asset ID |
loadTerrain | Set terrain provider |
loadImageryService | Add imagery service (WMS/WMTS/XYZ/Ion) |
| Tool | Description |
|---|
screenshot | Capture map as base64 PNG |
highlight | Highlight layer features |
Other
| Tool | Toolset | Description |
|---|
playTrajectory | trajectory | Animate entity along coordinate path |
addHeatmap | heatmap | Generate heatmap from point data |
MCP Resources
| URI | Description |
|---|
cesium://scene/camera | Current camera position, heading, pitch, roll |
cesium://scene/layers | List of all loaded layers with types and visibility |
Environment Variables
| Variable | Default | Description |
|---|
CESIUM_WS_PORT | 9100 | WebSocket server port |
DEFAULT_SESSION_ID | default | Preferred browser session for MCP tool routing |
CESIUM_TOOLSETS | (not set) | Toolset activation: omit for defaults, all for everything, or comma-separated list |
CESIUM_LOCALE | en | Tool description language: en (English, default) or zh-CN (Chinese) |
MCP_TRANSPORT | stdio | MCP transport mode: stdio or http |
MCP_HTTP_PORT | (auto) | HTTP port for Streamable HTTP mode (default: CESIUM_WS_PORT + 100) |
Browser-Side Setup
Your browser page needs to connect to the runtime via WebSocket and relay commands to cesium-mcp-bridge:
import { CesiumBridge } from 'cesium-mcp-bridge'
const bridge = new CesiumBridge(viewer)
const ws = new WebSocket('ws://localhost:9100?session=default')
ws.onmessage = async (event) => {
const { id, method, params } = JSON.parse(event.data)
try {
const result = await bridge.execute({ action: method, params })
ws.send(JSON.stringify({ id, result }))
} catch (error) {
ws.send(JSON.stringify({ id, error: { message: String(error) } }))
}
}
Session Routing
Multiple browser tabs can connect to a single runtime using different session IDs:
Tab A: ws://localhost:9100?session=geoagent
Tab B: ws://localhost:9100?session=demo
Routing via MCP URL (recommended for Dify / third-party integrations)
Add ?session=xxx to the MCP HTTP endpoint URL:
http://localhost:3216/mcp?session=geoagent
All tool calls from that connection are automatically routed to the matching browser β no need to inject sessionId into prompts or tool parameters.
Routing priority
sessionId in tool parameters (explicit per-call override)
?session=xxx in MCP HTTP URL (connection-level)
DEFAULT_SESSION_ID environment variable
- First connected browser (fallback)
Explicit routing is fail-closed: when a tool parameter or MCP URL names a
session that is missing or disconnected, the call returns an error instead of
running against another Viewer. The default/first-connected fallback applies
only when the caller did not explicitly select a session. Pending responses are
also accepted only from the browser that received the command, and are rejected
immediately if that browser disconnects.
HTTP Push API
The runtime also exposes an HTTP endpoint for non-MCP integrations (e.g., FastAPI backend):
curl -X POST http://localhost:9100/push \
-H "Content-Type: application/json" \
-d '{"sessionId": "default", "command": {"action": "flyTo", "params": {"longitude": 116.39, "latitude": 39.91}}}'
Compatibility
| Channel | Runtime | Bridge | MCP protocol | Cesium |
|---|
latest | current stable | matching stable | 2025-11-25 + 2026-07-28 | ~1.145.0 |
The stable release serves both protocol generations from the same stdio/HTTP
entry using @modelcontextprotocol/server and
@modelcontextprotocol/node 2.0.0 packages.
The repository pins the official conformance runner separately and validates
the 2026-07-28 server-stateless scenario with:
npm run test:conformance:mcp
Conformance-only diagnostic tools are enabled only for that command. They are
not registered by normal stdio, HTTP, or browser-demo runtime startup.
License
MIT