Skip to main content
Glama
thiagoamaro91

mcp-weather-server

mcp-weather-server

A small, tested Model Context Protocol server that connects Claude to a public REST API, here Open-Meteo (free, no API key). Ask Claude "Do I need an umbrella in Lisbon this weekend?" and it calls these tools instead of guessing.

It is deliberately small: one HTTP client module, one server module, typed results, and a test suite that runs offline in about a second. The same shape works for any REST API, database or SaaS tool.

Tools

Tool

Arguments

Returns

get_current

city

Temperature, feels-like, humidity, wind, precipitation, condition

get_forecast

city, days (1-16, default 3)

Daily min/max, rain chance and amount, max wind, condition

compare_cities

cities (2-5 names)

Current weather for each, plus warmest, coldest and the spread

  • City names can carry a country code to disambiguate: "Springfield, US".

  • Every tool is marked read-only and returns structured JSON with an output schema, so Claude (or any MCP client) gets typed data, not just text.

  • Units: Celsius, km/h, mm.

Related MCP server: hevy-mcp

What makes it production-shaped

  • Input validation in the tool schema (Claude sees the limits) and again in code (empty or oversized city, days out of range). Bad input is rejected before any HTTP call.

  • Clear errors. Unknown city, upstream 4xx/5xx, timeouts and non-JSON bodies all come back to Claude as a readable tool error ("No place called 'Atlantis' found. Check the spelling, or add a two-letter country code..."), never a stack trace.

  • Timeouts on every request (5 s connect, 10 s read).

  • Response cache: place lookups for 24 hours, weather for 10 minutes, so repeated questions do not hammer the API.

  • Tests with no network and no key. HTTP is faked with httpx.MockTransport, a guard fails any test that tries to open a real socket, and the tools are exercised through a real MCP client session, plus one test that boots the actual stdio entry point.

Quick start

Requires Python 3.10+ and uv.

git clone <this repo> mcp-weather-server
cd mcp-weather-server
uv sync
uv run weather-mcp        # starts the stdio server; Ctrl+C to stop

Without uv: python -m venv .venv && .venv/bin/pip install -e ".[dev]", then .venv/bin/weather-mcp.

Use it from Claude Code

claude mcp add weather -- uv --directory /absolute/path/to/mcp-weather-server run weather-mcp

Then ask: "What's the 5-day forecast for Oslo?" (claude mcp list shows it as connected.)

Use it from Claude Desktop

Add this to claude_desktop_config.json (Settings > Developer > Edit Config) and restart Claude Desktop:

{
  "mcpServers": {
    "weather": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/mcp-weather-server", "run", "weather-mcp"]
    }
  }
}

Run the tests

uv run pytest -q

or, in any environment with the dependencies installed, python -m pytest -q. The pytest config puts src/ on the path, so no install step is needed for the tests themselves. No network access or API key is used.

Layout

src/weather_mcp/
  client.py         # the only file that knows about HTTP: Open-Meteo calls, errors, cache use
  server.py         # MCP tool definitions, validation, error mapping, stdio entry point
  models.py         # typed results (pydantic) that become the tools' output schemas
  cache.py          # tiny TTL cache with an injectable clock
  weather_codes.py  # WMO weather code -> plain-language condition
tests/
  conftest.py       # fake Open-Meteo, fake clock, no-network guard
  test_client.py    # parsing, errors, validation, caching
  test_server.py    # every tool through a real MCP client session, plus a stdio boot test

How I'd adapt this to your API

The design keeps the API-specific part in one file so the rest carries over unchanged:

  1. Swap client.py for a client of your API (REST, GraphQL, a database driver, a SaaS SDK). Keep the same pattern: async calls, timeouts, auth from an environment variable (never hard-coded), and a small set of named exceptions for "not found", "bad input" and "upstream failed".

  2. Define the tools around what your users ask, not around your endpoints. Typically three to six tools with tight argument schemas and typed results in models.py. Write actions (create, update) get explicit confirmation-friendly arguments and are marked as such.

  3. Keep the tests' shape: a fake of your API behind httpx.MockTransport (or a throwaway SQLite database), unit tests for the client, and end-to-end tests that call each tool through an MCP client session. They run in CI without credentials.

  4. Ship the config snippet for Claude Desktop and Claude Code, as above, with the environment variables your API needs.

Built with

Python, the official MCP Python SDK (mcp 2.x, MCPServer), httpx and pydantic. Built with Claude Code.

License

MIT, see LICENSE.

Available Tools

3 tools
compare_citiesCompare citiesA
Read-onlyIdempotent

Current weather side by side for 2-5 cities, with the warmest and coldest named.

NameRequiredDescriptionDefault
citiesYesTwo to five city names

Output Schema

NameRequiredDescription
citiesYes
coldestYes
warmestYes
spread_cYesWarmest minus coldest current temperature

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, open-world, and idempotent behavior, so the description only needs added context. It usefully discloses that results are presented side by side and that the warmest and coldest cities are named, though it does not describe failure behavior for invalid cities.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single efficient sentence with the key scope and output framing front-loaded. Every phrase contributes useful information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only comparison tool, the description covers purpose, input range, and notable output behavior. Output schema, parameter schema, and annotations already supply the remaining structured details.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the cities parameter already documents the 2-5 item constraint. The description reinforces the same range but adds no new format or syntax guidance beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action and resource: current weather compared side by side for 2-5 cities. The multi-city comparison scope clearly distinguishes it from single-current and forecast siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Strong implied usage for comparing current weather across multiple cities, with the 2-5 city range making the applicable scenario clear. It does not explicitly say when to choose this over get_current or get_forecast, so it stops short of full alternative guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_currentCurrent weatherA
Read-onlyIdempotent

