veda-mcp-app
veda-mcp-app
MCP App for the VEDA STAC catalog: tools that render interactive widgets (collection picker, raster map) inline in Claude or ChatGPT.
ARCHITECTURE.md — MCP concepts and how this repo maps onto them
CONTEXT.md — domain glossary
Tools
search_collections(query?, limit?)— search/list collections; renders the picker, clicking a card announces the pick in the chat.show_map(collectionId, datetime)— single-layer raster map over a date range (YYYY-MM-DDorYYYY-MM-DD/YYYY-MM-DD, clamped to the collection's temporal extent). Non-mappable collections are rejected with a corrective error.compare_map(leftCollectionId, leftDatetime, rightCollectionId, rightDatetime)— swipe-compare; same collection twice = before/after.run_demo()— map ofno2-monthly-difffor 2020-2021. Ask the host to "run a demo of the VEDA MCP app".
Quick start
npm install # auto-builds dist/ (prepare script)
npm run setup:claude # register with Claude Desktop + Claude CodeRestart Claude Desktop, then ask it to "run a demo of the VEDA MCP app".
Local development
Prerequisites: Node 22. No credentials — the server reads the public VEDA
catalog (https://dev.openveda.cloud/api/stac, override with VEDA_STAC_ROOT).
npm start # build + serve over HTTP (http://localhost:3001/mcp)
npm run serve:stdio # stdio from source (Claude Desktop / Claude Code)
npm run dev # watch UI bundles + restart server on change
npm test # unit tests (vitest)
npm run build # typecheck + UI bundles + server -> dist/To run the compiled output exactly as production does:
npm run build, then npm run start:prod.
To verify the widgets end-to-end without Claude, use basic-host (the
reference host in the ext-apps repo,
examples/basic-host): it expects this server at http://localhost:3001/mcp
and renders the widgets in a sandboxed iframe with debug panels.
Deployment (Heroku)
HTTP-first: POST /mcp (Streamable HTTP, stateless) + GET /health. Needs a
long-lived process — not serverless. Procfile runs npm run start:prod;
engines.node: 22.x pins the runtime.
heroku create <app-name>
heroku config:set MCP_PATH_TOKEN=$(openssl rand -hex 16)
git push heroku mainUse a Basic dyno (Eco dynos sleep; a cold start mid-demo takes ~10-30 s).
Env vars (all optional):
MCP_PATH_TOKEN— shared-secret path segment: endpoint moves to/mcp/<token>, bare/mcp404s. Letters/digits/-/_only. Recommended for any public deploy.VEDA_STAC_ROOT/VEDA_RASTER_ROOT— catalog/titiler roots.
Verify: curl https://<app-name>.herokuapp.com/health →
{"status":"ok","transport":"http"}. The connector URL is
https://<app-name>.herokuapp.com/mcp/<token>.
Connecting
claude.ai / Claude Desktop: Settings → Connectors → Add custom connector → paste the connector URL. No auth (the token in the URL is the gate). Widgets render inline.
Claude Code:
claude mcp add --transport http veda https://<app-name>.herokuapp.com/mcp/<token>ChatGPT: Settings → Connectors → Create new connector → MCP server URL = the connector URL, auth: none.
Troubleshooting
502 after deploy —
heroku logs --tail; if theVEDA MCP App (HTTP transport)banner is absent, the process crashed at boot (config validation errors print the reason).404 on
/mcp— expected whenMCP_PATH_TOKENis set; use/mcp/<token>.First request hangs ~30 s — Eco dyno waking. Upgrade to Basic.
HTTPS required — Claude and ChatGPT only connect to
https://endpoints.Tool answers "cannot be mapped" / "unknown collection" — corrective by design; the model retries with a valid collection.
Scripts
npm run setup:claude— register with local Claude hosts (idempotent). Flags:--print,--remove,--desktop-only,--code-only.npm test/npm run build/npm start/npm run dev— see above.