Skip to main content
Glama
HumairaShaista

weather-learning-server

Weather MCP Learning

Ein progressives Lernprojekt, das den Weg von einer einfachen LLM-Anwendung zu Wetterfunktionen zeigt, die über das Model Context Protocol (MCP) bereitgestellt werden.

Lernfortschritt

  1. Einfache LLM-Anwendung — Chat mit einem lokalen Open-Source-Modell über Ollama

  2. Traditionelle Wetter-API-App — Open-Meteo-Client (Stufe 2A) + direkte LLM-Orchestrierung (Stufe 2B)

  3. Weather MCP Server — Wetter als MCP-Tools über stdio bereitstellen (Stufe 3)

  4. MCP-Client / Agent — Expliziter Tool-Client (Stufe 4A) + modellselektierte Tools (Stufe 4B)

Dieses Repository implementiert derzeit die Stufen 1 bis 4B.

Related MCP server: MCP Weather Data Fetcher

Voraussetzungen

  • Python 3.12 oder neuer

  • Ollama (oder ein beliebiger OpenAI-kompatibler lokaler Server)

  • Ein lokales Open-Source-Modell mit Tool-Aufruf (Standard: qwen2.5:7b)

Es wird kein OpenAI- oder Gemini-Konto benötigt.

Einrichtung

1. Ollama installieren und starten

Installieren von https://ollama.com, dann ein Modell pullen:

ollama pull qwen2.5:7b

Oder verwenden Sie ein beliebiges Responses-API-toolfähiges Modell, das Sie bereits haben (ollama list), und setzen Sie dann LLM_MODEL in .env auf diesen Namen.

Stellen Sie sicher, dass Ollama läuft (normalerweise automatisch unter macOS nach der Installation):

ollama list

2. Virtuelle Umgebung erstellen

python3 -m venv .venv
source .venv/bin/activate

Unter Windows:

python -m venv .venv
.venv\Scripts\activate

3. Abhängigkeiten installieren

pip install -e ".[dev]"

4. Umgebungsvariablen konfigurieren

cp .env.example .env

Standardeinstellungen in .env zielen auf lokales Ollama:

LLM_BASE_URL=http://localhost:11434/v1
LLM_API_KEY=ollama
LLM_MODEL=qwen2.5:7b
  • LLM_BASE_URL — OpenAI-kompatible API-URL (Ollamas Standard ist oben gezeigt; wird von Chat Completions und Responses verwendet)

  • LLM_API_KEY — von der Client-Bibliothek benötigt; Ollama ignoriert sie (jeder nicht-leere Wert funktioniert)

  • LLM_MODEL — lokaler Modellname aus ollama list (Stufe 4B Tool-Aufruf funktioniert gut mit qwen2.5:7b)

Andere Optionen: LM Studio, vLLM oder jeder Server, der die OpenAI-Chat-API spricht — ändern Sie einfach LLM_BASE_URL und LLM_MODEL.

Stufe 2A: Open-Meteo Wetter-Client

app/weather_client.py kommuniziert in zwei Schritten mit Open-Meteo (kein LLM, kein MCP):

  1. Geokodierung — GET https://geocoding-api.open-meteo.com/v1/search wandelt einen Stadtnamen (plus optionalem Bundesstaat/Region und Land) in Breitengrad, Längengrad, kanonischen Namen, Verwaltungsregion, Land und Zeitzone um.

  2. Vorhersage — GET https://api.open-meteo.com/v1/forecast verwendet diese Koordinaten, um das aktuelle Wetter abzurufen (Temperatur, Luftfeuchtigkeit, Wind, WMO-Wettercode).

Aufrufer erhalten typisierte Modelle (Location, CurrentWeather, WeatherResult), kein rohes Provider-JSON. Die WMO-Wettercode → Text-Übersetzung befindet sich an einer Stelle (WMO_WEATHER_CODES / weather_condition_from_code).

Beispiel (asynchron):

from app.weather_client import get_current_weather

result = await get_current_weather("Berlin")
print(result.location.name, result.current.temperature, result.current.condition)

Stufe 2B: Direkte Wetter- + LLM-Anwendung

app/direct_weather_app.py ist eine traditionelle LLM-App: Ihr Code entscheidet, wann die Wetter-API aufgerufen wird, und übergibt dieses Ergebnis dann an das LLM für eine freundliche Zusammenfassung.

