Skip to main content
Glama

eia-energy-mcp-server

Search EIA Routes

eia_search_routes
Read-only

Fuzzy text search across route names, descriptions, and category labels. Resolves natural-language queries like "electricity retail sales by state" or "natural gas imports" to matching route paths. Multi-term queries are also matched term by term, so combining a commodity, a metric, and a sector — "electricity price residential", "coal generation industrial sector" — reaches the route carrying that data even when no single entry reads like the whole phrase. STEO series names are indexed so queries like "ethanol net imports" or "crude oil production forecast" also resolve, and so are facet values, so a fuel type or sector term like "wind" or "anthracite coal" resolves to the route that exposes it, with filter_hint carrying the filter to pass on. Results include isLeaf so you know whether to browse further or query directly. Results with score > 0.72 are weak matches — try a more specific query or use eia_browse_routes to explore the taxonomy. The first call after server start waits 24-30s while the index warms, and at most 45s; every later call returns in milliseconds. Check indexComplete before reading anything into a short or empty result set.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum results to return (default 10, max 30).
queryYesFree-text search terms to match against route names and descriptions.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
capNoThe limit that was applied.
errorNoPresent when the call failed. Absent on success.
shownNoNumber of results returned.
noticeNoRecovery hint when no routes matched — suggests alternative queries or using eia_browse_routes.
resultsNoRanked matches, best first.
indexGapsNoPresent only when indexComplete is false: route paths whose metadata could not be fetched (call eia_browse_routes on one to re-fetch it) and index passes that did not land ("steo_series", "facet_values").
truncatedNoTrue when matches were capped at limit; more may exist.
totalIndexedNoTotal entries in the search index (routes + STEO series names + facet values).
indexCompleteNoTrue when this answer was ranked against the complete corpus. False means part of it is missing (see indexGaps) — results may be short, and a better match may exist that was never scored.
effectiveQueryNoQuery as submitted to the Fuse.js index.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed6 schema fields changed
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedInput schema / additionalProperties
      Added value: +false
    • changedOutput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedOutput schema / anyOf
      Added value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "results",
      +      "effectiveQuery",
      +      "totalIndexed",
      +      "indexComplete",
      +      "truncated",
      +      "shown",
      +      "cap"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • addedOutput schema / properties / error
      Added value: +{
      +  "additionalProperties": {},
      +  "description": "Present when the call failed. Absent on success.",
      +  "properties": {
      +    "code": {
      +      "description": "JSON-RPC error code for this failure.",
      +      "maximum": 9007199254740991,
      +      "minimum": -9007199254740991,
      +      "type": "integer"
      +    },
      +    "data": {
      +      "additionalProperties": {},
      +      "properties": {
      +        "reason": {
      +          "description": "Machine-readable failure mode.",
      +          "type": "string"
      +        },
      +        "recovery": {
      +          "additionalProperties": {},
      +          "description": "Actionable next step for the caller.",
      +          "properties": {
      +            "hint": {
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "hint"
      +          ],
      +          "type": "object"
      +        },
      +        "retryable": {
      +          "description": "Whether retrying may succeed.",
      +          "type": "boolean"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "message": {
      +      "description": "Human-readable description of what went wrong.",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "code",
      +    "message"
      +  ],
      +  "type": "object"
      +}
    • removedOutput schema / required
      Removed value: -[
      -  "results",
      -  "effectiveQuery",
      -  "totalIndexed",
      -  "indexComplete",
      -  "truncated",
      -  "shown",
      -  "cap"
      -]
  2. Changed1 schema field changed
    • changedOutput schema / properties / results / items / properties / score / description
      Previous value: -"Fuzzy match score: 0 = exact, 1 = no match. Lower is better; above 0.9 the match is unreliable."New value: +"Match score: 0 = exact, 1 = no match. Lower is better; above 0.72 the match is unreliable. On a multi-term query it is the better of the whole-phrase score and a per-term score that penalizes each query term the entry does not carry."
  3. Changed3 schema fields changed
    • addedOutput schema / properties / indexComplete
      Added value: +{
      +  "description": "True when this answer was ranked against the complete corpus. False means part of it is missing (see indexGaps) — results may be short, and a better match may exist that was never scored.",
      +  "type": "boolean"
      +}
    • addedOutput schema / properties / indexGaps
      Added value: +{
      +  "description": "Present only when indexComplete is false: route paths whose metadata could not be fetched (call eia_browse_routes on one to re-fetch it) and index passes that did not land (\"steo_series\", \"facet_values\").",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "results",
      -  "effectiveQuery",
      -  "totalIndexed",
      -  "truncated",
      -  "shown",
      -  "cap"
      -]New value: +[
      +  "results",
      +  "effectiveQuery",
      +  "totalIndexed",
      +  "indexComplete",
      +  "truncated",
      +  "shown",
      +  "cap"
      +]
  4. Changed2 schema fields changed
    • changedOutput schema / properties / results / items / properties / filter_hint / description
      Previous value: -"Pre-built filter for eia_query_route when a specific facet value is required. Present on STEO series results — pass directly as filters (e.g. eia_query_route(route=\"steo\", filters=filter_hint))."New value: +"Pre-built filter for eia_query_route when a specific facet value is required. Present on STEO series and facet-value results — pass directly as filters (e.g. eia_query_route(route=\"steo\", filters=filter_hint))."
    • changedOutput schema / properties / totalIndexed / description
      Previous value: -"Total entries in the search index (routes + STEO series names)."New value: +"Total entries in the search index (routes + STEO series names + facet values)."
  5. Changed1 schema field changed
    • changedOutput schema / properties / results / items / properties / score / description
      Previous value: -"Fuzzy match score: 0 = exact, 1 = no match. Lower is better."New value: +"Fuzzy match score: 0 = exact, 1 = no match. Lower is better; above 0.9 the match is unreliable."
  6. Changed4 schema fields changed
    • addedOutput schema / properties / cap
      Added value: +{
      +  "description": "The limit that was applied.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / shown
      Added value: +{
      +  "description": "Number of results returned.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / truncated
      Added value: +{
      +  "description": "True when matches were capped at limit; more may exist.",
      +  "type": "boolean"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "results",
      -  "effectiveQuery",
      -  "totalIndexed"
      -]New value: +[
      +  "results",
      +  "effectiveQuery",
      +  "totalIndexed",
      +  "truncated",
      +  "shown",
      +  "cap"
      +]
  7. Changed5 schema fields changed
    • addedOutput schema / properties / effectiveQuery
      Added value: +{
      +  "description": "Query as submitted to the Fuse.js index.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / notice
      Added value: +{
      +  "description": "Recovery hint when no routes matched — suggests alternative queries or using eia_browse_routes.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / totalIndexed
      Added value: +{
      +  "description": "Total entries in the search index (routes + STEO series names).",
      +  "type": "number"
      +}
    • removedOutput schema / properties / total_indexed
      Removed value: -{
      -  "description": "Total entries in the search index (routes + STEO series names).",
      -  "type": "number"
      -}
    • changedOutput schema / required
      Previous value: -[
      -  "results",
      -  "total_indexed"
      -]New value: +[
      +  "results",
      +  "effectiveQuery",
      +  "totalIndexed"
      +]
  8. First observed

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the description's job is to add context — and it adds a lot: first-call warm-up latency of 24-30s (up to 45s) vs. milliseconds on later calls, the indexComplete check, result semantics (isLeaf, filter_hint carrying filters), and the weak-match threshold. This is non-obvious behavioral disclosure that no annotation or schema could convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but efficient — purpose is front-loaded and each subsequent clause adds value (matching behavior, facet handling, result fields, latency, indexComplete). The operational warm-up note is valuable rather than padding. It runs a bit long but no sentence is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values needn't be spelled out, and the description covers optimization/search-navigation guidance, result semantics (isLeaf, filter_hint, score threshold), and a critical operational quirk (warm-up latency, indexComplete). Nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema documents both query and limit (default 10, max 30) — baseline 3. The description goes beyond this by clarifying query semantics: fuzzy matching, term-by-term multi-term matching, STEO series indexing, and facet-value resolution. It meaningfully enriches how the query parameter behaves in ways the schema cannot express.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — 'Fuzzy text search across route names, descriptions, and category labels' — and explains the resolution goal (natural-language queries → matching route paths). This clearly differentiates it from siblings like eia_browse_routes (browse taxonomy) and eia_query_route (direct query), which the sibling list makes relevant.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent to eia_browse_routes when results are weak (score > 0.72), and distinguishes browsing further vs. querying directly via isLeaf. It doesn't enumerate every sibling differentiation (e.g., when to use eia_query_route vs. this for an exact known path), but the key exclusion condition and alternative are stated clearly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.