Skip to main content
Glama

solar-plan-mcp

エージェントは、ある家庭の質問に答えます。明日、この消費者のセットを自家発電で賄えるか、無理なら何を先送りするか?

屋根にパネル、バッテリー、インバーター、既知の停電スケジュール。エージェントは既製のMCPサーバーから天気予報を取得し、自前のMCPサーバーで時間ごとの期待発電量を計算し、物理ルールに対して計画を検証し、それが通らない場合は柔軟な負荷を先送りして、数値で改善したことを示します。

2つのMCP接続:

サーバー

役割

既製

mschneider82/mcp-openweather、コミット e032683

予報: 3時間ごとの空の状態と気温

自前

solar_mcp (このリポジトリ)

ドメインの4つの実質的なツール + 予報テキストの解析

ドキュメント: ツール契約 · 設計の根拠 · デモシナリオ

必要なもの

目的

備考

Python 3.13

エージェントと自前サーバー

管理者権限は不要

Go 1.24+

天気サーバーをビルドするためだけ

既製バイナリは公開されていない; go.mod は1.24を要求するが、READMEには1.20と書いてある

OpenWeatherキー

天気サーバー

無料、openweathermap.org/api; 有効化に最大数時間かかる

claude CLI + モデルへのアクセス

エージェントのみ; 自前サーバーとテストは不要

Claude Agent SDK はこのCLIを子プロセスとして起動する — モデルへのアクセス を参照

Node + npx

任意 — MCP Inspector

npx @modelcontextprotocol/inspector

PVGISデータセットはすでにリポジトリ内にある (data/pvgis_kyiv_5kwp.csv、1.1 MB) ため、自前サーバーはネットワークなしで動作します。ダウンロードは不要です。

Related MCP server: KinSwitch

インストール

Windows、そしてこれは見た目の問題ではない: すべてのコマンドはPowerShellで実行する。なぜならPowerShell 5.1では && はそもそも演算子ではないからだ。以降、すべて .venv\Scripts\python.exe を使用する。

まず2つのエンコーディング変数。そしてそれらは別物だ。 PYTHONUTF8=1 はPythonにUTF-8で書き出すよう指示する; [Console]::OutputEncoding はPowerShellに同じくUTF-8で読み取るよう指示する。2つ目がないと、ウクライナ語の出力は ╨▓╨╗╨░╤ü╨╜╨╕╨╣ になる — 実測済みで、特にパイプ (| Tee-Object、| Select-String) の中で発生する。なぜならそこではPowerShellがコンソールのコードページでバイトをデコードするからだ。新しいウィンドウごとに、そしてインストールの前に設定すること。後ではない:

[Console]::OutputEncoding = [Text.Encoding]::UTF8
$env:PYTHONUTF8 = "1"
git clone https://github.com/prasolantoncp-bot/solar-plan-mcp.git
cd solar-plan-mcp

python -m venv .venv                       # або: uv venv .venv
.venv\Scripts\python.exe -m pip install -r requirements.txt

必要なのはPython 3.13 — まさに python --version が応答するもの。なぜなら venv は作成時に使ったインタープリターのバージョンを継承するからだ。

なぜバージョンを固定しているのか。 デモは「どこかで動く」ではなく再現可能であるべきだ。mcp==2.0.0 はすでに FastMCP の代わりに MCPServer であり、1.x向けのコードはここでは動かない; claude-agent-sdk==0.2.144 は、エージェントが両方の接続を出力する tools とinitメッセージ形式が検証されたバージョンだ; tzdata — Windowsにはシステムのタイムゾーンデータベースがなく、Europe/Kyiv がなければ現地時間は一切得られないからだ。requirements.txt 自体は意図的にASCIIで維持されている: pipはそれをロケールのエンコーディングで読み取るため、コメント内のキリル文字1文字が、ロケールがUTF-8でない任意のマシンで pip install -r を UnicodeDecodeError で失敗させる。クリーンなクローンからcp1252で実測済み — だから説明はここにあり、あのファイルにはない。

天気サーバーをビルドする

Goはユーザープロファイルにインストールされ、管理者もレジストリの変更も不要:

# 1. портативний Go у профіль (один раз). curl.exe є у Windows 10 1803+
curl.exe -Lo go.zip https://go.dev/dl/go1.27.0.windows-amd64.zip
Expand-Archive go.zip -DestinationPath "$env:LOCALAPPDATA\Programs"

# 2. клон і збірка. GOROOT і PATH живуть лише в цьому вікні — так і треба
$env:GOROOT = "$env:LOCALAPPDATA\Programs\go"
$env:PATH = "$env:GOROOT\bin;$env:PATH"
New-Item -ItemType Directory -Force vendor | Out-Null
cd vendor
git clone https://github.com/mschneider82/mcp-openweather.git
cd mcp-openweather
git checkout e032683574a0723591445462ef7104d360ad0889
go build -o mcp-weather.exe .
cd ..\..