User
  → direct_weather_app
      → Open-Meteo   (application-controlled)
      → LLM          (summarize only the supplied payload)
  → Response

So führen Sie es aus

Mit aktivierter virtueller Umgebung, laufendem Ollama und Netzwerkzugriff für Open-Meteo:

python -m app.direct_weather_app "San Francisco"

Optionale Disambiguierung:

python -m app.direct_weather_app "Springfield" --state Illinois --country US

Oder das Konsolenskript:

direct-weather "San Francisco"

Auf stderr sehen Sie die Orchestrierungsschritte:

  1. Anwendung hat Stadt empfangen

  2. Anwendung hat Wetteranbieter aufgerufen

  3. Anwendung hat strukturierte Wetterdaten empfangen

  4. Anwendung hat Wetterkontext an das LLM gesendet

Stdout zeigt den strukturierten Wetterblock, dann die LLM-Zusammenfassung.

Wie es sich von der einfachen LLM-Anwendung unterscheidet

Stufe 1 plain_llm_app

Stufe 2B direct_weather_app

Wetterdaten

Keine — Modell hat kein Live-Wetter

Zuerst von Open-Meteo abgerufen

Wer ruft Wetter auf?

Niemand

Anwendungscode (explizit)

LLM-Rolle

Beantwortet eine freie Eingabeaufforderung

Fasst eine autoritative Nutzlast zusammen

MCP / Tools

Nein

Nein

Wichtiger Lernpunkt: Das LLM entdeckt oder ruft keine Wetter-Tools auf. Die Anwendung orchestriert Open-Meteo und bittet dann das LLM, das Ergebnis zu formulieren. Die Eingabeaufforderung teilt dem Modell mit, dass die Nutzlast autoritativ ist und keine fehlenden Fakten erfunden werden sollen.

Stufe 3: Weather MCP Server

app/mcp_server.py stellt den vorhandenen weather_client als MCP-Tool bereit. Der Server bietet nur Fähigkeiten — er kommuniziert nicht mit einem LLM oder verwaltet eine Konversation.

Offizielle SDK-Version und verwendete API

In dieser Projektumgebung überprüft:

Element

Wert

Paket

offizielles mcp auf PyPI (modelcontextprotocol/python-sdk)

Installierte Version

2.0.0

Server-Klasse

MCPServer aus mcp.server

Nicht verwendet

Drittanbieterpaket fastmcp; älterer v1 FastMCP-Importpfad

from mcp.server import MCPServer

mcp = MCPServer("weather-learning-server")

Server-Verantwortlichkeiten

  • Tools an MCP-Clients bewerben (Tool-Erkennung)

  • Einen get_current_weather-Tool-Aufruf akzeptieren

  • An app.weather_client delegieren (kein duplizierter Open-Meteo-Code)

  • Eine strukturierte Wetter-Nutzlast zurückgeben (oder einen sicheren Tool-Fehler)

  • MCP über stdio für diesen lokalen Lern-POC sprechen

Bereitgestellter Tool-Vertrag: get_current_weather

Argumente

Name

Typ

Erforderlich

Beschreibung

city

string

ja

Stadt- oder Ortsname

state_or_region

string

nein

Bundesstaat / Verwaltungsregion zur Disambiguierung

country

string

nein

Ländername oder ISO-3166-1 Alpha-2-Code

Strukturierte Ergebnisfelder

resolved_location, region, country, latitude, longitude, temperature, apparent_temperature (wenn verfügbar), condition, wind_speed, observation_time, timezone, units

So starten Sie den Server

python -m app.mcp_server

Oder:

weather-mcp-server

Mit stdio wartet der Prozess auf einen MCP-Host auf stdin/stdout. Wenn Sie ihn allein in einem Terminal ausführen, sieht es „hängend“ aus — das ist erwartet.

Wie stdio-Transport funktioniert (konzeptionell)

MCP host / Inspector
   ├── spawns: python -m app.mcp_server
   ├── writes JSON-RPC MCP messages → server stdin
   └── reads JSON-RPC MCP messages  ← server stdout
  • Kein Port und kein HTTP für diesen POC

  • stdout ist der Protokolldraht (geben Sie dort keine normalen App-Ausgaben mit print() aus)

  • Logs gehören auf stderr

Unabhängiges Testen mit dem offiziellen MCP Inspector

