Skip to main content
Glama
cyanheads

@cyanheads/eia-energy-mcp-server

by cyanheads

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework

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

eia_browse_routes

Lists child routes under a path in the EIA dataset taxonomy; omit path for the 14 top-level categories.

eia_describe_route

Returns a leaf route's facets, valid values, data columns, frequencies, and date range.

eia_search_routes

Fuzzy text search across route names, descriptions, STEO and SEDS series names, and facet values.

eia_query_route

Fetches data from a leaf route with facet filters, date range, and column selection; optionally stages results for SQL.

eia_dataframe_describe

Lists active DataCanvas dataframes staged by eia_query_route, with schema and provenance.

eia_dataframe_query

Runs a read-only SQL SELECT against staged DataCanvas dataframes.

eia_dataframe_drop

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 path for 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 retryable rate_limited or upstream_unreachable.


eia_describe_route tool

  • Pass a leaf route for facets, data columns, frequencies, and date range. Each facet window is capped at EIA_FACET_VALUE_CAP (default 50); page with facet and values_offset.

  • value_count and values_truncated describe each window. A facet whose values EIA did not return is listed in unavailable_facets; the next call retries it.

  • Errors: route_not_found, route_not_queryable, facet_not_found, and retryable facet_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. limit defaults to 10 and is served at no more than 30 (up to 100 accepted); truncated is true when more matches exist.

  • Matches carry score (0 exact, 1 no match; above 0.72 is weak) and may carry a filter_hint for eia_query_route. Check indexComplete and indexGaps before 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_limited or upstream_unreachable.


eia_query_route tool

  • Pass a leaf route, with optional facet-ID filters, columns, frequency, start/end, and sort. Page with offset and length (default 100, max 5000).

  • Responses stay within 64,000 bytes: a page may end early at the last whole row that fits, and next_offset gives where to continue. A single row too large to fit is withheld, and the note gives the offset that skips it.

  • total reports 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 retryable rate_limited and upstream_unreachable.

  • stage: true stages up to EIA_CANVAS_MAX_ROWS (default 25000) as a dataset handle for SQL via eia_dataframe_describe and eia_dataframe_query (hyphens in column names become underscores). If staging fails, dataset is absent and the note says so.


eia_dataframe_describe tool

  • Omit name to list active staged dataframes; pass a handle to inspect one. A miss returns found: false with active_names.

  • Entries carry source_tool, query_params, created_at, expires_at, row_count, truncated/max_rows, and column_schema. Listing does not extend expiry.


eia_dataframe_query tool

  • Run one read-only SQL SELECT against staged handles. row_limit defaults to 1000 and caps at 10000; preview narrows the inline slice, and the 64,000-byte per-surface budget can end it sooner.

  • truncated: true means totalRows is a cap, not a full count. register_as stages the complete result under an unused name with an exact count; the notice gives the ORDER BY … LIMIT/OFFSET query 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, and register_as_clash.


eia_dataframe_drop tool

  • Pass name to remove a staged dataframe; requires EIA_DATAFRAME_DROP_ENABLED=true.

  • Returns dropped: false when nothing matched; a failed drop returns retryable canvas_drop_failed and 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 in unavailable_facets and retried on the next call

  • Routes whose metadata could not be fetched are reported through eia_search_routes instead of dropped

  • DataCanvas (DuckDB) staging is opt-in per call; without canvas the three dataframe tools are not callable

Agent-friendly output:

  • Provenance — eia_query_route echoes the canonical route, and staged dataframes record their source_tool and query_params

  • Capped-window disclosure — truncated responses report the count against the cap and a notice naming the next call

  • Typed failures — error reason values (e.g. route_not_queryable, invalid_facet, missing_table) carry a recovery hint

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/mcp

Prerequisites

  • Bun v1.4.0 or higher (or Node.js v24+).

  • A free EIA API key from api.eia.gov. The DEMO_KEY hits rate limits quickly; a real key is required for sustained use.

Installation

  1. Clone the repository:

git clone https://github.com/cyanheads/eia-energy-mcp-server.git
  1. Navigate into the directory:

cd eia-energy-mcp-server
  1. Install dependencies:

bun install
  1. Configure 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

EIA_API_KEY

Required. Free API key from api.eia.gov — appended as api_key on every request.

—

EIA_BASE_URL

EIA API base URL.

https://api.eia.gov/v2

EIA_DATASET_TTL_SECONDS

Dataframe lifetime in seconds; each eia_dataframe_query that references a dataframe extends it.

86400 (24 h)

EIA_DATAFRAME_DROP_ENABLED

Set to true to expose eia_dataframe_drop (also requires CANVAS_PROVIDER_TYPE=duckdb). Off by default to avoid accidental canvas cleanup.

false

EIA_CANVAS_MAX_ROWS

Row ceiling for eia_query_route staging; reaching it adds ~8.5 s to a call.

25000

EIA_FACET_VALUE_CAP

Facet values eia_describe_route returns per facet before truncating; page with facet and values_offset.

50

CANVAS_PROVIDER_TYPE

Set to duckdb to enable DataCanvas (Node only), which adds the three eia_dataframe_* tools and stage: true.

—

MCP_TRANSPORT_TYPE

Transport: stdio or http.

stdio

MCP_HTTP_PORT

HTTP server port.

3010

MCP_HTTP_ENDPOINT_PATH

HTTP endpoint path.

/mcp

MCP_SESSION_MODE

HTTP sessions: stateless, stateful, or auto.

stateless

MCP_PUBLIC_URL

Public origin override for TLS-terminating reverse-proxy deployments.

—

MCP_AUTH_MODE

Auth mode: none, jwt, or oauth.

none

MCP_LOG_LEVEL

Log level (RFC 5424).

info

LOGS_DIR

Directory for log files (Node.js only).

<project-root>/logs

STORAGE_PROVIDER_TYPE

Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1.

in-memory

OTEL_ENABLED

Enable OpenTelemetry instrumentation.

false

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:http
  • Run 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-server

The 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

src/index.ts

createApp() entry point — registers tools and inits services.

src/config

Server-specific environment variable parsing and validation with Zod.

src/mcp-server/tools

Tool definitions (*.tool.ts) — browse, describe, search, query, and three DataCanvas dataframe tools.

src/services/eia

EIA API v2 service — route tree cache, Fuse.js index, facet fan-out, HTTP client.

src/services/canvas-bridge

DataCanvas bridge — registers EIA query results as DuckDB dataframes, routes SQL queries.

tests/

Unit and integration tests mirroring src/.

docs/

Design documents (design.md, idea.md).

Development guide

See CLAUDE.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — no try/catch in tool logic

  • Use ctx.log for request-scoped logging, ctx.state for tenant-scoped storage

  • Always call eia_describe_route before eia_query_route — facet values require a separate API fan-out and are not embedded in route metadata

  • Wrap 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 test

License

Apache-2.0 — see LICENSE for details.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    Not graded
    maintenance
    Provides 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
  • A
    license
    Not graded
    quality
    A
    maintenance
    Exposes 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 npm
    1
    Apache 2.0
  • F
    license
    A
    quality
    D
    maintenance
    An 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
    -