opendata-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@opendata-mcpfind datasets about air quality in New York"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
opendata-mcp
A Model Context Protocol server for the OpenData Platform API. Tools are generated dynamically from the bundled OpenAPI 3.1 spec — every endpoint is exposed as an MCP tool with a typed input schema and a transparent HTTP handler.
GET endpoints: 76 — exposed without auth (the API serves them unauthenticated).
Write endpoints (POST / PUT / PATCH / DELETE): 23 — require a Bearer token via
OPENDATA_API_KEY.Built on
@modelcontextprotocol/sdk(TypeScript) with stdio transport.
Install
Uses pnpm (pinned via packageManager in package.json so corepack enable is enough to get the right version).
pnpm install
pnpm run buildConfigure
Copy .env.example → .env (or set in your MCP client config) and fill in:
OPENDATA_BASE_URL=https://api.tryopendata.ai # required at call time
OPENDATA_API_KEY=od_live_xxx # required for writes
# OPENDATA_READ_ONLY=true # optional: only register GET tools
# OPENDATA_TIMEOUT_MS=30000 # optional: per-request timeout
# OPENDATA_MAX_ATTEMPTS=3 # optional: total HTTP attempts (retries are bounded; see below)
# OPENDATA_LOG_LEVEL=info # optional: off|error|info|debugSecrets are never read from the repo. .env is gitignored; .env.example ships placeholders only.
Run
# Dev (tsx, no build step)
pnpm run dev
# Production (after build)
pnpm startThe server speaks MCP over stdio — wire it into any MCP-capable client. Example client config (Claude Desktop / similar):
{
"mcpServers": {
"opendata": {
"command": "node",
"args": ["/absolute/path/to/opendata-mcp/dist/index.js"],
"env": {
"OPENDATA_BASE_URL": "https://api.tryopendata.ai",
"OPENDATA_API_KEY": "od_live_xxx"
}
}
}
}Test
pnpm test # unit tests (mocked fetch — offline-safe)
pnpm run typecheck # tsc --noEmitLive tests against the real API run only when OPENDATA_BASE_URL is set:
OPENDATA_BASE_URL=https://api.tryopendata.ai pnpm testCI runs the unit suite on every push/PR (badge above). The live smoke job runs on a daily schedule (and on pushes to main) only if the repo has OPENDATA_BASE_URL (and optionally OPENDATA_API_KEY) configured as Actions secrets — it's continue-on-error: true so a transient upstream outage doesn't show the repo as red.
How tool generation works
At startup the server:
Loads
openapi.json(OpenAPI 3.1, bundled).Walks every
(path, method)pair (skippingdeprecatedoperations and skipping non-GET whenOPENDATA_READ_ONLY=true).Converts each operation's path + query parameters (and JSON request body for writes) into a Zod input schema via
openapi-to-zod.ts.Registers one MCP tool per operation. The tool name is the OpenAPI
operationId(sanitized to[a-zA-Z0-9_-]{1,64}); the description isMETHOD path (auth?) — summary — description.On invoke, builds the URL (substituting path params + appending the query string), attaches
Authorization: Bearer ${OPENDATA_API_KEY}for non-GET, sends the request, and returns the response as a text MCPcontentblock.
The auth contract is enforced at the client layer (src/api-client.ts):
GET → no auth header is sent. If you pass a key it's still ignored.
Non-GET →
OPENDATA_API_KEYis required; the request fails fast with a clear error if it's missing.
Logging, retries, and shutdown
Structured logging to stderr (stdout is reserved for the MCP protocol). One JSON object per line:
{ts, level, msg, ...fields}. Tuned viaOPENDATA_LOG_LEVEL(off|error|info|debug, defaultinfo). Every tool invocation carries a shortrid(request id) that also surfaces in any error message returned to the client — so a user can quote anERROR (rid=…)and you can grep it in logs.Bounded retries on transient failures only:
502 / 503 / 504and network errors are retried with jittered exponential backoff (200ms → 600ms → 1.4s, capped).500and any4xxare never retried — a 500 means "I tried, it broke" and retrying just hammers a server that already gave its answer; a 4xx means the request is wrong and retrying won't help. Total attempts viaOPENDATA_MAX_ATTEMPTS(default 3).Graceful shutdown on
SIGINT/SIGTERM: the MCP transport is closed beforeprocess.exitso any in-flight tool calls have a chance to land.
Layout
src/
index.ts # entry — MCP server, stdio transport
openapi-loader.ts # loads + normalizes the bundled spec
openapi-to-zod.ts # OpenAPI schema → Zod schema converter
api-client.ts # fetch wrapper + auth contract
tools.ts # generates MCP tool defs from normalized ops
__tests__/
tools.test.ts # unit tests (mocked fetch)
live.test.ts # live tests (skipped unless OPENDATA_BASE_URL set)
openapi.json # bundled OpenAPI 3.1 specLicense
MIT
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Tools
- add_comment_v1_requests__request_id__comments_postC
- approve_request_v1_requests__request_id__approve_postA
- check_slug_availability_v1_users__user_id__views_check_slug_getA
- compose_download_csv_v1_datasets__provider___dataset__compose_doA
- compose_preview_v1_datasets__provider___dataset__compose_previewA
- create_and_publish_view_v1_user_views_create_and_publish_postA
- create_draft_figure_v1_figures_drafts_postA
- create_view_v1_user_views_postA
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Skeego/opendata-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server