Verifiziert gegen:

  • offizielles mcp 2.0.0 (MCPServer)

  • offizielles Inspector-Paket @modelcontextprotocol/inspector

  • Node.js 22.19+ (erforderlich durch aktuelle Inspector-Dokumentation)

  • Netzwerkzugriff auf Open-Meteo

Voraussetzungen

cd weather-mcp-learning
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"   # includes mcp[cli]

Bestätigen Sie Node/npx:

node --version   # need 22.19.0 or newer
npx --version

Wenn Ihr System-node/npx defekt oder zu alt ist, verwenden Sie ein aktuelles Node über nvm (oder gleichwertig) und stellen Sie sicher, dass npx zuerst in Ihrem PATH ist.

Option A — Web-UI über mcp dev (offizielles SDK-Hilfsprogramm)

Vom Projektstamm aus mit aktivierter venv (benötigt auch uv, da mcp dev den Server über uv run startet):

mcp dev app/mcp_server.py --with-editable .

Erwartet:

  1. Terminal gibt etwas aus wie MCP Inspector Web is up and running at: http://localhost:6274?MCP_INSPECTOR_API_TOKEN=...

  2. Browser öffnet den Inspector

  3. Inspector startet/verbindet sich mit dem lokalen stdio-Server (weather-learning-server)

  4. Sitzung initialisiert (Servername/Anweisungen erscheinen)

  5. Öffnen Sie Tools → Liste zeigt get_current_weather

  6. Wählen Sie das Tool → UI zeigt den Docstring/die Beschreibung und Eingabefelder aus dem Schema (city erforderlich; state_or_region / country optional)

  7. Setzen Sie city = San Francisco → Run Tool

  8. Ergebnisbereich zeigt strukturierten Inhalt wie resolved_location, region, temperature, condition, units usw.

--with-editable . installiert dieses Projekt in die temporäre Umgebung, die mcp dev erstellt, damit import app... funktioniert.

Option B — Web-UI über Inspector + Projektkonfiguration

mcp-inspector.json im Repository-Stammverzeichnis verweist den Inspector auf den lokalen stdio-Server:

npx -y @modelcontextprotocol/inspector --config ./mcp-inspector.json --server weather-learning-server

Öffnen Sie die gedruckte http://localhost:6274?...-URL, bestätigen Sie, dass die Sitzung verbunden ist, und verwenden Sie dann den Tools-Tab wie in Option A.

Option C — Skriptbare CLI-Prüfungen (kein Browser)

Diese sind nützlich, um dieselben Protokollschritte von einem Terminal aus zu beweisen. Führen Sie sie vom Projektstamm aus mit aktiver venv und einem funktionierenden Node 22.19+ npx im PATH aus:

# 1–2. Start/connect over stdio + initialize session
npx -y @modelcontextprotocol/inspector --cli \
  --config ./mcp-inspector.json \
  --server weather-learning-server \
  --method initialize \
  --format json

Erwartetes JSON enthält "name": "weather-learning-server" unter result.serverInfo.

# 3–4. List tools; confirm description + input schema
npx -y @modelcontextprotocol/inspector --cli \
  --config ./mcp-inspector.json \
  --server weather-learning-server \
  --method tools/list \
  --format json

Erwartet: ein Tool namens get_current_weather, mit inputSchema.required, das city enthält, und einer Live-/Aktuellwetter-Beschreibung.

# 5–6. Invoke with city = San Francisco; display structured result
npx -y @modelcontextprotocol/inspector --cli \
  --config ./mcp-inspector.json \
  --server weather-learning-server \
  --method tools/call \
  --tool-name get_current_weather \
  --tool-arg 'city=San Francisco' \
  --format json

Erwartet: "isError": false und structuredContent mit Feldern wie:

{
  "resolved_location": "San Francisco",
  "region": "California",
  "country": "United States",
  "latitude": 37.77493,
  "longitude": -122.41942,
  "temperature": 13.8,
  "apparent_temperature": 12.1,
  "condition": "Fog",
  "wind_speed": 19.1,
  "observation_time": "2026-08-12T22:45",
  "timezone": "America/Los_Angeles",
  "units": {
    "temperature": "°C",
    "wind_speed": "km/h",
    "apparent_temperature": "°C"
  }
}

Numerische Wetterwerte ändern sich im Laufe der Zeit; die Feldnamen und "isError": false sind das, was zählt.

Offizielle Inspector-Dokumentation: MCP Inspector · SDK-Ausführungsdokumentation: Running your server

