weather-alert-mcp-v2
by rainygold25
README.md
# weather-alert-mcp v2 — one MCP tool, two implementations
An **MCP (Model Context Protocol) server** that exposes live U.S. National Weather Service
alerts as a callable tool, so any MCP client — Claude Desktop, Claude Code, or an SDK client
— can query active weather alerts by state.
Implemented **twice**: once in Python, once in TypeScript, against the same tool contract.
A client cannot tell which one it is talking to. That is the point of building against a
protocol rather than an API, and the two implementations are where the interesting parts of
MCP become visible.
> v1 (Python only) lives at
> [weather-alert-mcp](https://github.com/rainygold25/weather-alert-mcp) and is left
> untouched. This repo is the continuation.
## The tool
| Tool | Argument | Returns |
|---|---|---|
| `get_alerts` | `state` — two-letter US state code (e.g. `IL`) | Up to 5 active alerts: event, severity, affected area, headline |
Data source: `https://api.weather.gov/alerts/active` — public, no API key, no signup.
## The same contract, derived two ways
| | Python (`server.py`) | TypeScript (`ts/src/index.ts`) |
|---|---|---|
| Schema source | generated from type hints | generated from a `zod` schema |
| Argument validation | trusts the client's schema conformance | validates at the boundary, rejects before any HTTP call |
| Transport | stdio | stdio |
| Offline mode | `WX_MOCK=1` | `WX_MOCK=1` |
| Tool contract | `get_alerts(state)` | `get_alerts(state)` — identical |
Both derive the JSON Schema the client sees from the implementation rather than maintaining
it separately, so the contract cannot drift from the code.
The TypeScript server additionally validates at the protocol boundary. `{"state": "Illinois"}`
comes back as a protocol-level error **before any network request is made**, so a malformed
tool call costs nothing:
```
MCP error -32602: Input validation error: Invalid arguments for tool get_alerts
```
---
## Python
```bash
pip install -r requirements.txt
python server.py # speaks MCP over stdio; a client launches this
```
Verify — `test_client.py` is a real MCP client: it spawns the server as a subprocess,
completes the `initialize` handshake, lists the advertised tools, and calls one.
```bash
python test_client.py # live
WX_MOCK=1 python test_client.py # protocol only, no network
```
```
TOOLS: ['get_alerts']
DESC: Get active National Weather Service alerts for a US state.
SCHEMA: {'properties': {'state': {'title': 'State', 'type': 'string'}}, 'required': ['state'], ...}
RESULT for IL:
Severe Thunderstorm Warning (Severe) — Lake County, IL
Severe Thunderstorm Warning issued for Lake County until 7:15 PM CDT
```
## TypeScript
```bash
cd ts
npm install
npm run build
node build/index.js # speaks MCP over stdio
```
Verify — `ts/test-client.mjs` drives the same round trip and additionally asserts that a
malformed argument is rejected:
```bash
cd ts
WX_MOCK=1 node test-client.mjs # protocol only, no network
node test-client.mjs TX # live NWS data
```
```
TOOLS: [ 'get_alerts' ]
SCHEMA: {"type":"object","properties":{"state":{"type":"string","minLength":2,"maxLength":2,
"pattern":"^[A-Za-z]{2}$","description":"Two-letter US state code, e.g. \"IL\" or \"CA\""}},
"required":["state"],"additionalProperties":false}
RESULT:
Severe Thunderstorm Warning (Severe) — Lake County, IL
Severe Thunderstorm Warning issued for Lake County until 7:15 PM CDT
VALIDATION: rejected bad input as expected — MCP error -32602: Input validation error
```
See [`ts/README.md`](ts/README.md) for detail on the TypeScript implementation.
---
## Use from Claude Desktop
Add either (or both) to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"weather-alerts": {
"command": "python",
"args": ["/absolute/path/to/server.py"]
},
"weather-alerts-ts": {
"command": "node",
"args": ["/absolute/path/to/ts/build/index.js"]
}
}
}
```
Both register the same tool name, so run one at a time unless you want to compare them.
## Notes
- **`stdout` is the protocol channel.** Anything written there corrupts the JSON-RPC stream,
which is why startup logging goes to `stderr`.
- **Errors surface rather than being swallowed.** An upstream API failure is raised to the
client instead of returning "no alerts", which would be indistinguishable from a genuinely
quiet state.
- **`WX_MOCK=1` runs the full path with no network call** — useful in CI, and for separating
a protocol failure from an upstream API failure when something breaks.
- Alerts are truncated to the first 5 features to keep tool output inside a reasonable
context budget.
## Known limitations
- One read-only tool. No resources, no prompts, no sampling — the parts of MCP beyond tool
registration are not exercised here.
- stdio transport only; no HTTP/SSE transport.
- The NWS endpoint requires a `User-Agent`; it is set to a contact string in both
implementations, per the API's stated policy.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues