Skip to main content
Glama
HumairaShaista

weather-learning-server

Weather MCP 学習

段階的に学べるプロジェクトで、プレーンな LLM アプリケーションから Model Context Protocol (MCP) を通じて天気機能を公開するまでの道筋を示します。

学習の段階

  1. プレーンな LLM アプリケーション — Ollama 経由でローカルのオープンソースモデルとチャット

  2. 従来の天気 API アプリ — Open-Meteo クライアント(ステージ 2A)+ 直接 LLM オーケストレーション(ステージ 2B)

  3. Weather MCP サーバー — 天気を MCP ツールとして stdio 経由で公開(ステージ 3)

  4. MCP クライアント / エージェント — 明示的なツールクライアント(ステージ 4A)+ モデルが選択するツール(ステージ 4B)

このリポジトリは現在 ステージ 1 から 4B まで を実装しています。

Related MCP server: MCP Weather Server Demo

必要条件

  • Python 3.12 以降

  • Ollama(または OpenAI 互換のローカルサーバー)

  • ツール呼び出しに対応したローカルのオープンソースモデル(デフォルト: qwen2.5:7b

OpenAI や Gemini のアカウントは不要です。

セットアップ

1. Ollama のインストールと起動

https://ollama.com からインストールし、モデルをプルします:

ollama pull qwen2.5:7b

または、すでに持っているツール対応モデル(ollama list)を使用し、.envLLM_MODEL にその名前を設定します。

Ollama が実行中であることを確認します(macOS では通常インストール後に自動起動します):

ollama list

2. 仮想環境の作成

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

Windows の場合:

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

3. 依存関係のインストール

pip install -e ".[dev]"

4. 環境変数の設定

cp .env.example .env

.env のデフォルトはローカルの Ollama を対象としています:

LLM_BASE_URL=http://localhost:11434/v1
LLM_API_KEY=ollama
LLM_MODEL=qwen2.5:7b
  • LLM_BASE_URL — OpenAI 互換の API URL(上記は Ollama のデフォルト。Chat Completions と Responses の両方で使用)

  • LLM_API_KEY — クライアントライブラリで必要。Ollama は無視します(空でない値なら何でも可)

  • LLM_MODELollama list で表示されるローカルモデル名(ステージ 4B のツール呼び出しは qwen2.5:7b で良好に動作)

その他のオプション: LM Studio、vLLM、または OpenAI チャット API を話す任意のサーバー — LLM_BASE_URLLLM_MODEL を変更するだけです。

ステージ 2A: Open-Meteo 天気クライアント

app/weather_client.py は 2 段階で Open-Meteo と通信します(LLM も MCP もなし):

  1. ジオコーディングGET https://geocoding-api.open-meteo.com/v1/search で都市名(オプションで州/地域と国)を緯度、経度、正式名称、行政地域、国、タイムゾーンに変換します。

  2. 予報GET https://api.open-meteo.com/v1/forecast でその座標を使用して 現在の 天気(気温、湿度、風、WMO 天気コード)を取得します。

呼び出し元は、生のプロバイダ JSON ではなく、型付けされたモデル(LocationCurrentWeatherWeatherResult)を受け取ります。WMO 天気コードからテキストへの変換は一箇所(WMO_WEATHER_CODES / weather_condition_from_code)にあります。

非同期の例:

from app.weather_client import get_current_weather

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

ステージ 2B: 直接天気 + LLM アプリケーション

app/direct_weather_app.py従来の LLM アプリです: あなたのコード が天気 API を呼び出すタイミングを決定し、その結果を LLM に渡して親しみやすい要約を生成します。

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

実行方法

仮想環境を有効にし、Ollama を実行し、Open-Meteo へのネットワークアクセスがある状態で:

python -m app.direct_weather_app "San Francisco"

オプションの曖昧性解消:

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

またはコンソールスクリプト:

direct-weather "San Francisco"

stderr にオーケストレーションの手順が表示されます:

  1. アプリケーションが都市を受け取った

  2. アプリケーションが天気プロバイダを呼び出した

  3. アプリケーションが構造化された天気データを受け取った

  4. アプリケーションが天気コンテキストを LLM に送信した

stdout には構造化された天気ブロック、次に LLM の要約が表示されます。

プレーンな LLM アプリケーションとの違い

ステージ 1 plain_llm_app

ステージ 2B direct_weather_app

天気データ

なし — モデルはライブ天気を持たない

最初に Open-Meteo から取得

誰が天気を呼ぶか?

誰も呼ばない

アプリケーションコード(明示的)

LLM の役割

自由形式のプロンプトに答える

信頼できるペイロードを要約する

MCP / ツール

なし

なし

重要な学習ポイント: LLM は天気ツールを 発見したり呼び出したりしません。アプリケーションが Open-Meteo をオーケストレーションし、LLM に結果を言い換えるよう依頼します。プロンプトは、ペイロードが信頼できるものであり、不足している事実を捏造しないようにモデルに指示します。

ステージ 3: Weather MCP サーバー

app/mcp_server.py は既存の weather_client を MCP ツール として公開します。サーバーは機能のみを提供し、LLM と通信したり会話を管理したりしません。

使用している公式 SDK バージョンと API

このプロジェクト環境で確認:

項目

パッケージ

公式 mcp on PyPI (modelcontextprotocol/python-sdk)

インストール版

2.0.0

サーバークラス

mcp.serverMCPServer

未使用

サードパーティの fastmcp パッケージ; 古い v1 の FastMCP インポートパス

from mcp.server import MCPServer

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

サーバーの責務

  • MCP クライアントにツールを通知する(ツール発見)

  • get_current_weather ツール呼び出しを受け付ける

  • app.weather_client に委譲する(Open-Meteo コードの重複なし)

  • 構造化された天気ペイロード(または安全なツールエラー)を返す

  • このローカル学習 POC では stdio 経由で MCP を話す

公開ツール契約: get_current_weather

引数

名前

必須

説明

city

string

はい

都市または場所の名前

state_or_region

string

いいえ

曖昧性解消のための州/行政地域

country

string

いいえ

国名または ISO-3166-1 alpha-2 コード

構造化結果フィールド

resolved_locationregioncountrylatitudelongitudetemperatureapparent_temperature(利用可能な場合)、conditionwind_speedobservation_timetimezoneunits

サーバーの起動方法

python -m app.mcp_server

または:

weather-mcp-server

stdio を使用する場合、プロセスは stdin/stdout で MCP ホストを待機します。単独でターミナルで実行すると「ハング」しているように見えますが、それは想定内です。

stdio トランスポートの仕組み(概念)

MCP host / Inspector
   ├── spawns: python -m app.mcp_server
   ├── writes JSON-RPC MCP messages → server stdin
   └── reads JSON-RPC MCP messages  ← server stdout
  • この POC ではポートも HTTP もなし

  • stdout はプロトコルワイヤ(通常のアプリ出力を print() してはいけない)

  • ログは stderr に出力

公式 MCP Inspector を使用した独立テスト

以下に対して検証済み:

  • 公式 mcp 2.0.0 (MCPServer)

  • 公式 Inspector パッケージ @modelcontextprotocol/inspector

  • Node.js 22.19+(現在の Inspector ドキュメントで必要)

  • Open-Meteo へのネットワークアクセス

前提条件

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

Node/npx を確認:

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

システムの node/npx が壊れているか古すぎる場合は、nvm(または同等のもの)で最新の Node を使用し、npxPATH の最初にあることを確認してください。

オプション A — mcp dev による Web UI(公式 SDK ヘルパー)

venv がアクティブなプロジェクトルートから(uv も必要。mcp devuv run でサーバーを起動するため):

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

期待される動作:

  1. ターミナルに MCP Inspector Web is up and running at: http://localhost:6274?MCP_INSPECTOR_API_TOKEN=... のようなメッセージが表示される

  2. ブラウザで Inspector が開く

  3. Inspector がローカルの stdio サーバー(weather-learning-server)に接続する

  4. セッションが初期化される(サーバー名/説明が表示される)

  5. Tools を開く → リストに get_current_weather が表示される

  6. ツールを選択 → UI に docstring/説明とスキーマからの入力フィールド(city 必須; state_or_region / country オプション)が表示される

  7. city = San Francisco に設定 → Run Tool

  8. 結果ペインに resolved_locationregiontemperatureconditionunits などの構造化コンテンツが表示される

--with-editable . は、mcp dev が構築する一時環境にこのプロジェクトをインストールし、import app... が動作するようにします。

オプション B — Inspector + プロジェクト設定による Web UI

リポジトリルートの mcp-inspector.json は、Inspector をローカルの stdio サーバーに向けます:

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

表示された http://localhost:6274?... URL を開き、セッションが接続されていることを確認し、オプション A と同様に Tools タブを使用します。

オプション C — スクリプト可能な CLI チェック(ブラウザ不要)

これらは、ターミナルから同じプロトコル手順を証明するのに便利です。venv がアクティブで、動作する Node 22.19+ の npxPATH にあるプロジェクトルートから実行:

# 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

期待される JSON には "name": "weather-learning-server"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

期待される: get_current_weather という名前のツールが 1 つ、inputSchema.requiredcity が含まれ、ライブ/現在の天気の説明があること。

# 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

期待される: "isError": false と、次のようなフィールドを持つ structuredContent:

{
  "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"
  }
}

