Skip to main content
Glama
borovkov-d

BuildWindow

by borovkov-d

BuildWindow

MCP ラボプロジェクト:エージェントが 2 つの MCP サーバーを使用して、実際の天気予報に対して建設作業を計画します。

これは KSE AI Agentic School のコース課題です(MCP 統合課題):実際のドメイン問題に対するカスタム MCP サーバーを構築し、それを既存のサードパーティ MCP サーバーとともに、両方を一緒に使用して単一のツールではできないことを行うエージェントに接続します。

概要

BuildWindow は、具体的なスケジューリング問題を中心に構築された MCP(Model Context Protocol)ラボプロジェクトです:依存関係を持つ建設作業のリストと都市の天気予報が与えられたとき、両方を尊重するスケジュールを生成します。この計画を実行するエージェントは、同時に 2 つの別々の MCP 接続を保持します。1 つ目は、外部の Go ベースの OpenWeather MCP サーバー(github.com/mschneider82/mcp-openweather)で、エージェントは実行ごとに 1 回呼び出して、要求された都市の現在のライブ状況と 5 日間の予報を取得します — これはプロジェクト全体でネットワーク呼び出しが発生する唯一の場所です。2 つ目は、このリポジトリ独自の BuildWindow MCP サーバーです:実行時にネットワーク呼び出しを行わない完全に決定論的なローカルサーバーで、建設作業の種類とその気象制限のローカル JSON データセットに基づいており、建設ドメインのルールをエンコードする 4 つのツール(気象適合性の判定、養生時間の推定、複数作業のスケジューリング)を公開します。

2 つのサーバーは意図的に責任範囲が重複していません。OpenWeather MCP は、日々変化するもの — つまり天気そのもの — の唯一の情報源です。BuildWindow MCP は、代わりに固定ルールであるすべてのものを所有します:特定の作業タイプが許容する温度、風、湿度、降水量、特定の温度でコンクリートの養生にかかる時間、および複数の依存する作業を複数日の予報全体で最も早い禁止されていないウィンドウに配置する方法。BuildWindow サーバーは、公式の Python MCP SDK(パッケージ mcp、v2.0.0+)を使用して構築され、その MCPServer クラスを使用します — このクラスは古い SDK バージョンでは FastMCP という名前で、SDK v2.0.0 以降で MCPServer に改名されたことに注意してください。両方の接続を駆動するエージェントは、Claude Agent SDK(PyPI の claude-agent-sdk)で構築されています。

スケジュールに重要な OpenWeather 呼び出しは、意図的に LLM によって行われません。上流ツールの実際の出力(ソースを読んで確認済み — docs/tool-contracts.md を参照)は JSON ではなくプレーンテキストのレポートであり、あらゆる失敗(キーが不正、都市が認識されない、プロバイダーに到達できない)に対して与える唯一のシグナルは、構文的には成功しているが空の応答です — 反応すべきエラーテキストはありません。したがって、agent/main.py は低レベル MCP クライアントを介して直接呼び出し、小さな単体テスト済みの関数(agent/normalize.py)で解析し、その後で初めて LLM セッションを開始します — モデルには生のプロバイダーテキストを解釈させる代わりに、すでにクリーンな日別の数値を渡します。LLM セッションは両方の MCP サーバーに接続されており(get_mcp_status() の検出で両方の接続が表示されます)、モデルは実際に天気ツール自体を呼び出すことが許可されています(allowed_tools に明示的にリストされています)— ただし、システムプロンプトに従って、最終レポートの現在の状況に関する 1 文のみです。plan_work_schedule を駆動する日別予報は常にセッション前の決定論的フェッチから取得され、モデル自身の呼び出しからは決して取得されません。両方のサーバーはエージェント自身のフローで実際に使用されており、単に見えるだけではありません。

