Install
$ agentstack add mcp-cesiumgs-cesiumjs-ai-starter-app ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
CesiumJS AI Sample App
A ready-to-run starter pairing a CesiumJS 3D globe with an LLM-powered chat interface. The LLM drives the globe through structured tool calls (e.g. "fly to Paris"_) while the LLM API key never reaches the browser — all inference runs behind a Node.js API server.
[Getting Started](docs/getting-started.md) · [Architecture](docs/architectures/architecture.md) · [Packages](docs/packages/index.md) · [Viewer Tools Tutorial](docs/tutorials/cesium-viewer-tools-tutorial.md)
Get Started
You need an LLM API key from OpenAI, Anthropic, or Google Generative AI to enable chat. A free Cesium Ion token is optional but improves terrain and imagery.
npx degit CesiumGS/cesiumjs-ai-starter-app cesiumjs-ai-starter-app
cd cesiumjs-ai-starter-app
cp .env.example .env
Open .env and set AI_PROVIDER with its matching API key (e.g. OPENAI_API_KEY). Optionally set VITE_CESIUM_ION_ACCESS_TOKEN.
Option A — Docker (recommended)
Requires Docker Desktop only — no local Node.js needed.
docker compose up --build --wait
Open http://localhost:8080 once both containers report healthy.
Option B — Local dev (hot reload)
Requires Node.js ≥ 20 and npm ≥ 9.
npm install
npm run dev
- Globe + HMR: http://localhost:5173
- Chat API:
http://localhost:3001
Try It Out
Type a place into the chat panel — e.g. fly to Paris — and the camera flies there. Any city, landmark, or address works.
For requests that don't fit a single fly-to, try something like drop a pin at the Eiffel Tower — this routes through executeCesiumCode instead, which is gated behind AI SDK's native tool-approval mechanism (toolApproval configured in backend/src/app.ts — see backend/src/tools/execute-cesium-code-tool.ts): the chat panel shows you the assistant's raw intent for the call and waits for you to approve or reject it (a human-in-the-loop checkpoint — see frontend/src/components/ChatPanel.tsx's onApprovalRequired handler) before any code is generated. After approval, the backend generates and statically verifies a CesiumJS snippet; the frontend then executes it in a fresh QuickJS-WASM sandbox with memory/deadline limits and a guarded bridge to the live Viewer.
If no provider key is configured, the globe still runs as a plain viewer with a "AI is not configured. Add a supported provider API key to your .env file." banner.
Architecture
Browser Server
┌─────────────────────────┐ ┌────────────────────────────┐
│ Vite SPA │ │ Node.js API │
│ ├─ CesiumJS Viewer │◄────►│ ├─ /api/chat │
│ └─ Chat Panel │ SSE │ ├─ Agent loop (streamText) │
│ └─ onToolCall ──────┼─────►│ └─ Tool registry │
└─────────────────────────┘ └────────────────────────────┘
▲ │
│ Viewer tool results │ LLM API key (server only)
└───────────────────────────────────┘
Viewer tools (camera, entities) are streamed via Server-Sent Events to the browser and executed against the live Viewer. The workspace packages provide the reusable pieces:
| Package | Role | | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [@cesium-ai/server](packages/server/) | Express router — mounts POST /api/chat, runs the streamText agent loop | | [@cesium-ai/tools-schemas](packages/tools-schemas/) | Zod-schemed viewer tool definitions (flyTo, entities, imagery, …) — schemas only, no execute | | [@cesium-ai/codegen-cesium](packages/codegen-cesium/) | Intent → AST-verified CesiumJS code pipeline; owns the executeCesiumCode tool definition | | [@cesium-ai/codegen-sandbox](packages/codegen-sandbox/) | QuickJS + WASM runtime isolation for executing verified CesiumJS snippets in the browser | | [@cesium-ai/mcp-tools](packages/mcp-tools/) | Optional Model Context Protocol client bridge that exposes allowlisted MCP tools to the agent | | [@cesium-ai/chat-element](packages/chat-element/) | Reusable React chat panel component that renders streamed assistant/tool activity and approval UX | | [@cesium-ai/sample-config](shared/) | App-level tool allowlist and shared flyTo args contract |
@cesium-ai/server— an Express router that mounts the AI SDK chat key-layer (/api/chat). It accepts a tool registry and a resolved language model and runs thestreamTextagent loop server-side, so the LLM API key never reaches the browser. The host app owns provider selection.@cesium-ai/tools-schemas— Zod-schemed CesiumJS viewer tool definitions (flyTo, …). Schemas only, noexecute, and scoped strictly to tools that run directly against a liveViewer.@cesium-ai/tools— default, ready-to-use client-side executors for every tool in@cesium-ai/tools-schemas's catalogue (flyTo, camera, entity, animation, and imagery tools) — the browser-side "other half" of that schema-only package, so a host app doesn't have to hand-write an executor for every tool before it can turn one on.createCesiumToolExecutors({ ... })lets a host override or extend any individual tool (e.g. this app's ownflyTo, which validates against an extended shape — see below) without forking the rest. See [packages/tools/README.md](packages/tools/README.md).@cesium-ai/codegen-cesium— backend-only pipeline that turnsexecuteCesiumCode's natural-languageintentinto statically-verified CesiumJS code (skills-grounded generation + an AST verifier), and also ownsexecuteCesiumCode's tool definition itself (schema-only, noexecute) — that tool can't run directly against aViewerlikeflyTodoes, so it lives here rather than intools-schemas. Parse-only — it never executes generated code itself.@cesium-ai/codegen-sandbox— frontend-only QuickJS-WASM execution sandbox used to run verified generated CesiumJS snippets under strict memory/time limits and a guarded bridge to the liveViewer.@cesium-ai/mcp-tools— optional, server-only Model Context Protocol client bridge. Connects to MCP servers (SSE/HTTP — stdio is deliberately unsupported), namespaces + allowlist-filters their tools, and merges them into an AI SDKToolSeta host app spreads alongsidecreateCesiumTools()— this is the "MCP-backed tool group" the split-execution diagram above refers to. Entirely opt-in through anmcp.config.jsonfile, with no MCP client created when the file is absent. See [packages/mcp-tools/README.md](packages/mcp-tools/README.md) for the full security model and API.@cesium-ai/chat-element— reusable React chat UI package consumed by the frontend app, including tool event rendering and inline approval UI used for protected tool calls.
This app builds its own executable executeCesiumCode tool on top of the library's schema (backend/src/tools/execute-cesium-code-tool.ts, wrapping @cesium-ai/codegen-cesium), the same "app extends the shared schema" pattern flyTo uses via backend/src/tools/flyto-tool.ts. Because executeCesiumCode is a "Code Mode" tool — the model's output is arbitrary generated code, not bounded typed args like flyTo's lat/lon/altitude — it needs a materially different security posture than flyTo. The backend's AST verification (see [packages/codegen-cesium/README.md](packages/codegen-cesium/README.md)) is defense-in-depth only, not a substitute for runtime isolation; the frontend independently executes verified snippets through @cesium-ai/codegen-sandbox, a fresh QuickJS-WASM interpreter with memory/deadline limits and a guarded host bridge. See [packages/tools-schemas/README.md](packages/tools-schemas/README.md) and [packages/codegen-cesium/README.md](packages/codegen-cesium/README.md) for the full generation/verification pipeline.
See Architecture for more detail.
Working with Cesium Tools
Enable or disable a tool: edit ENABLED_CESIUM_TOOLS in [shared/src/enabled-tools.ts](shared/src/enabled-tools.ts). Both the backend registry and frontend executor map derive from this array — a typo fails to build, and enabling a tool without a client-side executor also fails to compile.
Update a tool's schema: structural args rules live in flyToInputShape (both tiers derive from it); model-facing descriptions live in flyTo.ts backend-only and are never bundled into the client.
See the Cesium Viewer Tools Tutorial for the full step-by-step walkthrough.
Enabling MCP tools
MCP tools are a separate, opt-in tool group — see [@cesium-ai/mcp-tools](packages/mcp-tools/README.md) for the full API and security model. Nothing below is required for the app to run; without an mcp.config.json file, no MCP client is ever created.
List servers in a dedicated mcp.config.json file at the repo root (see [mcp.config.json.example](mcp.config.json.example)). It is a plain JSON array, easier to read and edit than an inline environment value, and keeps server configuration out of shell history:
[
{
"name": "docs",
"transport": { "type": "http", "url": "https://example.com/mcp" },
"allowedTools": ["search"]
},
{ "name": "ion", "transport": { "type": "http", "url": "http://localhost:3000/mcp/" } }
]
There's no manual "does this need OAuth" flag to set. backend/src/index.ts attempts every configured server the same way at startup ([createMcpTools](packages/mcp-tools/README.md)):
- Connects successfully (e.g. the
docsserver above, using a static header/API key or no auth at all) — shared by every visitor from then on. Tools are namespacedmcp____and merged into the same registryflyTo/executeCesiumCodelive in ([backend/src/app.ts](backend/src/app.ts)) — every MCP tool is approval-gated by default (toolApproval: "user-approval"), the same human-in-the-loop checkpointexecuteCesiumCodeuses, since MCP tools run arbitrary third-party server code this app doesn't control. - Fails with a 401 (e.g. the
ionserver above) — auto-detected as needing per-user authentication, and automatically offered through the chat panel's interactive Connect flow instead: credentials and MCP clients are scoped to the browser session, kept in backend memory only, and discarded on disconnect or restart. See the mcp-tools README's [session-scoped OAuth](packages/mcp-tools/README.md#session-scoped-oauth) section. - Fails any other way (network unreachable, bad URL, etc.) — recorded as a genuine connection failure (surfaced on
GET /healthasmcpServers) and never prevents the rest of the app from starting.
The full resolved tool registry for a given request — including any connected MCP tools, which aren't knowable statically at build time — can be inspected via GET /api/tools (rate-limited the same as /api/chat); the frontend's ChatPanel shows this list in a small "Tools (N)" disclosure so it's visible which tools (built-in and MCP) are actually available in a running instance.
If a connected server's tool declares an "MCP Apps" ui:// widget resource (e.g. an interactive asset-import launcher), GET /api/tools reports it via that tool's mcpApp field and the chat panel renders it inline in a sandboxed iframe (packages/chat-element/src/McpAppWidget.tsx) — including a bridge that lets the widget call tools back on its own server, gated behind an explicit inline Approve/Reject prompt. See the mcp-tools README's [MCP Apps widgets](packages/mcp-tools/README.md#mcp-apps-widgets) section for the full architecture.
Environment Variables
| Variable | Required | Description | | -------------------------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | VITE_CESIUM_ION_ACCESS_TOKEN | Yes | Cesium Ion token — baked into the client bundle at build time. Intentionally client-visible; scope it in the Ion console to restrict allowed assets and HTTP referrers. | | VITE_CESIUM_ION_SERVER_URL | No | Cesium ion API server the token above was issued by. Only needed for a token from a non-production ion server (e.g. an internal or staging ion environment) — leave unset for a normal ion.cesium.com token. A mismatched/missing value here causes every asset request to 401 against the default production server. | | OPENAI_API_KEY | When chat enabled | LLM API key — server-side only, never VITE_ prefixed. Required when AI_PROVIDER=openai. | | ANTHROPIC_API_KEY | When chat enabled | Required when AI_PROVIDER=anthropic. | | GOOGLE_GENERATIVE_AI_API_KEY | When chat enabled | Required when AI_PROVIDER=google. | | AI_PROVIDER | No | openai (default) \| anthropic \| google
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: CesiumGS
- Source: CesiumGS/cesiumjs-ai-starter-app
- License: Apache-2.0
- Homepage: https://cesiumgs.github.io/cesiumjs-ai-starter-app/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.