@cyanheads/eia-energy-mcp-server
Enables use of Cloudflare KV, R2, or D1 as a storage backend for persistent state.
Enables tabular data spillover and SQL querying via DuckDB-powered DataCanvas for large result sets.
Provides optional OpenTelemetry tracing for observability.
Enables use of Supabase as a storage backend for persistent state.
Click on "Deploy 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., "@@cyanheads/eia-energy-mcp-serverFind electricity net generation data for California in 2022"
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.
Public Hosted Server: https://eia-energy.caseyjhand.com/mcp
Overview
US energy data from the Energy Information Administration (EIA): electricity, petroleum, natural gas, coal, and forecasts. Find datasets in plain language, query time series with facet filters, and run SQL over large results.
Tools
Tool | Description |
| Lists child routes under a path in the EIA dataset taxonomy; omit |
| Returns a leaf route's facets, valid values, data columns, frequencies, and date range. |
| Fuzzy text search across route names, descriptions, STEO and SEDS series names, and facet values. |
| Fetches data from a leaf route with facet filters, date range, and column selection; optionally stages results for SQL. |
| Lists active DataCanvas dataframes staged by |
| Runs a read-only SQL SELECT against staged DataCanvas dataframes. |
| Drops a DataCanvas dataframe, freeing its memory. |
The three eia_dataframe_* tools are callable and listed by MCP only when CANVAS_PROVIDER_TYPE=duckdb is set; eia_dataframe_drop additionally requires EIA_DATAFRAME_DROP_ENABLED=true. Disabled definitions remain in the server manifest with their enable hints. A default deployment lists the first four tools.
Related MCP server: @cyanheads/federal-reserve-mcp-server
Capability reference
Browse accepts route as an alias for path; describe and query accept path as an alias for route. Supplying both spellings is rejected. Leading, trailing, and repeated slashes are normalized.
eia_browse_routes tool
Omit
pathfor the 14 top-level categories; pass a path to browse its children.Each child carries
isLeaf: describe and query leaves, or browse categories further.A missing path returns
route_not_found; EIA rate-limiting or being unreachable returns retryablerate_limitedorupstream_unreachable.
eia_describe_route tool
Pass a leaf
routefor facets, data columns, frequencies, and date range. Each facet window is capped atEIA_FACET_VALUE_CAP(default 50); page withfacetandvalues_offset.value_countandvalues_truncateddescribe each window. A facet whose values EIA did not return is listed inunavailable_facets; the next call retries it.Errors:
route_not_found,route_not_queryable,facet_not_found, and retryablefacet_unavailable,rate_limited,upstream_unreachable.
eia_search_routes tool
Search route names, descriptions, STEO's 1,469 and SEDS's 968 series names, and facet values.
limitdefaults to 10 and is served at no more than 30 (up to 100 accepted);truncatedis true when more matches exist.Matches carry
score(0 exact, 1 no match; above 0.72 is weak) and may carry afilter_hintforeia_query_route. CheckindexCompleteandindexGapsbefore trusting a short result set.The first search builds the index and normally takes 17–30 s (at most 45 s); later calls are fast. If EIA rate-limits or cannot be reached, the call fails with retryable
rate_limitedorupstream_unreachable.
eia_query_route tool
Pass a leaf
route, with optional facet-IDfilters,columns,frequency,start/end, andsort. Page withoffsetandlength(default 100, max 5000).Responses stay within 64,000 bytes: a page may end early at the last whole row that fits, and
next_offsetgives where to continue. A single row too large to fit is withheld, and the note gives the offset that skips it.totalreports the full match count; values remain strings and units appear as{col}-units. Errors cover invalid route, facet, column, frequency, sort, or period, inverted ranges (no_data), a filter list too long for EIA's ~8 KB request URI (uri_too_long; split the values across calls), and retryablerate_limitedandupstream_unreachable.stage: truestages up toEIA_CANVAS_MAX_ROWS(default 25000) as adatasethandle for SQL viaeia_dataframe_describeandeia_dataframe_query(hyphens in column names become underscores). If staging fails,datasetis absent and the note says so.
eia_dataframe_describe tool
Omit
nameto list active staged dataframes; pass a handle to inspect one. A miss returnsfound: falsewithactive_names.Entries carry
source_tool,query_params,created_at,expires_at,row_count,truncated/max_rows, andcolumn_schema. Listing does not extend expiry.
eia_dataframe_query tool
Run one read-only SQL SELECT against staged handles.
row_limitdefaults to 1000 and caps at 10000;previewnarrows the inline slice, and the 64,000-byte per-surface budget can end it sooner.truncated: truemeanstotalRowsis a cap, not a full count.register_asstages the complete result under an unused name with an exact count; the notice gives theORDER BY … LIMIT/OFFSETquery that pages the rest.Cast EIA VARCHAR values for arithmetic. Writes, file reads, and system catalogs are rejected; declared failures include
missing_table,invalid_sql,non_select_statement,system_catalog_access, andregister_as_clash.
eia_dataframe_drop tool
Pass
nameto remove a staged dataframe; requiresEIA_DATAFRAME_DROP_ENABLED=true.Returns
dropped: falsewhen nothing matched; a failed drop returns retryablecanvas_drop_failedand the dataframe stays staged. Cleanup is optional: dataframes expire after 24 h unused.
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
EIA-specific:
Covers all 14 top-level dataset categories of EIA API v2, with the route tree cached in process
Fuzzy search (Fuse.js) over route names/descriptions, all 1,469 STEO and 968 SEDS series names, and facet values
Facet values are fetched and cached per route by
eia_describe_route; a list EIA does not return is reported inunavailable_facetsand retried on the next callRoutes whose metadata could not be fetched are reported through
eia_search_routesinstead of droppedDataCanvas (DuckDB) staging is opt-in per call; without canvas the three dataframe tools are not callable
Agent-friendly output:
Provenance —
eia_query_routeechoes the canonical route, and staged dataframes record theirsource_toolandquery_paramsCapped-window disclosure — truncated responses report the count against the cap and a
noticenaming the next callTyped failures — error
reasonvalues (e.g.route_not_queryable,invalid_facet,missing_table) carry arecoveryhint
Getting started
Public Hosted Instance
A public instance is available at https://eia-energy.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"eia-energy-mcp-server": {
"type": "streamable-http",
"url": "https://eia-energy.caseyjhand.com/mcp"
}
}
}Self-Hosted / Local
Get a free API key at api.eia.gov, then add the following to your MCP client configuration file.
{
"mcpServers": {
"eia-energy-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/eia-energy-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"EIA_API_KEY": "your-api-key"
}
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"eia-energy-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/eia-energy-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"EIA_API_KEY": "your-api-key"
}
}
}
}Or with Docker:
{
"mcpServers": {
"eia-energy-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"-e", "EIA_API_KEY=your-api-key",
"ghcr.io/cyanheads/eia-energy-mcp-server:latest"
]
}
}
}For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 EIA_API_KEY=your-key bun run start:http
# Server listens at http://localhost:3010/mcpPrerequisites
Bun v1.4.0 or higher (or Node.js v24+).
A free EIA API key from api.eia.gov. The
DEMO_KEYhits rate limits quickly; a real key is required for sustained use.
Installation
Clone the repository:
git clone https://github.com/cyanheads/eia-energy-mcp-server.gitNavigate into the directory:
cd eia-energy-mcp-serverInstall dependencies:
bun installConfigure environment:
cp .env.example .env
# edit .env and set required vars (at minimum, EIA_API_KEY)Configuration
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:
Variable | Description | Default |
| Required. Free API key from api.eia.gov — appended as | — |
| EIA API base URL. |
|
| Dataframe lifetime in seconds; each |
|
| Set to |
|
| Row ceiling for |
|
| Facet values |
|
| Set to | — |
| Transport: |
|
| HTTP server port. |
|
| HTTP endpoint path. |
|
| HTTP sessions: |
|
| Public origin override for TLS-terminating reverse-proxy deployments. | — |
| Auth mode: |
|
| Log level (RFC 5424). |
|
| Directory for log files (Node.js only). |
|
| Storage backend: |
|
| Enable OpenTelemetry instrumentation. |
|
See .env.example for the full list of optional overrides.
Running the server
Local development
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:httpRun checks and tests:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t eia-energy-mcp-server .
docker run --rm -e EIA_API_KEY=your-key -p 3010:3010 eia-energy-mcp-serverThe Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/eia-energy-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Directory | Purpose |
|
|
| Server-specific environment variable parsing and validation with Zod. |
| Tool definitions ( |
| EIA API v2 service — route tree cache, Fuse.js index, facet fan-out, HTTP client. |
| DataCanvas bridge — registers EIA query results as DuckDB dataframes, routes SQL queries. |
| Unit and integration tests mirroring |
| Design documents ( |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storageAlways call
eia_describe_routebeforeeia_query_route— facet values require a separate API fan-out and are not embedded in route metadataWrap EIA responses: validate raw → normalize to domain type → return output schema; data values are strings — never coerce silently
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
This server cannot be deployed
Maintenance
Related MCP Connectors
Query SEC EDGAR filings, XBRL financials, and company data via MCP. STDIO or Streamable HTTP.
EIA MCP — US Energy Information Administration API v2
Econdata MCP — wraps BLS (Bureau of Labor Statistics) public API v2
NREL MCP — wraps the US National Renewable Energy Laboratory developer API
Related MCP Servers
- AlicenseNot gradedqualityNot gradedmaintenanceProvides access to comprehensive U.S. and international energy data from the EIA API, including electricity, natural gas, petroleum, coal, renewables, CO2 emissions, and energy forecasts.MIT
- AlicenseNot gradedqualityAmaintenanceSearch and fetch ~800K Federal Reserve economic time-series from the FRED API via MCP, with STDIO or Streamable HTTP transport.94 npm1Apache 2.0
- AlicenseNot gradedqualityAmaintenanceExposes the FBI Crime Data Explorer API — crime estimates, agency offense rates, and LEOKA officer safety data via MCP. Supports STDIO or Streamable HTTP transport.85 npm1Apache 2.0
- FlicenseAqualityDmaintenanceAn MCP server that exposes the U.S. Energy Information Administration (EIA) Open Data API, enabling LLMs to browse and query energy data across 17 datasets with generic, composable tools.4-