既製バイナリをエージェントは vendor\mcp-openweather\mcp-weather.exe というパスで探す。別の場所にある場合は移動せず、変数を設定せよ: $env:WEATHER_MCP_BINARY = "…\mcp-weather.exe" (env.example を参照)。エージェントはセッション開始前にファイルの存在を確認し、SDK内部からのトレースではなく文章で拒否する。

vendor/ は .gitignore にある: 他人のgit履歴と13MBのバイナリはこのリポジトリには無関係だ。コミットは固定されている — まさにそのコミットに対して契約ドキュメントが書かれている。

コースが別の mcp-openweather コミットを固定している場合は、それを採用してここに記録せよ; docs/TOOLS.md の契約の説明は e032683 の main.go から書かれた。

キー

シークレットはリポジトリに入らない: .env と .env.* は .gitignore にあり、サンプルは値なしで env.example にある。

デモには3つのターミナルが必要で、$env: は1つにしか存在しないため、キーはユーザーレベルで設定する価値がある — 管理者権限は不要:

# так ключ не потрапляє ні в скролбек, ні в історію PSReadLine
$s = Read-Host "OWM_API_KEY" -AsSecureString
[Environment]::SetEnvironmentVariable("OWM_API_KEY",
  [Runtime.InteropServices.Marshal]::PtrToStringBSTR(
    [Runtime.InteropServices.Marshal]::SecureStringToBSTR($s)), "User")

新しい値は新しいターミナルでのみ見える。キーを公開せずに届いたことを確認する: .venv/Scripts/python.exe -c "import os; print(len(os.environ.get('OWM_API_KEY','')))" — 32 になるはずだ。カメラの前で dir env: を実行しないこと: キーが出力される。

セッション限定の $env:OWM_API_KEY = "…" も機能するが、ここでは1つの正しい用途がある — 障害シナリオ用に別のウィンドウでキーをクリアすること: $env:OWM_API_KEY = ""。

キーは環境からのみ読み取られる — コードにも .mcp.json.example にも存在せず、そこには ${OWM_API_KEY} という置換がある。.env ファイルは誰も読まない: コードには os.environ.get しかないため、env.example を .env にコピーするのは無意味な行為だ。

モデルへのアクセス

自前サーバーと57のテストはすべて、Anthropicの資格情報なしで動作する — これらは別物であり、混同すべきではない。モデルが必要なのは正確に1つのファイル、agent/run.py だけだ。

Claude Agent SDKはAPIに直接アクセスしない: claude CLIを子プロセスとして起動し、そのCLIが認証を探す。したがって2つのものが必要:

  1. PATH 内の claude。 確認: (Get-Command claude).Source。インストールは公式手順による; このプロジェクトではWinGetでインストールされ、%LOCALAPPDATA%\Microsoft\WinGet\Links\claude.exe にある。

  2. 認証 — 2つの経路のいずれか、CLIは見つかった方を使う:

    • claude login — 対話的ログイン; CLIはトークンを ~/.claude/.credentials.json に置く。 ここで使われたのはまさにこの経路だ: プロセス環境には ANTHROPIC_* 変数が一切なく、資格情報ファイルは存在する。2026年8月25日の記録済み実行はこのように通った。

    • 環境内の ANTHROPIC_API_KEY — console.anthropic.com のキー。 上記の OWM_API_KEY と同じように設定され、同じくリポジトリには入らない。

コードで固定されているもの: モデル claude-opus-5 (agent/run.py) と claude-agent-sdk==0.2.144 (requirements.txt)。別のアクセス権を持ち、このモデルIDが解決されない場合は、run.py で利用可能なものに置き換えて、ここにどれかを記録せよ; 実行の残りはIDに依存しない。

このコードは資格情報を一切読み取らず、どこにも渡さない: agent/run.py は ANTHROPIC_API_KEY にも資格情報ファイルにもアクセスしない — それを担当するのはCLIだ。リポジトリにシークレットはなく、env.example は空のまま置かれている。

外部APIの制限

OpenWeatherの無料プランは1分あたり60回の呼び出しを提供する(ドキュメント)。エージェントの1回の実行は weather ツールの1回の呼び出しを行い、内部で天気サーバーはそれを2つのHTTPリクエスト(現在の天気 + 5日間予報)に変換する。つまり、継続的なリハーサルでも上限まで3桁の余裕がある。

コードにはポーリングループ、エラー時の再試行、バックグラウンド更新は一切ない: 天気はモデルがツールを呼び出したときにのみ要求される。自前サーバーはネットワークに一切アクセスしない — データセットは data/ にあるため、estimate_pv_generation、validate_energy_plan などの実行を何度行っても外部リクエストは発生しない。

起動: 2つの独立したプロセス

自前サーバーはエージェントとは別に起動し、エージェントについて何も知らない。

ターミナル1 — 自前MCPサーバー:

$env:PYTHONUTF8 = "1"
.venv\Scripts\python.exe -m solar_mcp --transport streamable-http --port 8931

ターミナル2 — エージェント:

[Console]::OutputEncoding = [Text.Encoding]::UTF8
$env:PYTHONUTF8 = "1"
.venv\Scripts\python.exe agent\run.py

