@cyanheads/nasa-power-mcp-server
Query NASA POWER solar, wind, building, and agroclimatology data via MCP. STDIO or Streamable HTTP.
9 Tools
Overview
NASA POWER historical solar and meteorological observations for renewable energy, sustainable buildings and agroclimatology. Retrieve point time series and climatology, inspect native-grid regions, and compare labeled locations with source units and provenance. No NASA account or API key is required.
Tools
Eight tools are enabled by default; NASA_POWER_DATAFRAME_DROP_ENABLED=true enables the ninth.
Skills
The skill ships in skills/nasa-power-guide/SKILL.md. Plugin hosts load it from the package, and MCP clients that support the Skills extension read it from the server as skill://nasa-power-guide/SKILL.md.
Capability reference
nasa_power_get_timeseries tool
latitude / longitude and temporalResolution: hourly and daily take an inclusive startDate / endDate, monthly takes startYear / endYear. selection is a named preset (default solar_pv) or explicit parameters, at most 15 effective codes hourly and 20 otherwise, corrections included.
community (RE, SB, AG; default RE), units (metric, imperial) and timeStandard (LST, UTC). Optional siteElevation adds PSC; paired windElevation (10–300 meters) and windSurface add WSC. Use nasa_power_list_reference topic wind_surfaces for all 17 canonical NASA aliases, including airportgrass, airportice and vegtype_1; vegetation underscores are retained.
- Returns
metadata, parameters, expansions, omittedParameters, summaries, rows, an exact rowCount and dataset (null unless staged). Optional canvas_id reuses a canvas when staging is needed.
- When the response still overflows the budget without its observations (wide selections with hour-of-day groups), the summaries stage beside the observations as
summaryDataset; summaries keeps one entry and summaryCount gives the exact total. Query the table in summaryIndex order; SQL units: null restores an omitted source unit.
- Codes NASA lists but does not serve at the requested resolution (
GDD* at monthly and climatology, *_HR_MAX and *_HR_MIN at monthly) fail with unsupported_parameter before any data request, naming the codes and the resolution that serves them. This holds for every data tool.
nasa_power_get_climatology tool
- Point coordinates with the same selection and corrections; optional
startYear and endYear together, otherwise the source product range. No temporalResolution input.
- Small profiles remain inline; larger profiles return a bounded preview and complete
dataset handle, and oversized summaries stage as summaryDataset with an exact summaryCount, as in nasa_power_get_timeseries. Pass optional canvas_id to reuse an existing workspace. Without DuckDB, an oversized result is refused with canvas_required, which lists calls that each fit inline: parameter groups for a wide selection.
- Group codes list only their actually returned members in
expansions, on every data tool: SI_EF_TILTED_SURFACE and the distinct SI_TILTED_AVG, SI_TILTED_MIN, SI_TILTED_MAX groups (numeric angles and N/S orientation text included), the SI_TRACKER_AVG, SI_TRACKER_MIN, SI_TRACKER_MAX groups, hour-of-day *_HR groups (members *_00 … *_23, monthly and climatology) and *_HR_MAX / *_HR_MIN groups (members *_00_MAX … *_23_MAX, climatology). A group is omitted only when none of its members return.
nasa_power_get_region tool
- One
parameter over ordered latitudeMin / latitudeMax and longitudeMin / longitudeMax, each axis spanning 2–10 degrees (invalid_region otherwise); split antimeridian regions into separate calls. temporalResolution is daily, monthly or climatology; point corrections are unsupported.
- Daily regions require date bounds and monthly regions require year bounds. Regional climatology accepts no year fields and reports the source's precomputed period; use
nasa_power_get_climatology for a custom point year window.
- Returns cell-tagged
rows, cellCount and per-period summaries with equal-weight cell min / mean / max, not area-weighted. Optional canvas_id reuses a canvas for staging.
- Oversized summary envelopes return
summaryDataset with all cross-cell summaries, exact summaryCount and a whole-record inline preview. Query the table in summaryIndex order; SQL units: null restores an omitted source unit. Observations and summaries register together and retain linked provenance.
nasa_power_compare_locations tool
- 2–10
locations, each with coordinates and a label of 1–120 characters, sharing one selection, corrections and window. temporalResolution defaults to climatology; hourly, daily and monthly also work.
- Returns successful
locations with per-site provenance, location-tagged rows, annual and calendar-season summaries, and failed entries with partial: true when some sites fail; all-site failure returns all_locations_failed. possibleSharedGridCell flags sites that may share a grid cell.
- Optional
sort (parameter, direction asc / desc) orders by a selected numeric parameter with known identical units. Optional canvas_id reuses a canvas for staging.
- When summaries exceed the response budget,
summaryDatasets.buckets and summaryDatasets.locations point to complete SQL tables; inline summaries become whole-record previews and each location includes summaryCount. Query in summaryIndex order; the location-summary table includes locationId. SQL units: null represents an omitted source unit, not a known unit.
nasa_power_search_parameters tool
community (default RE), temporalResolution (default daily), optional filter (up to 256 characters), offset and positive integer limit (default 20, effective cap 100 with a notice when capped).
- Every case-insensitive
filter token must match a code, name or definition across the complete dictionary before sorted pagination; a blank filter browses it. entries, total, hasMore and truncated describe the page.
- Codes NASA lists but does not serve at the selected resolution are left out before counting and paging; a
notice names any the filter matched, with the resolution to request instead.
nasa_power_list_reference tool
topic: presets (default), communities, coverage, missing_data, wind_surfaces or dataframes.
- Returns typed
entries, guidance, documentationUrls and verifiedOn. Presets are solar_pv, wind_turbine, building_hvac, agroclimatology and water_balance; building_hvac is unavailable hourly. agroclimatology adds T2M_MAX and T2M_MIN outside hourly resolution; monthly/climatology extremes remain source aggregates, without reconstructed daily records or calculated growing degree days. Growing degree days (GDD*) are served at daily resolution only.
nasa_power_dataframe_describe tool
- Required
canvas_id from a producing response; optional table limits inspection to one table.
- Returns canvas and table expiry, SQL columns with source units, and original scientific
provenance. Only tables in the supplied canvas are visible.
nasa_power_dataframe_query tool
- Required
canvas_id and one read-only SELECT in sql (up to 16,384 characters); positive integer rowLimit defaults to 100 and is capped at 1,000, with an effective-cap notice for larger requests. Files, writes and system catalogs are denied.
- Returns
columns, rows, rowCount, shownCount, truncated and countSemantics (exact or materialized_prefix). SQL has a 10-second deadline; the structured and rendered outputs each must fit 40,000 characters.
- SQL mistakes retain bounded identifiers or conversion values with recovery guidance. Operational failures use generic messages; engine paths and native causes are excluded.
nasa_power_dataframe_drop tool
- Required
canvas_id and exact table; enabled only by NASA_POWER_DATAFRAME_DROP_ENABLED=true.
- Returns
dropped: false for an absent table while other tables keep the canvas alive. Removing the final table also retires its canvas and frees its slot; subsequent describe, query or drop calls return canvas_not_found.
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.
POWER-specific:
- Historical gridded observations, rather than site measurements or forecasts. Meteorological coverage starts in 1981, solar in 1984 and hourly in 2001; source configuration and publication latency further constrain availability.
- One active upstream request, starts at least two seconds apart, bounded retries and a 55-second overall call deadline. NASA publishes no numeric request allowance. References cache for 24 hours and observations for 10 minutes.
- Source fill values become
null; zero remains a measurement. Monthly annual keys and climatology ANN remain distinct from monthly observations. LST labels have no UTC offset.
T_ZONES and TM_ZONES retain numeric climate-zone codes with valueKind: categorical, including in SQL column metadata. They have no arithmetic summaries or comparison sort metrics; explicit numeric sorting by either is rejected.
Agent-friendly output:
- Scientific provenance — source API version, dataset identifiers, endpoint and access time accompany results; preserve returned units and attribute NASA POWER.
- Explicit gaps —
omittedParameters distinguishes an absent series from fill values; arithmetic observation means and calendar-season buckets are not climate normals, annual yields or water balances.
- Complete datasets — inline outputs each fit 40,000 characters. Larger datasets stage all rows with a preview of at most 20 rows and a
dataset handle; unsupported requests fail with narrowing guidance, and oversized ones without DuckDB fail with canvas_required and a list of calls that each fit inline, instead of returning a capped source prefix.
Staging requires DuckDB and supports at most 250,000 rows, 64 parameter columns and 32 MiB of serialized rows per dataset. Canvases are process-local capabilities: pass the returned token explicitly and route later calls to the same process. Tables expire after 30 minutes with eight tables per canvas. Defaults are one idle hour and six absolute hours per canvas, four canvases per tenant, eight per process, and 256 MiB engine memory per canvas. Operators can size canvas capacity, memory and lifetime below; engine memory does not bound total RSS or temporary disk.
Getting started
Connect to the hosted instance, no install:
Or run it locally:
For other clients, add this to the MCP config file:
npm and Docker installs stage large results in DuckDB for SQL by default; set CANVAS_PROVIDER_TYPE=none to keep every result inline. The Claude Desktop bundle is inline-only: send the calls an oversized request's canvas_required refusal lists, or use npm or Docker for analytics. No NASA account or API key is required. For Docker or a source build, see Running the server.
Configuration
Unset, blank and whole-value placeholder settings retain these defaults. Invalid sizing fails startup. Byte budgets, table limits and producer concurrency remain fixed independently of operator canvas sizing. See .env.example for optional transport, authentication, storage, logging and telemetry settings.
Running the server
Local development
Requires Bun v1.4.0 or higher (or Node.js v24+).
Docker
The image defaults to HTTP on port 3010 in stateless session mode and logs to /var/log/nasa-power-mcp-server. To run it over stdio from an MCP client, use "command": "docker" with "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/nasa-power-mcp-server:latest"]. To build locally, docker build -t nasa-power-mcp-server .; OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them. For a client outside loopback, configure authentication and TLS at the deployment boundary.
Project structure
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 logging and ctx.signal for cancellation
- Register new tools in the
createApp() array in src/index.ts
- Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields, and preserve source units and annual-period distinctions
content[] and structuredContent carry the same complete data
Contributing
Issues are welcome. Run checks and tests before submitting:
License
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.