Stufe 4A: Einfacher MCP-Client (expliziter Tool-Aufruf)

app/basic_mcp_client.py ist ein Nicht-LLM-MCP-Client. Er startet den lokalen Wetter-MCP-Server über stdio, entdeckt Tools und ruft dann explizit get_current_weather auf.

basic_mcp_client
    → list_tools
    → get_current_weather   (hardcoded by this app — not chosen by an LLM)
    → MCP server (app.mcp_server via stdio)
    → Open-Meteo

Wichtig: Dieser Client ruft das Wetter-Tool immer noch explizit auf. Das LLM hat das Tool noch nicht ausgewählt. Das kommt in einer späteren Stufe.

So führen Sie es aus

Mit aktivierter virtueller Umgebung (Sie müssen den MCP-Server nicht selbst starten — dieser Client erzeugt ihn):

python -m app.basic_mcp_client "San Francisco"

Optionale Filter:

python -m app.basic_mcp_client "Springfield" --state Illinois --country US

Oder:

basic-mcp-client "San Francisco"

Sie sollten sehen:

  1. Verbindungs-/Protokollinformationen für weather-learning-server

  2. Jedes entdeckte Tool mit Name, Beschreibung und Eingabeschema

  3. Einen expliziten Aufruf von get_current_weather

  4. Das strukturierte MCP-Tool-Ergebnis-JSON

Das Beenden des Prozesses bereinigt die MCP-Sitzung und den untergeordneten Serverprozess.

Stufe 4B: OpenAI Responses Agent (modellselektierte MCP-Tools)

app/mcp_agent.py verbindet sich mit dem Wetter-MCP-Server, entdeckt Tools zur Laufzeit, gibt diese Definitionen an das Modell über die offizielle OpenAI Responses API, führt alle vom Modell angeforderten Tool-Aufrufe über MCP aus, gibt Tool-Ergebnisse an das Modell zurück und gibt die endgültige Antwort aus.

user question
  → mcp_agent
      → MCP list_tools          (discovery)
      → OpenAI Responses API    (question + tool schemas)
      → model may request tool(s)
      → MCP tools/call          (only discovered names)
      → Responses function_call_output
      → final natural-language answer

Es gibt kein if "weather" in question, keine Stadt-Regex und keinen hartcodierten get_current_weather-Aufruf. Das Modell entscheidet, ob es ein Tool verwendet.

Agenten-Schleife (Detail)

  1. MCP-Sitzung starten — python -m app.mcp_server über stdio erzeugen; Client initialisieren

  2. Tool-Erkennung — list_tools; jeden Tool-Namen/jede Beschreibung protokollieren

  3. Schema-Übersetzung — MCP-Tools → Responses type: "function"-Tools

  4. Modell-Durchgang — client.responses.create(..., tools=..., tool_choice="auto")

  5. Ausgabe prüfen — wenn function_call-Elemente existieren:

    • Tool-Namen gegen den entdeckten Satz validieren

    • JSON-Argumente parsen/validieren

    • MCP aufrufen; strukturierte Ergebnisse bewahren

    • function_call_output mit previous_response_id einreichen

  6. Wiederholen, bis das Modell eine endgültige Textnachricht zurückgibt (oder maximale Iterationen erreicht)

  7. Endgültige Antwort ausgeben und die MCP-Sitzung/den untergeordneten Prozess schließen

So führen Sie es aus

ollama pull qwen2.5:7b   # once, if needed
source .venv/bin/activate
python -m app.mcp_agent "What is the current weather in San Francisco?"
python -m app.mcp_agent "Explain what dependency injection is."

Erwartet:

  • Wetterfrage → Logs zeigen model_requested_tools / tool_call für get_current_weather, dann eine Wetterantwort

  • Dependency-Injection-Frage → Logs zeigen eine endgültige Antwort ohne Tool-Aufrufe

Beobachten Sie stderr auf [mcp-agent]-Zeilen: Erkennung, Modellausgabetypen, Tool-Name/Argumente/Dauer/Ergebnis. API-Schlüssel werden nie protokolliert.

Ausführen der einfachen Anwendung

Mit aktivierter virtueller Umgebung und laufendem Ollama:

python -m app.plain_llm_app

Oder mit einer benutzerdefinierten Eingabeaufforderung:

python -m app.plain_llm_app "What is the Model Context Protocol in one sentence?"

Sie können auch das installierte Konsolenskript verwenden:

plain-llm "Hello!"