--date なしでは、エージェントは明日の日を計画する: 製品の質問はまさに明日についてであり、OpenWeatherの予報は 現在 … +5日 のみをカバーするため、今日の日はすでに半分が地平線の外にある。このウィンドウ外の日付は黙ったゼロではなく NO_FORECAST_FOR_DATE になる。

天気サーバーはエージェントが自分でstdio経由で起動する — 接続はそのように設定されている。自前サーバーもstdioで起動できる (python -m solar_mcp、これがデフォルト) — Claude Codeのようなクライアントはそれを期待しており、まさにそのバリアントが .mcp.json.example に記述されている。デモにはHTTPの方が良い: サーバーが本当に別のプロセスであることが見えるからだ。

エージェントの便利なフラグ:

--plan boiler:18:2 --plan aircon:18:3    # свій план замість дефолтного (можна кілька разів)
--date YYYY-MM-DD                        # інша доба; вт/чт/пт — без відключень, сб/нд — вечірнє вікно
--objective maximize_outage_reserve      # інша цільова функція
--city Lviv                              # інше місто
--width 120                              # скільки символів сліду друкувати

--date は予報の地平線内の日のみを受け付ける — 明日 … 今日 + 5。範囲外の日付は NO_FORECAST_FOR_DATE になり、スケジュールに停電ウィンドウがあることは救いにならない: スケジュールはリポジトリにあり任意の日付を知っているが、予報は5日しか生きない。起動前に確認: scripts/call_weather.py --city Kyiv --covers YYYY-MM-DD。

停電スケジュールの日付は週次パターンと来歴を持つ — data/outage_windows.json を参照: 8月22〜26日のウィンドウは公開スケジュールから入力され、以降は同じパターンが前方に繰り返され、デモが録画日付に依存しないようにしている。

すべてが生きていることの確認

# 4 інструменти домену + 1 допоміжний, зі схемами входу І виходу
.venv\Scripts\python.exe scripts\inspect_tools.py
.venv\Scripts\python.exe scripts\inspect_tools.py --url http://127.0.0.1:8931/mcp --schemas

# сервер погоди напряму: сирий текст і те, що з нього вийшло
.venv\Scripts\python.exe scripts\call_weather.py --city Kyiv

# 57 тестів: фізика, правила домену, планувальник, контракт через MCP-клієнта
$env:PYTHONUTF8 = "1"; $env:PYTHONPATH = "."
.venv\Scripts\python.exe -m pytest tests\ -q

テストはネットワークもOpenWeatherキーもモデルへのアクセスも必要としない: データセットはリポジトリにあり、外部サーバーの応答は tests/fixtures/ に記録されている。

ファイルの配置

solar_mcp/            власний MCP-сервер (окремий процес)
  server.py           інструменти й ресурс — увесь контракт
  models.py           схеми входу й виходу (Pydantic → справжні inputSchema/outputSchema)
  errors.py           закритий перелік кодів; помилка ≠ порожній результат
  pv.py               огинаюча ясного неба × прозорість × температурний дерейтинг
  rules.py            симуляція балансу, порушення, планувальник, порівняння
  forecast.py         розбір плоского тексту сервера погоди
  dataset.py store.py читання датасету; реєстр виданих оцінок
agent/run.py          Claude Agent SDK, дві MCP-конекції, слід викликів
scripts/              inspect_tools.py — контракт; call_weather.py — чужий сервер напряму
data/                 датасет + fetch_pvgis.py (провенанс)
tests/                57 тестів; у fixtures/ — три записані відповіді сервера погоди й одна синтетична
docs/                 TOOLS.md · DESIGN.md · DEMO.md

これらのディレクトリのうち2つには独自のREADMEがあり、「データソース」と「フィクスチャ」を探すときにまさにそれらが対象になる: data/README.md — PVGIS行、料金、停電スケジュールの出所; tests/fixtures/README.md — 外部サーバーから何が、いつ、何で記録されたか。

デザインの半分が立っている1つの観察

天気サーバーは障害と空の応答を区別しない。キーなしでは is_error: false と、ゼロと空の都市名を含むテキストを返す — tests/fixtures/owm_no_api_key.txt に逐語的に記録されている。READMEは「FATAL: OWM_API_KEY environment variable not set」を約束しているにもかかわらず。

だから自前サーバーは逆に作られている: 閉じたエラーコードの列挙、問題のあるフィールドを指す field、そして空が正当な場所(夜、違反なし)には別途 reason。詳細: DESIGN.md、TOOLS.md。

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI-powered analysis and prediction of household energy consumption through machine learning models, providing historical consumption breakdowns, price queries from Spanish electricity markets, and personalized energy optimization recommendations.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to manage household schedules by checking availability, proposing minimal changes, and requiring explicit human approval before executing any action.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables conversational home power management by providing real-time solar, battery, and grid status, plus forecasts to answer questions like whether you can run an appliance. It supports Victron and Growatt inverters, remembers household appliances and grid events, and renders an interactive dashboard card in MCP-compatible clients.
    5 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to size hybrid renewable energy systems by simulating candidate designs hour-by-hour for a full year, filtering out constraint violations, and ranking remaining options by net present cost and related techno-economic metrics.
    Apache 2.0