cyanheads avatar

Eia Energy Mcp Server

cyanheads/eia-energy-mcp-server

Connects Claude to the U.S. Energy Information Administration's v2 API with seven tools covering the full query workflow. Browse the 14 top-level dataset categories (electricity, petroleum, natural gas, coal, forecasts), search 1,469 STEO series by fuzzy text, describe route schemas with facet vocabularies, then pull filtered data by state, sector, or date range. Query results spill to DuckDB tables when they exceed page limits, so you can run SQL over large datasets. Handles the EIA's string-formatted numerics and per-row unit fields. Useful when you need structured energy data for analysis, dashboards, or policy research without manually navigating the API docs.

GitHub stars
3
tools
6
auth
Required
transport
STDIO, HTTP
env vars
14
last updated
Nov 4, 2026

Install

From registry metadata
$ npx add-mcp https://eia-energy.caseyjhand.com/mcp --name eia-energy

Run in your terminal. add-mcp asks which agents to add it to (Claude Code, Codex, Cursor and more). Add -g to install it for every project.

Review the command, arguments and environment values before installing. MCP servers run with your local permissions.

Other ways

Claude Code

$ claude mcp add --transport http eia-energy https://eia-energy.caseyjhand.com/mcp

Run in your terminal. Add --scope user to make it available in every project.

Tools

Verified live · 6 tools

Verified live against the running server on Nov 6, 2026.

eia_browse_routesLists child routes under a given path in the EIA dataset taxonomy. Start with no path to get the 14 top-level categories (electricity, petroleum, natural-gas, steo, aeo, ieo, seds, etc.), then drill into subcategories. Each result includes an isLeaf flag — leaf routes are quer...1 params

Lists child routes under a given path in the EIA dataset taxonomy. Start with no path to get the 14 top-level categories (electricity, petroleum, natural-gas, steo, aeo, ieo, seds, etc.), then drill into subcategories. Each result includes an isLeaf flag — leaf routes are quer...

Parameters* required
pathstring
Route path to browse (e.g. "electricity", "petroleum/pri"). Omit for root. Whitespace and slashes are normalized, then one complete leading v2 segment is removed: "/v2/electricity/retail-sales/" re...
eia_describe_routeReturns metadata for a leaf route: available facets with their valid values, data column names and units, frequency options, and date range. Call this before eia_query_route to discover valid facet IDs, facet values, column IDs, and frequency codes. Each facet returns a capped...4 params

Returns metadata for a leaf route: available facets with their valid values, data column names and units, frequency options, and date range. Call this before eia_query_route to discover valid facet IDs, facet values, column IDs, and frequency codes. Each facet returns a capped...

