Changelog
Source:NEWS.md
entsoeapi.mcp 0.6.1
The Docker image builds again: its build-time smoke test still expected 29 tools, so the image failed to build once 0.6.0 added
congestion_management. The test no longer hard-codes a count: it checks that every tool defined in the package is served, under a unique name, as a valid tool definition. Neither 0.5.0 nor 0.6.0 reached Docker Hub, so this is the first image since 0.4.0 and carries the changes of both.Docker images are published by CI: pushing a
vX.Y.Ztag runs.github/workflows/docker.yaml, which builds the image, smoke-tests it (MCPinitialize,tools/listlists every tool, runs as the non-rootmcpuser) and pushessbudai/entsoeapi.mcp:vX.Y.Zand:latest. An existing tag can be (re)published with a manual run of the workflow.Release checklist: the
initializesmoke test passed without any output, because the server exits as soon as stdin closes, before it answers; stdin is now kept open. Atools/listsmoke test was added, and section 7 describes the CI publishing, with the manualdocker pushkept as a fallback.
entsoeapi.mcp 0.6.0
entsoeapi 1.3.1
New
congestion_managementtool (ENTSO-E 13.1.A-C), one tool with atypeargument so the tool list sent with every request grows by one:redispatching_internal(default, control-areaeic),redispatching_cross_borderandcountertrading(eic_in,eic_out), andcosts(monthly costs of redispatching, countertrading and other remedial actions, optionalevent_natureA46/B03/B04).Requires entsoeapi >= 1.3.1, which fixed the tidy output of
costs_of_congestion_management()(the cost amount was dropped, monthly points drifted to Mar 3 instead of Mar 1 and ignored CEST, and a sparse A03 series lost its last month).coststherefore returnsts_point_congestion_cost_price_amountwith one row per month, starting at local midnight (CET/CEST) on the first of the month.gen_time_series(type = "wind_solar")takesprocess_type:A01day-ahead (new default),A40intraday orA18current forecast. Before, onlyA18(entsoeapi’s default) was reachable, although the tool and the README called it a day-ahead forecast.No-data replies no longer fail: when ENTSO-E has no data it sends an acknowledgement, which entsoeapi returns as a one-row frame. Caching it emptied every column and DuckDB raised “Data frame with at least one column required”. The tools now return
(no data)followed by the API’s reason.
entsoeapi.mcp 0.5.0
Server instructions: the MCP
initializereply now carries real instructions for the model (resolve the EIC witharea_eicfirst, fetch once, answer withsql_queryon the cached table, handle several series and# error:results) instead of mcptools’ generic “This provides information about a running R session.”. mcptools offers no argument for this, sorun()wraps its internalcapabilities(); with an mcptools version that lacks it, the server starts with the default text.serverInfonow reportsentsoeapi.mcpand the package version instead of “R mcptools server”.Agent skill:
inst/skills/entsoe-market-data/SKILL.mddescribes the workflow, a question-to-tool map and the common pitfalls (wrong area type, several series in one table, UTC timestamps) for agents that load skills.DST-safe local time in cached tables: every point timestamp column (
ts_point_dt_start,bid_ts_point_dt_start) now gets a_cettwin holding the same instant in Central European wall-clock time (CET/CEST), computed in R. The sandboxed DuckDB cannot load the ICU extension, sotimezone()was unavailable, and the advised fixed+ INTERVAL 2 HOURshift misplaced part of every DST changeover day. The envelope gets a# time:note, the suggested query groups by the_cetcolumn, and the server instructions, SKILL.md,sql_querydescription and README say to group by it. Envelope sample rows now keep00:00:00on midnight values, and the multi-series WARNING lists values in sorted order.One dependency fewer:
digestis dropped. Cache table names are now hashed withrlang::hash(); rlang is already installed as a dependency of entsoeapi, mcptools and ellmer, so the install loses a compiled package. Table name suffixes differ from 0.4.0, which only matters within a session.Multi-series detection uses the real column names: the envelope WARNING now checks
ts_classification_sequence_position,ts_mridandts_resolution, the columns entsoeapi’s tidy output actually carries, so stacked day-ahead price series (e.g. a PT15M and a PT60M auction) are flagged again. The suggested query prefersts_point_dt_startand a price/quantity column instead of averagingts_mrid.Descriptions and README use real column names:
energy_prices,intraday_pricesand thesql_queryexample refer tots_classification_sequence_position,ts_point_dt_startandts_point_quantityinstead of the non-existentsequence,dt_startandvaluecolumns. The README example envelope and workflow come from real ENTSO-E responses.
entsoeapi.mcp 0.4.0
entsoeapi 1.3.0
Requires
entsoeapi (>= 1.3.0). Version 1.3.0 parses API responses about 10x faster and sends the split requests of a query in parallel (e.g. the day-by-day requests ofgen_time_series(type = "per_unit")). Version 1.2.1 adds theconstraint_ts_*columns toflow_based_allocationsand fixes the A03 curve gap filling. No exported function or argument changed, so the 29 tools keep their signatures.Persistent EIC cache:
run()now switches entsoeapi’s EIC code table cache to disk (ENTSOEAPI_CACHE_DIR, defaulting totools::R_user_dir("entsoeapi", "cache")), so the EIC lookup tools no longer re-download the tables in every new MCP session. Entries expire after one day. Anentsoeapi.cache_diroption set by the user is respected; an emptyENTSOEAPI_CACHE_DIRor an unwritable directory keeps the in-memory cache. In Docker, mount a volume on/home/mcp/.cacheto keep it.The
gen_time_seriesdescription no longer callsper_unit“slow”; it now says that it sends one request per day, in parallel.
Speed and robustness
-
Repeated queries no longer hit the API. The session DuckDB cache was checked only after the API call had been made, so an identical repeat call downloaded and parsed the data again and then discarded it.
safe_to_cache()now checks for the table first; because the tools pipe theentsoeapicall into it, the call is a lazy promise that is never evaluated on a cache hit (e.g. 3.7 s -> instant for two days of day-ahead prices). -
Clear date errors:
parse_date()now fails withperiod_start must be a date in YYYY-MM-DD format (...), got "Oct 1"instead of passingNAon to entsoeapi, so the LLM can fix the call straight away. -
Sandboxed
sql_query: the session DuckDB now runs with file system and network access disabled (read_csv(),COPY ... TO,ATTACH,INSTALL), a memory cap (ENTSOEAPI_MCP_DB_MEMORY, default1GB), and a locked configuration, so LLM-written SQL cannot read container files, reach the network, or exhaust memory. Temp tables and all queries work as before. -
Faster EIC filtering: the
queryfilter of the EIC tools is vectorised per column (1.1 s -> 0.15 s on the 74k-rowall_approved_eictable). A query that is not a valid regular expression (e.g.C++) is matched literally instead of failing, and empty cells no longer match the queryNA.
Docker image
-
~230 MB instead of ~1.8 GB. Multi-stage build:
rocker/r-verinstalls the binaries, then R and the packages are copied ontoubuntu:noblewith only the shared libraries they link against (worked out withlddat build time). pak no longer installs system requirements (a JDK, LLVM, compilers,-devheaders, …), and the build drops unused recommended packages, package docs, the X11/cairo/Tcl-Tk modules and debug symbols. - Dependencies are now read from
DESCRIPTION, so the image follows the narrowed entsoeapi dependency tree (no moretidyr,readr,vroom,xmlconvert,httr, …) automatically;mcptoolscomes from CRAN. - R 4.6.1 (was 4.4.3), selectable with
--build-arg R_VERSION=.... - The image is smoke-tested at build time (all namespaces load, DuckDB connects, 29 tools register).
- A
.dockerignorekeeps.git,.RData, etc. out of the build context.
entsoeapi.mcp 0.3.2
LLM guidance improvements
Natural language trigger phrases: all 22 tool descriptions (21 data-fetching tools +
area_eic) now lead with a human-phrasing sentence covering synonyms users actually speak — e.g. “power prices, spot prices, SDAC prices, EPEX prices” forenergy_prices; “total load, power demand, electricity consumption” forload; “fuel mix, renewable generation, wind power output” forgen_time_series— plus explicit country/zone examples (Germany (DE-LU), Austria (AT), Hungary (HU), France (FR), …). This improves tool routing accuracy when the user asks in plain language rather than ENTSO-E document codes.Anti-hallucination instruction: every data-fetching tool description now contains “Returns actual ENTSO-E data — do NOT generate synthetic [prices/load/generation/…] when this tool is available.” This directly prevents the LLM from substituting synthetic values when a live data tool is reachable.
Balancing terminology:
contracted_reservesdescription now names FCR, aFRR, mFRR, and RR by their full names alongside the ENTSO-E process type codes, eliminating a routing gap for users who ask about frequency reserves by acronym.Third-country specifics:
allocated_transfer_capacities_3rd_countriesnow lists example third countries (Ukraine, Serbia, Norway, Switzerland) for border-specific queries.
entsoeapi.mcp 0.3.1
Bug fix
-
Tool error resilience: API errors (invalid EIC code, missing token, HTTP failures) previously propagated as unhandled R exceptions, causing Claude Desktop to show “Failed to call tool”. The
mute_stdout_tool()wrapper now catches these errors viatryCatchand returns a# error: <message>text string so the LLM can read the message and self-correct (e.g. by callingarea_eicfirst to obtain a valid EIC code).
LLM guidance improvements
-
sql_querymax_rowsguidance: the tool description now explains when to raisemax_rowsbeyond the 100-row default — e.g.max_rows = 800for one month of hourly data,max_rows = 3000for 15-min data — while recommending that values above 5000 be avoided to prevent filling the context window. Themax_rowsargument description notes that the 100-row default is intentional: it encouragesGROUP BYaggregation inside DuckDB rather than bulk dumps through the JSON-RPC pipe.
entsoeapi.mcp 0.3.0
LLM-usability fixes for the DuckDB cache
Envelope rewrite: every cached-table envelope now leads with an explicit directive — never compute statistics from the schema sample; always use
sql_queryagainst the named table. The block previously labelled# preview (first N rows)is now# schema sample (N of M rows; do not use for analysis)so the LLM does not mistake it for the result.Multi-series detection: when a cached table contains more than one distinct value in any of the ENTSO-E series-discriminator columns (
sequence,business_type,process_type,time_series_mrid,auction_type, etc.), the envelope now carries a# WARNING: multiple series presentline listing the values. The LLM is instructed to filter explicitly before aggregating.EIC disambiguation:
area_eicdescription now requires the LLM to present every match with itsarea_type_codeand ask the user when a country resolves to multiple EICs (e.g. Germany: DE-LU bidding zone vs. DE control area). Prices → bidding zone, load → control area, flows → border.Binding-sequence guidance:
energy_pricesandintraday_pricesdescriptions now explain that Sequence 1 is normally the binding auction price and Sequence 2 is secondary/shadow, and require explicit filtering when both are present.
entsoeapi.mcp 0.2.0
DuckDB-backed result cache
New: in-process DuckDB (in-memory, per session) caches every time-series result. The 21 data tools now return a compact envelope
{table, rows, schema, 5-row preview, SQL hint}instead of capped CSV.New tools:
sql_query,list_tables,describe_table. Tool count: 26 → 29.Repeat calls with identical arguments reuse the existing cached table (content-addressed via a short md5 hash) — no second hit to the Transparency Platform within a session.
slim_ts()still drops constant metadata columns before insertion to save memory and preview tokens.
Compatibility
Behaviour change: the 21 time-series tools no longer return a raw CSV string. Anything parsing the old format would break. EIC lookup tools (
area_eic,party_eic,all_approved_eic,resource_object_eic) andget_newsare unchanged — they still return CSV directly.New runtime dependencies:
duckdb,DBI,digest.
entsoeapi.mcp 0.1.0
Initial release
Provides a Model Context Protocol (MCP) server that exposes the
entsoeapipackage as 26 structured tools for LLM-enabled applications such as Claude Desktop.-
Tools cover all major ENTSO-E Transparency Platform domains:
- EIC lookup – area, party, resource-object and all-approved EIC codes, and ENTSO-E news.
-
Load – actual, day-ahead, week-ahead, month-ahead, year-ahead, and margin load (unified
tool_loadwith atypeparameter). -
Generation – time-series (
tool_gen_time_series) and installed capacity (tool_gen_capacity), each merging several underlying API document types. - Market – day-ahead energy prices, intraday prices, net transfer capacities, day-ahead commercial schedules, explicit offered transfer capacities, flow-based allocations, congestion income, and allocated transfer capacities for third countries.
- Transmission – cross-border physical flows, total commercial schedules, net positions, and forecasted transfer capacities.
- Outages – generation units, production units, and transmission grid.
- Balancing – imbalance prices, imbalance volumes, and contracted reserves.
Key implementation details
MCP server runs over stdin/stdout via
mcptools::mcp_server(); theENTSOE_PATsecurity token is read automatically from the environment.All tool results are serialised as CSV (instead of JSON), reducing context-window token usage by 60–70 % for wide time-series data frames. Results are capped at 100 rows with a truncation notice appended when data is partial.
Uninformative constant columns (repeated domain names, currency codes, unit labels) are dropped from every result via an internal
slim_ts()helper, further reducing payload size.HTTP response headers printed by
httr2::req_verbose()are suppressed before they can corrupt the JSON-RPC stream on the MCP stdio transport.Tool argument descriptions steer the LLM toward short date ranges to avoid unnecessarily large API responses.