Skip to main content
Glama
vasilyevstan

nordpool-ee-mcp

by vasilyevstan

Estonia electricity prices CLI and MCP server

nordpool_ee.py is a small, dependency-free command-line tool that prints Estonia's Nord Pool day-ahead wholesale electricity prices for the next Europe/Tallinn calendar day. mcp_server.py exposes validated current-day and next-day data as typed Model Context Protocol tools over stdio.

Repository: https://github.com/vasilyevstan/electro

Requirements

  • Python 3.10 or newer

  • Internet access to dashboard.elering.ee

  • uv

Related MCP server: Steddion Energy MCP Server

Setup

Clone the repository and install its locked dependencies:

git clone https://github.com/vasilyevstan/electro.git
cd electro
uv sync --locked

CLI usage

From a checkout:

uv run nordpool-ee

Without a checkout:

uvx --from "git+https://github.com/vasilyevstan/electro.git@main" nordpool-ee

The output contains every published market interval in Tallinn local time, followed by the minimum, maximum, and duration-weighted average. Each price is shown in:

  • EUR/MWh, the unit returned by Elering

  • euro cents/kWh, calculated as EUR/MWh / 10

These are wholesale energy prices only. VAT, electricity supplier margin, network charges, excise, and other consumer costs are not included.

Day-ahead prices are normally published during the afternoon before delivery. If tomorrow's prices are not available yet, the command reports that explicitly and exits with a non-zero status instead of showing today's or partial data.

Exit statuses:

  • 0: complete next-day data was printed

  • 2: next-day prices have not been published

  • 3: Elering could not be reached successfully

  • 4: Elering returned invalid or incomplete data

MCP server

Start the local stdio server from a checkout:

uv run nordpool-ee-mcp

Or launch it directly from GitHub:

uvx --from "git+https://github.com/vasilyevstan/electro.git@main" \
  nordpool-ee-mcp

It exposes three tools:

get_estonia_current_day_prices
get_estonia_next_day_prices
get_estonia_prices_for_hour

The current-day and next-day tools take no arguments and return typed structured content containing:

  • the Estonia bidding area and delivery date

  • timezone, currency, source, and interval metadata

  • every complete 15-minute interval in EUR/MWh and cents/kWh, with and without VAT

  • minimum, maximum, and duration-weighted average prices on both VAT bases

  • hourly_averages for every elapsed hour, with offset-aware start/end times

  • the applied vat_rate_percent and excluded consumer costs

The current-day response includes current_interval, identifying the active Estonia quarter-hour price, and current_hour, containing the full-hour average at the time of the call. These are different prices: show both and label the time period and VAT basis. The next-day response returns null for both fields.

get_estonia_prices_for_hour accepts:

  • delivery_date: an Estonia delivery date in YYYY-MM-DD format

  • hour: an Estonia local clock hour from 0 through 23

It returns all quarter-hour prices in that local hour plus the hourly minimum, maximum, and average on both VAT bases. A repeated daylight-saving hour contains eight intervals and two separate hourly_averages, distinguished by UTC offset. Its summary averages both occurrences for compatibility. Day responses contain 23, 24, or 25 hourly averages; no missing or repeated hour is fabricated or collapsed. Requesting a skipped hour returns a tool error.

VAT and price fields

Each interval (including summary minima/maxima and current_interval) includes excluding_vat and including_vat, each containing eur_per_mwh and cents_per_kwh. Summaries and hourly averages use average_excluding_vat and average_including_vat with the same units. The MCP text response includes these same labeled values as its structured response.

For compatibility, existing interval fields eur_per_mwh / cents_per_kwh and summary fields average_eur_per_mwh / average_cents_per_kwh remain VAT-exclusive. The standalone CLI also remains VAT-exclusive.

The MCP adds Estonia's standard 24% VAT to the wholesale energy component. This rate has applied since 1 July 2025 and covers the supported 15-minute price period. Source: Estonian Tax and Customs Board. Historical hourly-era and incomplete-day support is unchanged.

VAT-inclusive price = VAT-exclusive price multiplied by 1.24. Calculations use decimal arithmetic before serialization, without rounding individual intervals first. Negative and zero spot prices are retained.

For example, the four 23:00-hour prices on 2026-09-28 were 20.01, 8.77, 7.05, and 6.05 EUR/MWh. The hourly average is 10.47 EUR/MWh:

{
  "vat_rate_percent": 24,
  "average_excluding_vat": {
    "eur_per_mwh": 10.47,
    "cents_per_kwh": 1.047
  },
  "average_including_vat": {
    "eur_per_mwh": 12.9828,
    "cents_per_kwh": 1.29828
  }
}

That is approximately 1.30 cents/kWh including VAT for the full hour, not the price for its first quarter-hour. wholesale_only still denotes the energy component, not a final consumer tariff. excluded_costs now lists only charges absent from both VAT bases: supplier margin, network charges, excise, and other consumer fees.

Expected retrieval failures are returned as MCP tool errors, not successful responses containing error text.

GitHub Copilot CLI

Register the server in Copilot CLI's user-level configuration so it is available in every new session:

