solar_mcp
solar-plan-mcp
一个回答日常问题的代理:明天我能否靠自家发电撑过这批用电设备,如果不行——该把什么挪走?
屋顶有光伏板、电池、逆变器,还有已知的停电时间表。代理从现成的 MCP 服务器取天气预报,在自有的 MCP 服务器上按小时计算预期发电量,把计划对照物理规则做校验,如果计划过不了——就挪动灵活负载,并用数字证明情况变好了。
两条 MCP 连接:
服务器 | 角色 | |
现成 |
| 预报:每 3 小时的天况等级和温度 |
自有 |
| 4 个领域内有实质内容的工具 + 预报文本解析 |
需要什么
用途 | 备注 | |
Python 3.13 | 代理和自有服务器 | 不需要管理员权限 |
Go 1.24+ | 仅用于编译天气服务器 | 项目不发布现成二进制; |
OpenWeather 密钥 | 天气服务器 | 免费,openweathermap.org/api;激活最长需要几个小时 |
| 仅代理;自有服务器和测试都不需要它 | Claude Agent SDK 会把这个 CLI 作为子进程拉起——见模型访问 |
Node + npx | 可选——MCP Inspector |
|
PVGIS 数据集已经放在仓库里(data/pvgis_kyiv_5kwp.csv,1.1 MB),所以自有服务器无需联网即可工作。什么都不用下载。
Related MCP server: KinSwitch
安装
Windows,而且这不是表面功夫:所有命令都在 PowerShell 里执行,因为 && 在 PowerShell 5.1 里根本不是运算符。下文统一用 .venv\Scripts\python.exe。
先设两个编码变量,而且它们作用不同。 PYTHONUTF8=1 告诉 Python 写入 UTF-8;[Console]::OutputEncoding 告诉 PowerShell 同样地读取它。没有第二个变量,乌克兰语输出就会变成 ╨▓╨╗╨░╤ü╨╜╨╕╨╣——实测如此,而且恰恰发生在管道里(| 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 已经是 MCPServer 而不是 FastMCP,面向 1.x 的代码在这里跑不通;claude-agent-sdk==0.2.144 上验证过 tools 和 init 消息格式,代理正是从后者打印两条连接的;tzdata——因为 Windows 没有系统时区数据库,而没有 Europe/Kyiv 就不会有任何本地小时。requirements.txt 本身刻意保持 ASCII:pip 用区域设置的编码读取它,注释里一个西里尔字母就会让 pip install -r 在任何非 UTF-8 区域设置的机器上报 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 历史和 13 MB 的二进制跟本仓库无关。提交已固定——契约文档正是基于它写的。
如果课程固定的是
mcp-openweather的另一个提交——就用那个并在这里记下来;docs/TOOLS.md里的契约描述是根据e032683上的main.go写的。
密钥
机密不会进仓库:.env 和 .env.* 在 .gitignore 里,样例放在 env.example,没有任何值。
演示需要三个终端,而 $env: 只活在一个终端里,所以密钥最好设在用户级别——这不需要管理员权限:
# так ключ не потрапляє ні в скролбек, ні в історію 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 = "…" 也能用,但在这里只有一个正确用途——在单独窗口里为故障场景清空密钥:$env:OWM_API_KEY = ""。
密钥只从环境变量读取——代码里没有,.mcp.json.example 里也没有;那里放的是 ${OWM_API_KEY} 替换。没有人读取 .env 文件:代码里只有 os.environ.get,所以把 env.example 复制成 .env 是空操作。
模型访问
自有服务器和全部 57 个测试不需要任何 Anthropic 凭据——这是两回事,不该混淆。模型只服务于一个文件,agent/run.py。
Claude Agent SDK 不直接调用 API:它把 claude CLI 作为子进程拉起,而正是那个 CLI 去找授权。因此需要两样东西:
claude在PATH里。 验证:(Get-Command claude).Source。安装按官方说明;在本项目中它是通过 WinGet 安装的,位于%LOCALAPPDATA%\Microsoft\WinGet\Links\claude.exe。授权——两条路之一,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 免费套餐是每分钟 60 次调用(文档)。代理跑一次只做一次 weather 工具调用;天气服务器内部把它变成两个 HTTP 请求(当前天气 + 5 天预报)。也就是说离上限还有三个数量级的余量,哪怕连续排练也没问题。
代码里没有任何轮询循环、出错重试或后台刷新:天气只在模型调用工具的那一刻被请求。自有服务器完全不联网——它的数据集在 data/ 里,所以无论跑多少次 estimate_pv_generation、validate_energy_plan 等都不会产生任何外部请求。
启动:两个独立进程
自有服务器独立于代理启动,对代理一无所知。
终端 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,而且停电时间表里有这个窗口也救不了:时间表在仓库里,认识任何日期,而预报只活五天。启动前先验证: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其中两个目录有自己的 README,而且正是「数据来源」和「fixtures」要找的地方:data/README.md——PVGIS 行、电价和停电时间表的来源;tests/fixtures/README.md——从外部服务器录了什么、何时、用什么录的。
一个支撑了半个设计设计的观察
天气服务器区分不了故障和空响应。没有密钥时它返回 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。
This server cannot be deployed
Maintenance
Related MCP Connectors
Home energy for AI assistants: live Power flow, Energy history, solar forecast, and device control.
Solar, weatherization, EV charging, battery and heat-pump decision tools for AI agents.
EU power dispatch for wallet-enabled compute, DePIN, battery and trading agents.
Solar power estimates from the electricity bill, and the service area check, for São Paulo, Brazil.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables 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.-
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to manage household schedules by checking availability, proposing minimal changes, and requiring explicit human approval before executing any action.MIT
- AlicenseNot gradedqualityBmaintenanceEnables 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.6 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables voice assistants to answer when to run household appliances using live solar forecasts, typical-year production, savings, battery, and multi-load planning. It remembers site details, estimates usable solar windows, and returns concise spoken guidance without inventing measurements.MIT