Parameters* required
facetstring
Restrict the response to one facet by ID (e.g. "stateid"). Use with values_offset to page a facet whose values were truncated, or with values_query to find a value in it. Omit to get every facet.
route*string
Leaf route path (e.g. "electricity/retail-sales", "steo"). Discoverable via eia_browse_routes or eia_search_routes. Whitespace and slashes are normalized, then one complete leading v2 segment is re...
values_offsetinteger
Index of the first facet value to return, applied to every facet in the response. Use the value named in a truncation hint to continue past the cap. With values_query, indexes the matching values.default: 0
values_querystring
Keep only the facet values whose id, name, or alias contains this text, ignoring case (e.g. "palo verde" on plantCode). On the balancing-authority facets of electricity routes (respondent, fromba,...
eia_search_routesFuzzy text search across route names, descriptions, category labels, and the names of the data columns a route publishes. Resolves natural-language queries like "electricity retail sales by state" or "natural gas imports" to matching route paths, and a measure named only by it...2 params

Fuzzy text search across route names, descriptions, category labels, and the names of the data columns a route publishes. Resolves natural-language queries like "electricity retail sales by state" or "natural gas imports" to matching route paths, and a measure named only by it...

Parameters* required
limitnumber
Maximum results to return. Default 10; a larger value returns at most 30 and says so. truncated says whether more matches exist.default: 10
query*string
Free-text search terms to match against route names and descriptions, or a legacy APIv1 series ID (e.g. "PET.RWTC.W": three or more dot-separated segments ending in a frequency code A, Q, M, W, D,...
eia_query_routeFetches data from a leaf route with optional facet filters, date range, frequency, and column selection. Use eia_describe_route first to discover valid facet IDs, facet values, column IDs, and frequency codes. Data values are strings in the response (EIA API returns all numeri...10 params

Fetches data from a leaf route with optional facet filters, date range, frequency, and column selection. Use eia_describe_route first to discover valid facet IDs, facet values, column IDs, and frequency codes. Data values are strings in the response (EIA API returns all numeri...

Parameters* required
columnsarray
Data column IDs to return (reduces payload). Defaults to all. IDs discoverable via eia_describe_route data_columns[].id. Every row also carries period and each facet ID whatever this lists, so nami...
endstring
Period end, read the same way as start: a coarser end selects only its first period, so "2020" ends at 2020-01 at monthly — use "2020-12" to include the whole year. At hourly a date-only end covers...
filtersobject
Facet filters keyed by facet ID (e.g. { "stateid": "TX", "sectorid": ["RES", "COM"] }). Use the facets[].id values returned by eia_describe_route as keys here. Every value travels in the request UR...
frequencystring
Aggregation frequency ID (e.g. "monthly", "annual"). Defaults to route default. Valid IDs from eia_describe_route.
lengthnumber
Rows per page. Default 25; a larger value returns at most 5,000 and says so. With stage: true, staging is not bounded by this — it pages past the page on its own.default: 25
offsetinteger
Row offset into the matching set (default 0). An offset at or beyond total returns zero rows.default: 0
route*string
Leaf route path (e.g. "electricity/retail-sales", "steo"). Discoverable via eia_browse_routes or eia_search_routes. Whitespace and slashes are normalized, then one complete leading v2 segment is re...
sortarray
Result ordering.
stageboolean
Stage the matching rows as a DataCanvas table for SQL (default false). Off, the call makes one upstream request and returns the preview alone. On, the service pages past the preview up to the stagi...default: false
startstring
Period start in the route date format (e.g. "2020-01" for monthly, "2020" for annual). Format from eia_describe_route. EIA reads a bound as the period of the effective frequency containing its firs...
eia_dataframe_describeList canvas dataframes (df_<id>) materialized by eia_query_route calls that passed stage: true, with provenance, expiry, row count, and column schema. Nothing is staged until such a call runs, so an empty list on a fresh session means no query has staged yet, not that staging...1 params

List canvas dataframes (df_<id>) materialized by eia_query_route calls that passed stage: true, with provenance, expiry, row count, and column schema. Nothing is staged until such a call runs, so an empty list on a fresh session means no query has staged yet, not that staging...

Parameters* required
namestring
df_<id> handle to describe a single dataframe. Omit to list all active dataframes.
eia_dataframe_queryRun a single-statement SELECT against canvas dataframes registered by eia_query_route calls that passed stage: true — a query that staged nothing leaves no table to select from. Standard DuckDB SQL — joins, aggregates, window functions, CTEs all supported. Reference dataframes...4 params

Run a single-statement SELECT against canvas dataframes registered by eia_query_route calls that passed stage: true — a query that staged nothing leaves no table to select from. Standard DuckDB SQL — joins, aggregates, window functions, CTEs all supported. Reference dataframes...

Parameters* required
previewnumber
Rows to include in the immediate response. Default 25; a larger value returns at most row_limit and says so. 0 returns none, useful when chaining via register_as.
register_asstring
When set, persist the result as a new dataframe with a fresh expiry. Use to chain analyses without re-running upstream queries. The name must be unused — reusing a staged name is rejected, and the...
row_limitnumber
Hard cap on rows materialized. Default 1,000; a larger value returns at most 10,000 and says so. Rows past the cap are dropped without being counted — the response then carries truncated: true and...default: 1000
sql*string
Single-statement SELECT against df_<id> tables. EIA data columns are VARCHAR — use CAST(col AS DOUBLE) for arithmetic. Example: SELECT period, CAST(value AS DOUBLE) AS val FROM df_XXXXX ORDER BY pe...

Sponsors

Configuration

EIA_API_KEY*

Free API key from api.eia.gov. Required — all requests use this as the api_key query parameter.

EIA_DATASET_TTL_SECONDSdefault: 86400

Sliding per-dataframe TTL in seconds, extended by every query that references the dataframe. At most 31536000 (365 days).

EIA_DATAFRAME_DROP_ENABLEDdefault: false

Set to 'true' to expose eia_dataframe_drop for manual canvas cleanup. Has no effect with CANVAS_PROVIDER_TYPE=none.

EIA_CANVAS_MAX_ROWSdefault: 25000

Cumulative row ceiling for eia_query_route DataCanvas staging on a stage: true call. Five requests at EIA's 5000-row-per-request ceiling. At most 250000.

EIA_FACET_VALUE_CAPdefault: 50

Facet values eia_describe_route returns per facet before truncating. Page past it with the tool's facet and values_offset inputs, or narrow a facet with values_query. At most 1000.

EIA_CLAMP_LIMITSdefault: true

Lower an over-cap eia_query_route length, eia_dataframe_query row_limit or preview, or eia_search_routes limit to its cap with a notice. 'false' advertises and enforces each cap as a schema maximum instead.

CANVAS_PROVIDER_TYPEdefault: duckdb

DataCanvas provider. 'duckdb', the default, registers eia_dataframe_describe and eia_dataframe_query and lets eia_query_route stage rows when called with stage: true; eia_dataframe_drop also requires EIA_DATAFRAME_DROP_ENABLED=true. 'none' disables DataCanvas.

MCP_LOG_LEVELdefault: info

Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').

MCP_TRANSPORT_TYPEdefault: http

Selects the HTTP transport.

MCP_HTTP_HOSTdefault: 127.0.0.1

The hostname for the HTTP server.

MCP_HTTP_PORTdefault: 3010

The port to run the HTTP server on.

MCP_HTTP_ENDPOINT_PATHdefault: /mcp

The endpoint path for the MCP server.

MCP_PUBLIC_URL

Public origin override for deployments behind a TLS-terminating reverse proxy (e.g. https://mcp.example.com).

MCP_AUTH_MODEdefault: none

Authentication mode to use: 'none', 'jwt', or 'oauth'.

Readme

@cyanheads/eia-energy-mcp-server

Browse and query the U.S. Energy Information Administration API v2 — electricity, petroleum, natural gas, coal, forecasts, and more via MCP. STDIO or Streamable HTTP.

4 core tools + 3 DataCanvas tools

Details

Repository
github.com/cyanheads/eia-energy-mcp-server
Package
@cyanheads/eia-energy-mcp-server
Transport
STDIO, HTTP
Auth
Required
Registry
MCP registry, active
Resources
1
Tools verified
Nov 6, 2026

More from cyanheads