copilot mcp add \
  --transport stdio \
  --tools get_estonia_current_day_prices,get_estonia_next_day_prices,get_estonia_prices_for_hour \
  electro -- \
  uvx --from "git+https://github.com/vasilyevstan/electro.git@main" \
  nordpool-ee-mcp

For an immutable installation, replace @main with @<commit-sha>.

The equivalent ~/.copilot/mcp-config.json entry is:

{
  "mcpServers": {
    "electro": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/vasilyevstan/electro.git@main",
        "nordpool-ee-mcp"
      ],
      "tools": [
        "get_estonia_current_day_prices",
        "get_estonia_next_day_prices",
        "get_estonia_prices_for_hour"
      ]
    }
  }
}

Copilot CLI inherits PATH for local MCP servers, so uvx must be available on PATH. The server writes only MCP protocol messages to stdout, as required for stdio transport.

Data source

The tool queries Elering, Estonia's transmission system operator:

https://dashboard.elering.ee/api/nps/price

The Estonia series is returned as data.ee in EUR/MWh. Elering explains that Nord Pool day-ahead prices use 15-minute market periods from September 30, 2025:

The implementation calculates the requested day in Europe/Tallinn and does not assume exactly 96 intervals. Daylight-saving transitions produce 92 or 100 quarter-hour intervals.

Nord Pool applies separate terms to customer-facing display and data redistribution. Publishing this source code under the MIT License does not grant rights to redistribute upstream market data. Review the applicable terms before exposing price data through a public website or API:

Validation

Run the deterministic test suite without live network access:

uv run python -m unittest discover -s tests -v

Check syntax:

uv run python -m py_compile nordpool_ee.py mcp_server.py

Run the CLI for a live next-day source check:

uv run nordpool-ee

License

The source code is available under the MIT License. The license does not cover Nord Pool or Elering data, trademarks, or third-party content.

Available Tools

3 tools
get_estonia_current_day_pricesGet Estonia current-day electricity pricesA

Get complete current-day Nord Pool prices for Estonia.

Returns 15-minute prices and hourly averages with and without VAT, in
EUR/MWh and euro cents/kWh. Show current_hour's average and the active
current_interval separately, using Estonia-local time. Supplier margin,
network charges, excise, and other fees remain excluded.
ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
areaYes
sourceYes
summaryYes
currencyYes
timezoneYes
intervalsYes
current_hourYes
delivery_dateYes
excluded_costsYes
interval_countYes
wholesale_onlyYes
hourly_averagesYes
current_intervalYes
interval_minutesYes
vat_rate_percentYes

TDQS

A3.6/5.0
Behavior4/5

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

No annotations exist, so the description must carry the load, and it does well: it discloses the time resolution (15-minute and hourly), VAT treatment, both unit systems, Estonia-local time, and explicitly what is excluded (supplier margin, network charges, excise, other fees). It omits whether prices are final day-ahead versus provisional and any refresh/auth behavior.

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?

Short and front-loaded: the scope sentence leads, followed by return-shape and exclusion details. Slight redundancy between 'current_hour's average' and the hourly-averages mention, but no wasted padding.

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

Completeness4/5

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

With an output schema present and zero parameters, the description need not explain return values, yet it still characterizes coverage and exclusions usefully. Complete enough to invoke correctly; only the freshness/finality of the data is unstated.

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?

The tool takes zero parameters, so there is nothing for the description to disambiguate. Baseline 4 applies; the description adds relevant framing around output shape without inventing parameter semantics.

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

Purpose4/5

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

Specifies verb + resource + scope precisely: current-day Nord Pool prices for Estonia. The 'current-day' qualifier implicitly separates it from the 'next_day' sibling, but the description never names the alternatives, so differentiation relies on the reader inferring it from the name.

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

Usage Guidelines2/5

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

No when-to-use, when-not-to-use, or alternative-tool guidance beyond what the name implies. With siblings like get_estonia_prices_for_hour and get_estonia_next_day_prices, the agent gets no explicit routing rule for choosing among them.

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

get_estonia_next_day_pricesGet Estonia next-day electricity pricesA

Get complete next-day Nord Pool prices for Estonia.

Returns each 15-minute interval and hourly averages in Europe/Tallinn local time, with and without VAT, in EUR/MWh and euro cents/kWh. Supplier margin, network charges, excise, and other fees remain excluded.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
areaYes
sourceYes
summaryYes
currencyYes
timezoneYes
intervalsYes
current_hourYes
delivery_dateYes
excluded_costsYes
interval_countYes
wholesale_onlyYes
hourly_averagesYes
current_intervalYes
interval_minutesYes
vat_rate_percentYes

TDQS

A4.3/5.0
Behavior4/5

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

With no annotations, the description carries the full burden, and it does disclose meaningful behavioral traits: 15-minute granularity plus hourly averages, Europe/Tallinn local time, with-and-without-VAT, and dual units. It also states what is excluded (supplier margin, network charges, excise, other fees). It does not cover auth or rate limits, but for a zero-param read tool this is a strong disclosure.

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

Conciseness5/5

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

Two short sentences, front-loaded with the core purpose, followed by the return-shape and exclusion caveats. Every clause adds information; nothing is padded.

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?

An output schema exists, so return values need not be re-explained, yet the description usefully summarizes granularity, timezone, VAT treatment, and units, and clarifies fees are excluded. 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?

There are zero parameters, so the baseline is 4; the description correctly avoids inventing parameter semantics that do not exist.

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 (Get), resource (next-day Nord Pool prices), and geographic scope (Estonia), which cleanly separates it from get_estonia_current_day_prices and get_estonia_prices_for_hour. An agent can route on the name/description alone without opening the schema.

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

Usage Guidelines3/5

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

Usage is implied by the 'next-day' qualifier against the 'current day' and 'for hour' siblings, but the description never explicitly says when to pick this tool over them or adds any prerequisite/exclusion. It is adequate but leaves the routing inference to the agent.

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

get_estonia_prices_for_hourGet Estonia electricity prices for an hourA

Get Estonia prices for a specific local date and clock hour.

Args:
    delivery_date: Estonia delivery date in YYYY-MM-DD format.
    hour: Estonia local clock hour from 0 through 23.

Returns every 15-minute market interval in the requested hour plus minimum,
maximum, and average prices with and without VAT. Repeated daylight-saving
hours include two offset-distinct hourly_averages and eight intervals;
summary averages both occurrences. A skipped hour returns a tool error.
Supplier margin, network charges, excise, and other fees remain excluded.
ParametersJSON Schema
NameRequiredDescriptionDefault
hourYes
delivery_dateYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
areaYes
hourYes
sourceYes
summaryYes
currencyYes
timezoneYes
intervalsYes
delivery_dateYes
excluded_costsYes
interval_countYes
wholesale_onlyYes
hourly_averagesYes
vat_rate_percentYes

TDQS

A4/5.0
Behavior5/5

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

With no annotations, the description carries the full burden and does so well: it discloses DST behavior (two offset-distinct hourly_averages, eight intervals, summary averaging both occurrences), that a skipped hour returns a tool error, and that supplier margin, network charges, excise and other fees are excluded. These are exactly the behavioral traits an agent needs before calling.

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?

The purpose is front-loaded, followed by an Args block and a Returns block. Given the 0% schema coverage the parameter restatement earns its place, and the DST/error sentences are dense with information rather than filler.

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

Completeness4/5

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

For a two-parameter read tool with an output schema, the description is thorough: it covers edge cases (DST, skipped hour error) and cost exclusions. Minor omissions such as authentication or rate-limit notes are not material here, and the presence of an output schema makes the return-value detail a bonus rather than a requirement.

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 0%, so the description must compensate, and it does: it specifies the YYYY-MM-DD format for delivery_date, identifies it as the Estonia delivery date, and clarifies hour is Estonia local clock time from 0 through 23. Both parameters gain meaning beyond the bare schema.

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

Purpose4/5

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

The description states a specific verb and resource (get Estonia prices) with a clear scope qualifier (for a specific local date and clock hour). It is distinguishable from the siblings in intent (arbitrary date/hour vs current-day or next-day), though it never names them explicitly.

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

Usage Guidelines3/5

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

"For a specific local date and clock hour" implies when to reach for this over the sibling current/next-day tools, but there is no explicit when-to-use, when-not-to-use, or alternative routing. Usage is left to inference.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.3.0
    • First observedget_estonia_current_day_prices
    • First observedget_estonia_next_day_prices
    • First observedget_estonia_prices_for_hour

TDQS

A3.9/5.0

Scored across 3 tools

Disambiguation4/5

The three tools target distinct time windows (current day, next day, specific hour), but get_estonia_prices_for_hour partially overlaps with get_estonia_current_day_prices since the current-day tool also surfaces the active interval and current-hour average. An agent can still choose correctly in most cases because each description clearly states its scope.

Naming Consistency4/5

All three follow a get_estonia_*_prices pattern in snake_case with a consistent verb, which is highly readable. The only minor deviation is the 'for_hour' prepositional suffix versus the adjective prefixes (current_day/next_day), so the shapes aren't perfectly parallel.

Tool Count4/5

Three tools is on the thin side but reasonably well-scoped for a niche single-zone price feed. Each tool earns its place by covering a distinct temporal window, so nothing feels redundant or bloated.

Completeness4/5

The surface covers the core lifecycle of price retrieval: current day, next day, and arbitrary date/hour lookups (which also enable historical queries). There's no range or multi-zone query and no 'all zones' option, but for an Estonia-focused server the essential operations are present.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    MCP server for real-time electricity prices, carbon intensity, and energy analytics across 41+ zones in Europe, Great Britain, the United States, and Australia. Query live prices, compare zones, check gas storage levels, get green scores, find optimal charging windows, and access advanced analytics. Free Basic tier requires no API key. Install via npx gridpulse-mcp or connect directly via Streamab
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables access to European electricity data including day-ahead prices, probabilistic forecasts, carbon intensity, and cheapest-window optimization for 43 bidding zones.
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Provides real-time electricity prices, cheapest hours, and contract comparison for 40+ countries, enabling AI agents to make energy-aware decisions.
    4
    -