engineer input (city + work list)
  -> agent/main.py calls OpenWeather MCP directly (not via the LLM) for
     the schedule-critical daily forecast
  -> agent/normalize.py parses the plain-text response into daily figures
  -> (if no usable forecast: report plainly, stop -- no LLM session started)
  -> LLM session starts, connected to BOTH MCP servers; may itself call
     the weather tool once for current-conditions color commentary only
  -> given the daily forecast + works as plain JSON (the only input that
     ever drives scheduling)
  -> BuildWindow MCP  (plan_work_schedule, validate_work_window,
     estimate_curing_time, ...)
  -> schedule + explanation

Related MCP server: Weather MCP Server

前提条件

  • Python 3.12+ — このリポジトリは 3.12.3 で構築およびテストされました。

  • uv — このプロジェクトの依存関係マネージャーとして使用されます。

  • Go 1.24+ — OpenWeather MCP サーバーを自分でビルドする場合にのみ必要です(ここでは winget install --id GoLang.Go でインストール、現在は Go 1.26.7)。BuildWindow サーバーを使用したり、そのテストを実行したりするには必要ありません。

  • OpenWeather API キー — 実際の天気に対するライブエージェント実行にのみ必要です。無料ティアは openweathermap.org/api で利用できます。

インストール

リポジトリのルートから:

uv sync

これにより .venv が作成され、ランタイム依存関係(mcppydanticclaude-agent-sdkpython-dotenv)と開発依存関係(pytestruffblack)の両方がインストールされます。

設定

サンプル環境ファイルをコピーしてキーを入力します:

Copy-Item .env.example .env

bash: cp .env.example .env

次に .env を編集し、openweathermap.org/api(無料ティア)から取得した実際のキーで OWM_API_KEY を設定します。.env は gitignore されており、コミットされることはありません。

agent/mcp_config.json は、両方の MCP サーバー設定の唯一の情報源です。その openweather エントリは ${OWM_API_KEY} をプレースホルダーとして参照しており、agent/main.py が起動時にプロセス環境から置換します。agent/main.py 自体は .env を読み取らないことに注意してください — その main() は最初に python-dotenvload_dotenv() を呼び出し、その呼び出しが実際に .env の値を置換が行われる前にプロセス環境に到達させます。

その openweather.command フィールド自体もプレースホルダー ${MCP_OPENWEATHER_PATH} です — agent/main.py は、MCP_OPENWEATHER_PATH 環境変数が設定されている場合はそこから解決し、設定されていない場合は素のコマンド mcp-openweather(PATH に依存)にフォールバックします。バイナリのディレクトリを PATH に追加したくない場合は、.envMCP_OPENWEATHER_PATH を設定してください(.env.example を参照)— 両方の方法がライブで動作確認済みです。

OpenWeather MCP サーバーのビルド(実際の天気に対するライブ実行が必要な場合のみ)。以下は、このリポジトリ自身の開発環境でビルドおよび検証するために使用された正確なコマンドです:

winget install --id GoLang.Go -e --accept-source-agreements --accept-package-agreements
# open a new shell so PATH picks up the Go toolchain, then:
go install github.com/mschneider82/mcp-openweather@main

これにより $(go env GOPATH)\bin\mcp-openweather.exe にインストールされます — Windows では通常 %USERPROFILE%\go\bin\mcp-openweather.exe です。重要: Go の MSI インストーラーは Go ツールチェーン(C:\Program Files\Go\bin)を PATH に追加しますが、go install が実際にビルド済みバイナリを配置する場所である %USERPROFILE%\go\bin は追加しません。そのディレクトリを自分で PATH に追加するか、MCP_OPENWEATHER_PATH をバイナリのフルパスに設定してください(上記参照)— このリポジトリ自身のセットアップは後者を使用しています。