Ausführen von Tests

pytest

Projektstruktur

weather-mcp-learning/
  README.md
  .env.example
  .gitignore
  pyproject.toml
  mcp-inspector.json
  app/
    __init__.py
    config.py
    llm_client.py
    plain_llm_app.py
    weather_client.py
    direct_weather_app.py
    mcp_server.py
    basic_mcp_client.py
    mcp_agent.py
  tests/

Hinweise

  • Das offizielle openai Python-Paket wird als OpenAI-kompatibler Client verwendet (zuvor Chat Completions; Responses API in Stage 4B). Anfragen gehen an Ihre konfigurierte LLM_BASE_URL (standardmäßig Ollama).

  • Wetterabfragen verwenden Open-Meteo über httpx (app/weather_client.py).

  • Stage 2B (direct_weather_app.py) orchestriert explizit Wetter → LLM; kein MCP und kein Tool-Aufruf.

  • Stage 3 verwendet das offizielle mcp 2.0.0 SDK (MCPServer aus mcp.server) über stdio. Verwenden Sie nicht das Drittanbieter-Paket fastmcp.

  • Stage 4A (basic_mcp_client.py) ruft das Wetter-Tool weiterhin explizit auf (keine LLM-Tool-Auswahl).

  • Stage 4B (mcp_agent.py) lässt das Modell nach der MCP-Erkennung über die Responses API Tools auswählen.

Available Tools

1 tool
get_current_weatherGet current weatherA

Get live/current weather for a city.

This tool returns real-time current conditions from the Open-Meteo weather provider (not a forecast summary and not model-invented weather). Provide a city name; optionally add state_or_region and/or country when the city name is ambiguous. The response includes the resolved location, coordinates, temperature, condition, wind, observation time, timezone, and units.

ParametersJSON Schema
NameRequiredDescriptionDefault
cityYesCity or place name to look up (required).
countryNoOptional country name or ISO-3166-1 alpha-2 code (for example 'United States' or 'US').
state_or_regionNoOptional state or first-level administrative region used to disambiguate the city (for example 'California' or 'Illinois').

Output Schema

ParametersJSON Schema
NameRequiredDescription
unitsYes
regionNoAdministrative region / state when available
countryYesCountry name
latitudeYes
timezoneYes
conditionYesHuman-readable weather condition
longitudeYes
wind_speedNo
temperatureYes
observation_timeYesObservation timestamp from the provider
resolved_locationYesCanonical place name from geocoding
apparent_temperatureNoApparent (feels-like) temperature when the provider returns it

TDQS

A4.3/5.0
Behavior4/5

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

No annotations are provided, so the description carries the full burden. It discloses that data comes from Open-Meteo, that it's real-time (not forecast or invented), and lists the response fields. It does not mention rate limits or availability constraints, which would be helpful.

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?

The description is very concise: two sentences. The first sentence states the core purpose, and the second adds key details in a natural flow. No wasted words.

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?

Given the tool has an output schema, the description doesn't need to explain return values. It also covers the important semantic clarifications (real-time, provider, disambiguation hints). For a simple 3-param weather tool, this is 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 description coverage is 100%, so baseline is 3. The description restates that city is required and that state_or_region and country help disambiguate, but does not add new format or usage details 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?

The description clearly states 'Get live/current weather for a city' with specific verb and resource. It explicitly distinguishes itself from non-forecast and non-invented weather, and mentions the provider (Open-Meteo).

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?

The description explains when to use (for current real-time conditions) and notes when to add optional parameters for disambiguation. It doesn't explicitly state when NOT to use or list alternative tools, but context is clear enough.

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. 1 tool updatev0.1.0
    • First observedget_current_weather

TDQS

A3.9/5.0

Scored across 1 tool

Disambiguation5/5

With only one tool, there is no risk of confusion between tools. The tool's purpose is clearly defined and distinct by default.

Naming Consistency3/5

The single tool uses a clear verb_noun pattern (get_current_weather), but with only one tool, consistency cannot be meaningfully evaluated across a set.

Tool Count2/5

A server named 'weather-learning-server' with only one weather tool feels incomplete for learning purposes. A 'learning' server typically benefits from multiple tools (e.g., forecast, history, alerts) to cover educational use cases.

Completeness2/5

The server only provides current weather data, missing obvious complementary tools like forecasts, historical data, or weather alerts. This severely limits its usefulness for weather-related learning or applications.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers