Skip to main content
Glama
narendrareddi

MCP Weather Agent

README.md
# MCP Weather Agent

An MCP (Model Context Protocol) server that turns a public REST API into
tools an AI agent can call directly — geocode a place name, then pull
current conditions or a multi-day forecast, with typed inputs and typed,
structured outputs instead of free text.

This is a small, self-contained example of the same pattern used to build
production agent-tool servers for enterprise systems: typed tool schemas,
input validation, retry/timeout handling on outbound calls, and structured
logging, so an agent's tool calls are predictable and debuggable.

## Why this exists

Most "AI agent" demos either hardcode a single API call or let the model
free-form parse HTML. Neither scales past a toy example. This project shows
the pattern that does: each capability is a small, independently testable
tool with a strict input/output contract, and the server itself knows
nothing about *how* an agent decides to call it — that separation is what
lets the same server work behind Claude Desktop, Claude Code, or a custom
LangGraph agent without changes.

## Architecture

```
Agent (Claude Desktop / Claude Code / LangGraph, etc.)
        │  MCP protocol (stdio transport)
        ▼
FastMCP server (server.py)
   ├─ geocode_location(location_name)      → GeocodeResponse
   ├─ get_current_weather(lat, lon)        → CurrentWeather
   └─ get_forecast(lat, lon, days)         → ForecastResponse
        │  validated params → httpx call w/ retry+timeout
        ▼
Open-Meteo REST API (geocoding + forecast, no API key required)
```

Each tool's return value is a Pydantic model, not a string — so a calling
agent (or a downstream function in a larger pipeline) can read
`result.temperature_c` directly instead of re-parsing prose.

## Design decisions & trade-offs

- **Open-Meteo over a keyed provider**: no API key means anyone cloning this
  repo can run it in under a minute. A production system would swap in
  whatever provider the business already pays for.
- **Structured Pydantic outputs over raw JSON passthrough**: costs a bit of
  mapping code per tool, but means malformed upstream responses fail loudly
  at the boundary instead of silently confusing the agent three steps later.
- **Bounded retries in `_get_json`, not a retry library**: for a 3-tool demo
  a dependency like `tenacity` is unnecessary weight; the same slot is where
  you'd add exponential backoff or circuit-breaking for a heavier-traffic
  service.
- **stdio transport by default**: simplest to run locally via Claude
  Desktop/Claude Code. Swapping to Streamable HTTP (see `mcp.server.fastmcp`
  docs) is a one-line change to `mcp.run(transport=...)` when you need a
  server other machines can call.

## Running it

```bash
python -m venv .venv
source .venv/bin/activate          # .venv\Scripts\activate on Windows
pip install -e ".[dev]"

pytest                              # run the offline unit test suite
python -m mcp_weather_agent.server  # run the server over stdio
```

### Connecting it to Claude Desktop or Claude Code

Add to your MCP config (see `examples/claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "weather-agent": {
      "command": "python",
      "args": ["-m", "mcp_weather_agent.server"],
      "cwd": "/absolute/path/to/mcp-weather-agent"
    }
  }
}
```

Restart the client, and the three tools (`geocode_location`,
`get_current_weather`, `get_forecast`) become available for the agent to call.

## Tools

| Tool | Input | Output |
|---|---|---|
| `geocode_location` | `location_name: str`, `max_results: int` | Ranked list of name/country/lat/lon candidates |
| `get_current_weather` | `latitude: float`, `longitude: float` | Current temperature, apparent temp, wind, precipitation |
| `get_forecast` | `latitude: float`, `longitude: float`, `days: int` | Daily high/low/precipitation for up to 16 days |

## Testing

`tests/test_server.py` monkeypatches the HTTP layer so the suite runs fully
offline and fast — useful for CI, and for making sure tool-shape regressions
(a renamed field, a missing key) get caught before an agent ever sees them.

## Possible extensions

- Swap stdio for Streamable HTTP transport and deploy behind auth for
  multi-client access.
- Add a `severe_weather_alerts` tool against a provider that supports it.
- Add response caching (short TTL) to cut duplicate calls when an agent
  re-checks the same location across a multi-step plan.

## License

MIT — see `LICENSE`.

TDQS

A4.2/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: geocoding a place name, retrieving current conditions, and retrieving a forecast. There is no meaningful overlap between geocode_location and the weather retrieval tools, and current vs. forecast are well differentiated by their descriptions.

Naming Consistency5/5

All tool names use lowercase snake_case with a verb_noun style: geocode_location, get_current_weather, get_forecast. The two retrieval tools follow a uniform get_* pattern, and geocode_location fits the same verb-first convention.

Tool Count5/5

Three tools is an appropriate, well-scoped size for a weather agent. Each tool covers a necessary step in the core workflow: resolve location, get current conditions, get forecast, with no redundancy.

Completeness4/5

The core weather lookup workflow is complete: geocode a place, then retrieve current or forecast weather. Minor gaps such as lack of alerts, historical data, or reverse geocoding are not essential for the stated purpose.

Maintenance

ActivitySlowing
ResponsivenessNo issues