Current conditions for a city: temperature, feels-like, humidity, wind, precipitation.

NameRequiredDescriptionDefault
cityYesCity name, optionally with a country code, e.g. 'Paris' or 'Paris, US'

Output Schema

NameRequiredDescription
locationYes
conditionYesPlain-language description of the WMO weather code
observed_atYesLocal time of the observation (ISO 8601)
feels_like_cNo
humidity_pctNo
temperature_cYes
wind_speed_kmhNo
precipitation_mmNo

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and openWorldHint, so the safety and idempotency profile is covered. The description adds only the returned field set, which duplicates the output schema, and says nothing about freshness, caching, units, or failure behavior for unknown cities.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One front-loaded sentence with no filler and the key distinction ('current') placed first. The trailing field list is somewhat redundant with the output schema but stays compact.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

A single-parameter, read-only lookup with an output schema and full annotation coverage needs little prose, and the description covers purpose and scope. Only ambiguity about data freshness and invalid-city handling keeps it short of complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single 'city' parameter already documents the 'Paris' / 'Paris, US' format. The description contributes no additional meaning about the parameter, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific retrieve action ('Current conditions') on a specific resource ('a city') plus the field set returned. The 'current' vs. 'forecast' distinction implicitly separates it from get_forecast, but no sibling is named explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: 'Current conditions' signals this is the now-snapshot tool versus get_forecast, and nothing is said about when to prefer compare_cities. No explicit when-to-use or when-not-to-use guidance is given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_forecastDaily forecastA
Read-onlyIdempotent

Daily forecast for a city: min/max temperature, rain chance and amount, max wind.

NameRequiredDescriptionDefault
cityYesCity name, optionally with a country code, e.g. 'Paris' or 'Paris, US'
daysNoNumber of days, 1 to 16

Output Schema

NameRequiredDescription
daysYes
locationYes

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint and idempotentHint, so the safety profile is covered and the description is not required to restate it. The description does add value by naming the specific payload fields (temperature range, rain probability and amount, max wind). It says nothing, though, about how many days are returned or how the 'days' horizon affects the result.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single dense sentence that front-loads the resource and then enumerates outputs in priority order. Every clause conveys information; nothing is padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values needn't be described, and annotations cover safety. The remaining gap is the forecast horizon: the description never mentions that a multi-day range (up to 16 days) can be requested, so an agent could reasonably read this as a single-day tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, including the 'Paris' / 'Paris, US' city format and the 1-16 day range, so the baseline of 3 applies. The description adds no parameter-level meaning beyond the schema and, in fact, its singular 'Daily forecast' framing is slightly out of step with the multi-day 'days' parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Daily forecast for a city') and enumerates the returned measurements (min/max temperature, rain chance and amount, max wind), which makes it distinguishable from get_current by implication. It never names the siblings get_current or compare_cities, however, so the differentiation is inferential rather than explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied by the phrase 'Daily forecast for a city'; there is no statement of when to prefer this over get_current (current conditions) or compare_cities. No prerequisites, exclusions, or notes about forecast horizon are given, leaving the agent to infer routing from the tool name alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.1.0
    • First observedcompare_cities
    • First observedget_current
    • First observedget_forecast

TDQS

A3.9/5.0

Scored across 3 tools

Disambiguation4/5

Each tool targets a distinct temporal or comparative view (current, forecast, multi-city comparison), and descriptions make the boundaries explicit. compare_cities partially overlaps with get_current applied to several cities, but the added ranking output justifies its separate existence.

Naming Consistency5/5

All three tools follow the same snake_case verb_noun pattern (get_current, get_forecast, compare_cities). The verbs are accurate and predictable, so an agent can guess a tool's intent from its name.

Tool Count4/5

Three tools is on the lean side, but each covers a genuinely distinct weather-query pattern and nothing feels redundant. It sits at the low edge of a well-scoped surface rather than being thin to the point of uselessness.

Completeness4/5

The core weather workflows (current conditions, daily outlook, multi-city comparison) are covered with no dead ends. Gaps exist around hourly breakdowns, historical data, alerts, and city/geocoding lookup, but agents can work around these for typical queries.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    D
    maintenance
    Exposes the Timely.mn v3 time-attendance API as MCP tools for Claude and other clients, allowing queries for company-wide attendance, employee profiles, and attendance reports.
    4
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Exposes the Hevy workout API to Claude, enabling users to manage workouts, routines, exercise templates, body measurements, and user info via natural language.
    3,367 npm
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables Claude, Cursor, or any MCP client to query your own recovery scores, sleep, strain cycles, workouts, profile, and body measurements through every WHOOP API v2 read endpoint. Tools return records exactly as WHOOP sends them, with paging and date-range filtering, and refresh tokens automatically after a one-time login.
    11
    3 npm
    1
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Exposes five tools that let Claude query training data from the intervals.icu API directly, covering weekly volume, fitness/fatigue/form, recent activities with per-rep detail, wellness metrics, and pace-at-heart-rate trends, with in-memory caching of upstream responses.
    -