数値の天気値は時間とともに変化します。重要なのはフィールド名と "isError": false です。

公式 Inspector ドキュメント: MCP Inspector · SDK 実行ドキュメント: Running your server

ステージ 4A: 基本 MCP クライアント(明示的なツール呼び出し)

app/basic_mcp_client.pyLLM なしの MCP クライアントです。ローカルの天気 MCP サーバーを stdio 経由で起動し、ツールを発見し、明示的に get_current_weather を呼び出します。

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

重要: このクライアントは依然として天気ツールを 明示的に 呼び出します。LLM はまだツールを選択していません。それは後のステージで行われます。

実行方法

仮想環境がアクティブな状態で(MCP サーバーを自分で起動する必要はありません — このクライアントが起動します):

python -m app.basic_mcp_client "San Francisco"

オプションのフィルター:

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

または:

basic-mcp-client "San Francisco"

次のものが表示されるはずです:

  1. weather-learning-server の接続/プロトコル情報

  2. 発見された各ツールの名前、説明、入力スキーマ

  3. get_current_weather への明示的な呼び出し

  4. 構造化された MCP ツール結果 JSON

プロセスを終了すると、MCP セッションと子サーバープロセスがクリーンアップされます。

ステージ 4B: OpenAI Responses エージェント(モデル選択型 MCP ツール)

