IPMA Weather Server
# IPMA MCP Server
A Model Context Protocol (MCP) server that exposes Portuguese weather, warning and seismic data from the public IPMA API to MCP-compatible AI clients.
Built with Node.js and the official Model Context Protocol SDK.

Live demonstration captured on 2026-09-10. Braga is selected explicitly by its IPMA identifier because Amares is not listed in this endpoint's forecast catalogue. [Reproduce the call and view capture details](docs/demo.md).
## Features
The server exposes six MCP tools:
- `get_weather_forecast` - daily weather forecasts for Portuguese locations
- `get_weather_warnings` - current and upcoming meteorological warnings
- `get_seismic_data` - recent seismic activity
- `get_locations` - available forecast locations
- `get_weather_stations` - latest hourly weather station observations
- `get_uv_forecast` - UV index forecasts
All six tools provide validated structured results alongside readable text. Forecast locations can be selected by name or stable IPMA identifier. An optional authenticated Streamable HTTP transport supports explicitly provisioned remote clients.
Data is retrieved directly from the public API provided by the Instituto Português do Mar e da Atmosfera (IPMA).
## Tech Stack
- Node.js
- JavaScript
- Model Context Protocol
- `@modelcontextprotocol/sdk`
- `node-fetch`
- Zod contracts and JavaScript checked with TypeScript
- IPMA Open Data API
## Architecture
```text
MCP Client
│
│ Model Context Protocol
▼
IPMA MCP Server
│
│ HTTPS
▼
IPMA Open Data API
```
The default entry point uses standard input/output. A separate HTTP entry point shares the same MCP handlers, domain contracts, formatting and IPMA client. Only reference catalogues are cached; live measurements are fetched on demand. See the [architecture and design decisions](docs/architecture-roadmap.md).
## Getting Started
### Requirements
- Node.js 22 or newer (Node.js 24 LTS recommended; `.nvmrc` and Docker use 24)
- npm
- An MCP-compatible client
### Installation
Clone the repository:
```bash
git clone https://github.com/brandao-20/ipma-mcp-server.git
cd ipma-mcp-server
```
Install the dependencies:
```bash
npm ci
```
Start the MCP server:
```bash
npm start
```
The process waits for MCP messages on standard input; it does not start an HTTP server or a command prompt. MCP clients should launch `node` directly as shown below, keeping standard output reserved for protocol messages. No environment variables or API keys are required.
For Docker, build with `docker build -t ipma-mcp-server .` and run with `docker run --rm -i ipma-mcp-server`. Keep standard input open and do not allocate a TTY.
For the optional HTTP transport, follow the [authenticated HTTP setup and deployment guide](docs/http.md). It requires client credentials and defaults to loopback. A [small SDK client](examples/http-client.mjs) demonstrates consuming structured forecast data.
## MCP Client Configuration
For clients that support local MCP servers, configure the server to run the project's entry point.
Example:
```json
{
"mcpServers": {
"ipma": {
"command": "node",
"args": ["/absolute/path/to/ipma-mcp-server/src/index.js"]
}
}
}
```
Replace the path with the absolute location of the cloned repository.
## Available Tools
### `get_weather_forecast`
Returns a daily weather forecast for a Portuguese location.
Parameters:
```text
city string required unless locationId is provided
locationId integer required unless city is provided
days integer optional, 1–5 (default: 5)
```
Provide exactly one of `city` or `locationId`. Names ignore case, accents and surrounding whitespace. Exact names take precedence; partial names must resolve to a single location. Ambiguous names return supported candidates instead of choosing one silently. The result identifies the selected location and returns only the days available from IPMA. [Data contracts and compatibility details](docs/data-contracts.md).
Example request:
```text
What is the weather forecast for Braga for the next three days?
```
### `get_weather_warnings`
Returns current and upcoming yellow, orange and red meteorological warnings for Portugal. Green entries and expired warnings are excluded. Each warning includes its status and UTC validity interval.
Example request:
```text
Are there any active weather warnings in Portugal?
```
### `get_seismic_data`
Returns up to ten recent seismic observations, sorted newest first, from IPMA's feeds covering the past 30 days.
Supported areas:
```text
continent
azores
madeira
all
```
The optional `area` defaults to `all`, which combines the Azores feed (`3.json`) and the mainland/Madeira feed (`7.json`), removing duplicate events. Both `continent` and `madeira` select the **same combined mainland/Madeira feed**: IPMA does not provide separate feeds for them. Results state this coverage explicitly. If either request fails, `all` returns an error rather than an incomplete national result.
Example request:
```text
Show me recent seismic activity in the Azores.
```
### `get_locations`
Lists supported forecast locations with stable identifiers, district IDs and coordinates. Optional `query` and `districtId` parameters filter the catalogue.
### `get_weather_stations`
Returns up to 15 stations with available measurements at the latest hourly timestamp. Missing measurements (including IPMA's `-99` sentinel) are omitted. The response states how many stations are shown.
### `get_uv_forecast`
Returns UV index forecasts for up to three dates and ten locations per date, with risk categories and peak UV time intervals in UTC. The response states the display limits; missing UV values are identified as unavailable.
## Data Source
This project uses the public open-data services provided by [IPMA — Instituto Português do Mar e da Atmosfera](https://www.ipma.pt/).
API:
```text
https://api.ipma.pt/open-data/
```
No API key is required for the IPMA endpoints used by this project.
Endpoint formats and coverage are documented in the [IPMA API reference](https://api.ipma.pt/). Response labels are in English; place names and warning text supplied by IPMA retain their original language.
## Testing
```bash
npm run check
npm test
npm audit
```
Tests use Node.js's built-in runner, synthetic IPMA fixtures, local HTTP servers and the official MCP client. They cover contracts, location resolution, data selection, cache expiry, retries, cancellation, HTTP authentication/session isolation and stdio lifecycle without contacting IPMA. `npm run check` verifies types and syntax without emitting compiled files. `npm audit` requires registry access.
The [CI workflow](.github/workflows/ci.yml) runs installation, type/syntax checks and tests on Node.js 22 and 24 for pushes and pull requests. The Node.js 24 leg also validates Compose configuration, builds the image and checks MCP over container stdio without network access. The workflow can be started manually; it does not deploy the application. Live IPMA requests are excluded to keep CI independent of upstream availability.
Run `npm run test:live` for stdio, or `npm run test:live:http` for a temporary authenticated loopback HTTP server. Both check all six tools, each seismic area and forecasts selected by name and identifier against the live API. They require internet access and may fail when IPMA is unavailable.
To validate Docker locally, run `docker build -t ipma-mcp-server:validation .` followed by `npm run test:container`.
## Limitations
- Live data depends on IPMA availability and publication times. Only three reference catalogues are cached for up to one hour; there is no stale-data fallback or cache of forecasts, warnings, seismic events or observations.
- Each tool call has a 10-second overall deadline and each upstream response a 5 MiB limit. Transient failures may receive one retry within that deadline. Tool failures return `isError: true` and a structured error; invalid arguments use MCP protocol errors.
- Forecast, seismic, station and UV results have the limits described above. Timestamps are displayed in UTC.
- `smithery.yaml` is retained as legacy installation metadata. The supported setup is the local stdio configuration above; no current Smithery listing or hosted service is claimed.
- HTTP uses provisioned bearer credentials and in-memory sessions; it does not implement OAuth discovery, persistent sessions or multiple application replicas. Public use requires a configured HTTPS proxy and host.
The [architecture document](docs/architecture-roadmap.md) records the implemented evolution, its trade-offs and validation boundaries.
## Project Structure
```text
ipma-mcp-server/
├── .github/workflows/ci.yml
├── docs/
│ ├── images/mcp-inspector-braga.png
│ ├── architecture-roadmap.md
│ ├── data-contracts.md
│ ├── demo.md
│ ├── http.md
│ └── inspector.json
├── src/
│ ├── index.js
│ ├── http.js
│ ├── mcp/
│ ├── domain/
│ ├── ipma/
│ └── http/
├── test/
│ ├── server.test.js
│ ├── contracts.test.js
│ ├── resilience.test.js
│ └── http.test.js
├── scripts/
│ ├── smoke.mjs
│ └── container-smoke.mjs
├── examples/http-client.mjs
├── deploy/Caddyfile
├── compose.http.yaml
├── tsconfig.json
├── Dockerfile
├── LICENSE
├── package.json
├── package-lock.json
└── README.md
```
## License
This project is licensed under the [MIT License](LICENSE).
TDQS
Scored across 6 tools
Each tool has a clearly distinct purpose with no overlap: listing locations, seismic data, UV forecast, weather forecast, station observations, and weather warnings. The descriptions specify different data types and targets, making misselection unlikely.
All tools follow a consistent 'get_<resource>' naming pattern (e.g., get_locations, get_weather_forecast). This uniformity makes the tool set predictable and easy to understand for an agent.
With 6 tools, the server is well-scoped for weather and seismic data in Portugal. Each tool serves a specific function without redundancy, fitting the domain appropriately and avoiding bloat.
The tools cover key aspects like forecasts, warnings, stations, and seismic data, but there are minor gaps such as no historical weather data or detailed location-specific queries beyond forecasts. However, core workflows are well-supported.