@latest ではなく @main を使用する理由: go install ...@latest はタグ v1.0.0 に解決されますが、これはリポジトリの main ブランチより 1 コミット(「Fix #5」)遅れています。両方をこのプロジェクトでビルドしてライブ比較しました:v1.0.0 はオプションの units/lang 引数が完全に省略された場合にフォールバックなしで読み取るため、lang を省略すると、ツール自身のスキーマがデフォルトを宣言しているにもかかわらず language unavailable で失敗します。main の「Fix #5」コミットは防御的な処理を追加し、同じ呼び出しが成功します。予報テンプレート自体は両者間でそれ以外は同一です(両バージョンのソースを読んで確認済み)— main からビルドしても日別の風/湿度/降水量が追加されるわけではなく、引数のバグを修正するだけです。agent/main.py は常に cityunits="c"lang="en" を明示的に渡すため、このバグはどちらにせよこのプロジェクトを通じて実際に表面化することはありません — ただし、ツールを別の方法で呼び出す場合は、main の方が依存するのに堅牢なバイナリです。

上流 README 自身の例の一部に示されている -o mcp-weather フラグは使用しないでください — これにより、自身の設定例と一致しないバイナリ名が生成されます。デフォルト名の mcp-openweather でビルドしてください。

MCP サーバーの実行

uv run python -m server.main

これにより、エージェントプロセスとは独立して、BuildWindow MCP サーバーが stdio 経由で実行されます — 完全に単独で起動して動作させることができます。成功すると、stderr に正確に次の行が出力されます:

BuildWindow MCP server ready: 4 tools, 12 work types loaded

エージェントの実行

uv run python -m agent.main

引数なしの場合、組み込みのデモ都市(「Kyiv」)と組み込みのデモ作業リストを使用します:excavation、次に concrete_pour(それに依存)、次に concrete_finishing(それに依存)。

両方とも上書きできます:

uv run python -m agent.main "CityName"
uv run python -m agent.main "CityName" '[{"work_code": "excavation", "duration_days": 1, "depends_on": []}]'

オプションの 2 番目の引数は、デモリストと同じ形式の作業の JSON 配列です。

リプレイモード--forecast-from-file <path> は完全にオフラインです:日別予報と現在の状況メモの両方を、記録されたファイルから読み取ったデータに置き換え、ライブ呼び出しに使用されるのと同じ決定論的パーサー(normalize_forecastparse_current_conditions)を介して処理します。このモードでは openweather はまったく接続されません(get_mcp_status() で確認済み — buildwindow のみが表示されます)。そのため、実行にはネットワークアクセスも API キーも一切不要です — 意図的に壊した OWM_API_KEY と到達不能な MCP_OPENWEATHER_PATH を同時に使用してライブ検証済みです。実行はそれでも正常に完了しました:

uv run python -m agent.main "Longyearbyen" '[{"work_code": "excavation", "duration_days": 1, "depends_on": []}, {"work_code": "exterior_painting", "duration_days": 2, "depends_on": []}]' --forecast-from-file fixtures/weather_longyearbyen.txt

fixtures/weather_kyiv.txtfixtures/weather_longyearbyen.txt は、このプロジェクトでライブキャプチャされた実際の応答です(それぞれ実際の暦日 3 日分にトリミング済み、内部にキーはありません)— 合成でも捏造された例でもありません。デモ都市の実際の天気が実行時に変わっている場合や、デモ時にネットワークがまったくない場合に役立ちます。

実際の天気に対する完全なライブ実行には、本当に有効な OWM_API_KEY(上記の設定を参照)が必要です — このリポジトリ自身の開発環境で動作確認済み:uv run python -m agent.main "Kyiv" は実際の予報から実際のスケジュールを生成し、uv run python -m agent.main "Longyearbyen" '[...]' は実際の天気が実際にリスケジュールを強制することを示します(docs/demo-checklist.md のステップ 4 を参照)。有効なキーがない場合、agent/main.py は予報を直接(LLM 経由ではなく)フェッチし、空の結果を受け取り、Forecast unavailable for '<city>' (...) と出力し、LLM セッションを開始する前に終了します — 無駄なモデル呼び出しも、捏造されたスケジュールもありません。これは 3 つの実際の障害モードで検証されました:mcp-openweather バイナリがまったく到達不能、無効な OWM_API_KEY、無効な都市名 — 最後の 2 つはこの上流ツールを通じて実際には区別できず(理由は docs/tool-contracts.md を参照)、同じ環境の他の場所で本当に有効なキーがアクティブであっても、両方とも同じクリーンな方法で失敗することが確認されました。

OpenWeather レート制限: 1 回の成功したライブ実行では、weather ツールへの実際の呼び出しは正確に2 回行われます(ライブで数えて確認済み)— セッション前の決定論的フェッチと、モデル自身の単一の現在の状況呼び出し(上記の概要を参照)。失敗したライブ実行(利用可能な予報がない場合)は、LLM セッションが開始されないため、正確に 1 回です。リプレイモード(--forecast-from-file)ではゼロ回です — 日別予報と現在の状況メモの両方が記録されたファイルから取得され、このモードでは openweather はまったく接続されません(ライブ確認済み:get_mcp_status()buildwindow のみを表示)。OpenWeather の無料ティアは 60 コール/分、1,000,000 コール/月と文書化されています — 手動デモ実行を何回行っても十分に余裕があります。このプロジェクトは、その公表された数値自体をストレステストするものではありません。

プロジェクト構造

.
├── README.md, DECISIONS.md, pyproject.toml, uv.lock, .env.example, .gitignore
├── docs/
│   ├── tool-contracts.md
│   ├── design-rationale.md
│   └── demo-checklist.md
├── scripts/
│   └── list_tools.py      # proves both MCP connections discover fine offline
├── server/
│   ├── main.py            # MCP server entry point, registers the 4 tools
│   ├── schemas.py         # Pydantic input/output models
│   ├── rules.py           # deterministic verdict/curing/planner logic
│   ├── dataset.py         # loads and validates work_types.json
│   ├── errors.py          # domain exceptions and error codes
│   └── data/work_types.json
├── agent/
│   ├── main.py             # agent entry point (Claude Agent SDK)
│   ├── normalize.py        # deterministic OpenWeather text -> daily figures
│   └── mcp_config.json     # config for both MCP servers
├── fixtures/
│   ├── weather_kyiv.txt      # real captured response, for --forecast-from-file
│   └── weather_longyearbyen.txt  # real captured response, for --forecast-from-file
└── tests/
    ├── conftest.py
    ├── test_dataset.py, test_lookup.py, test_validate.py
    ├── test_curing.py, test_planner.py, test_errors.py
    └── test_normalization.py

ツール概要

ツール

概要

lookup_work_requirements

作業タイプまたはカテゴリ全体の気象制限を検索します。

validate_work_window

1 つの作業タイプを 1 日の天気に対してチェックし、項目別の判定結果を返します。

estimate_curing_time

一連の日別気温が与えられたとき、養生中の作業タイプが実際にいつ完了するかを推定します。

plan_work_schedule

複数の依存する作業を 1 回の呼び出しで複数日の予報全体に配置します。

完全な契約 — すべてのツールの正確な JSON スキーマと実際にキャプチャされた例(このプロジェクトで使用される外部の weather ツールを含む)— は docs/tool-contracts.md にあります。

テスト

uv run pytest -v
uv run ruff check .
uv run black --check .

現在、このリポジトリでは3つすべてが問題なくパスしています。51件のテストがパスし(仕様で要求される38ケース、いくつかの補足的なアサーション、agent/normalize.pyの天気解析モジュールの8件のテスト(実フィクスチャ2件と現在の気象条件2件を含む)をカバー)、ruffblackの両方で問題は報告されていません。

制限事項

これらの各項目の完全な根拠はdocs/design-rationale.mdにあります。このリストは意図的に簡潔にしています。

  • データセットの閾値は実在のДБН/ДСТУ規格から導出されたものではなく、説明用のものです。

  • プランナーにはリソース/クルーの制約がありません。作業は日付が重複する可能性があります。

  • 実際の計画期間はOpenWeatherプロバイダーによって5日間に制限されています。

  • 養生時間は簡略化されたNurse-Saul成熟度モデルを使用しています。

  • 1つの作業は1つの連続したブロックを占有します。分割スケジューリングはありません。

  • OpenWeather MCPサーバーのweatherツール(推測ではなくソースを読んで確認済み)は、3時間ごとの予報エントリごとに気温のみを公開しています。風速と湿度は単一の現在の気象条件スナップショットでのみ利用可能で、ここではすべての予報日にわたって定数として適用されます。また、降水量はまったく公開されていないため、この統合を通じてprecipitation_mmは常に0.0になります。つまり、BuildWindowの降水ルール(precipitation_allowed=falseの作業は、precipitation_mm > 0の場合にハード違反となる)は、この統合を通じたライブ実行から実際にトリガーされることは決してありません。これは実際の正しいコードであり、構築されたデータに対するユニットテスト(tests/test_validate.py、仕様ケース#16-17)でカバーされていますが、非ゼロの降水量へのライブパスがないため、ライブデモで示すことはできません。このプロジェクトは、そのデモを作り出すために偽の雨データをシミュレートまたは注入することはありません。同じ上流ツールは、不正なAPIキーと認識されない都市と到達不能なプロバイダーを区別することもできません。3つすべてが同じ構文上は成功するが空のレスポンスとして返されるため、agent/main.pyはこれら3つのケースのいずれについても「予報が利用できません」としか報告できず、特定の原因を報告できません。完全なソース検証済みの詳細はdocs/tool-contracts.mdを参照してください。

  • 真正なOWM_API_KEYが機能することが現在確認されています。実際のキエフの天気に対する完全なライブ実行は、エンドツーエンドで実際のスケジュールを生成し、実際の寒冷地の都市(ロングイェールビエン)が見つかり、ライブ予報が実際に作業をunschedulableにし、validate_work_windowが実数で発火します。docs/demo-checklist.mdのステップ4を参照してください。このREADMEで説明されているすべては、欠落したキーだけでなく、実際の動作するキーに対して検証されています。その実データに対するライブ実行がコードで何を変更し、何を変更しなかったかについてはDECISIONS.mdを参照してください。

ドキュメント

  • docs/tool-contracts.md — 4つすべてのBuildWindowツールと、このプロジェクトで使用される外部OpenWeather weatherツールの正確なJSON Schema契約。それぞれに実際にキャプチャされた例が付いています。

  • docs/design-rationale.md — 各ツールが存在する理由、ツールセットがワークフローにどのようにマッピングされるか、コンポーネント間の境界、行われたトレードオフ、およびプロジェクトの制限事項の完全な説明。

  • docs/demo-checklist.md — プロジェクトのライブデモを実行するためのステップバイステップのチェックリスト。

  • DECISIONS.md — 実装上の決定の日付付きログ。各決定にはその根拠と却下された代替案が記載されています。

Install Server
F
license - not found
A
quality
B
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

  • F
    license
    B
    quality
    D
    maintenance
    Enables users to get weather alerts and forecasts through natural language interactions. Provides real-time weather information and alert notifications via MCP tools.
    2
  • A
    license
    Not graded
    quality
    D
    maintenance
    Global weather intelligence for AI assistants providing 10 weather tools — forecasts, historical data, air quality, marine, geocoding, elevation, and climate projections at 1km resolution with 80+ years of archive.
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Exposes Swiss weather forecast data as MCP tools, including rainfall, sunshine, temperature, wind, and more, with local caching.
    1
    Apache 2.0

View all related MCP servers

Related MCP Connectors

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/borovkov-d/buildwindow-mcp'

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