app/mcp_agent.py は天気 MCP サーバーに接続し、実行時にツールを 発見 し、その定義を公式の OpenAI Responses API を通じてモデルに渡し、モデルが要求したツール呼び出しを MCP 経由で実行し、ツール結果をモデルに返し、最終的な回答を出力します。

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

if "weather" in question も、都市の正規表現も、ハードコードされた get_current_weather 呼び出しも ありません。ツールを使用するかどうかは モデル が選択します。

エージェントループ(詳細)

  1. MCP セッション開始python -m app.mcp_server を stdio 経由で起動; クライアントを初期化

  2. ツール発見list_tools; 各ツールの名前/説明をログ出力

  3. スキーマ変換 — MCP ツール → Responses の type: "function" ツール

  4. モデルターンclient.responses.create(..., tools=..., tool_choice="auto")

  5. 出力検査function_call アイテムが存在する場合:

    • ツール名を発見済みセットに対して検証

    • JSON 引数をパース/検証

    • MCP を呼び出し; 構造化結果を保持

    • previous_response_id を指定して function_call_output を送信

  6. 繰り返し — モデルが最終テキストメッセージを返すまで(または最大反復回数に達するまで)

  7. 最終回答を出力 し、MCP セッション/子プロセスを閉じる

実行方法

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."

期待される動作:

  • 天気に関する質問 → ログに model_requested_tools / tool_call for get_current_weather が表示され、天気の回答が得られる

  • 依存性注入に関する質問 → ログにツール呼び出し なし の最終応答が表示される

stderr で [mcp-agent] 行を確認: 発見、モデル出力タイプ、ツール名/引数/所要時間/結果。API キーは決してログに記録されません。

プレーンアプリケーションの実行

仮想環境がアクティブで Ollama が実行中の場合:

python -m app.plain_llm_app

またはカスタムプロンプトで:

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

インストール済みのコンソールスクリプトも使用できます:

plain-llm "Hello!"

テストの実行

pytest

プロジェクト構成

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/

注意事項

  • 公式のopenai Pythonパッケージは、OpenAI互換のクライアントとして使用されます(初期はChat Completions、Stage 4BではResponses API)。リクエストは設定されたLLM_BASE_URL(デフォルトはOllama)に送信されます。

  • 天気の検索には、httpxを介したOpen-Meteoを使用します(app/weather_client.py)。

  • Stage 2B(direct_weather_app.py)は、天気→LLMの流れを明示的にオーケストレーションします。MCPやツール呼び出しはありません。

  • Stage 3では、公式のmcp 2.0.0 SDK(mcp.serverMCPServer)をstdio経由で使用します。サードパーティのfastmcpパッケージは使用しないでください。

  • Stage 4A(basic_mcp_client.py)では、依然として天気ツールを明示的に呼び出します(LLMによるツール選択はありません)。

  • Stage 4B(mcp_agent.py)では、Responses APIを介したMCPディスカバリ後に、モデルがツールを選択できるようにします。

Install Server
F
license - not found
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • OpenWeather MCP — wraps the OpenWeatherMap API (openweathermap.org)

  • Open-Meteo MCP — weather forecast + historical reanalysis + sister APIs

  • WeatherAPI.com MCP — wraps WeatherAPI.com (api.weatherapi.com)

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/HumairaShaista/Weather-MCP-Learning'

If you have feedback or need assistance with the MCP directory API, please join our Discord server