site-calc-investment 1.2.1__tar.gz → 1.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/CHANGELOG.md +35 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/PKG-INFO +58 -1
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/README.md +54 -0
- site_calc_investment-1.2.3/docs/MCP_SERVER_SPEC.md +413 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/examples/01_basic_capacity_planning.py +1 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/examples/02_scenario_comparison.py +1 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/pyproject.toml +6 -1
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/__init__.py +1 -1
- site_calc_investment-1.2.3/site_calc_investment/mcp/__init__.py +15 -0
- site_calc_investment-1.2.3/site_calc_investment/mcp/config.py +40 -0
- site_calc_investment-1.2.3/site_calc_investment/mcp/data_loaders.py +241 -0
- site_calc_investment-1.2.3/site_calc_investment/mcp/scenario.py +515 -0
- site_calc_investment-1.2.3/site_calc_investment/mcp/server.py +758 -0
- site_calc_investment-1.2.3/tests/test_mcp/__init__.py +0 -0
- site_calc_investment-1.2.3/tests/test_mcp/conftest.py +114 -0
- site_calc_investment-1.2.3/tests/test_mcp/test_data_loaders.py +224 -0
- site_calc_investment-1.2.3/tests/test_mcp/test_integration.py +252 -0
- site_calc_investment-1.2.3/tests/test_mcp/test_mcp_production.py +184 -0
- site_calc_investment-1.2.3/tests/test_mcp/test_scenario.py +437 -0
- site_calc_investment-1.2.3/tests/test_mcp/test_tools.py +489 -0
- site_calc_investment-1.2.3/uv.lock +2430 -0
- site_calc_investment-1.2.1/uv.lock +0 -1052
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/.github/workflows/ci.yml +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/.github/workflows/publish.yml +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/.gitignore +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/CONTRIBUTING.md +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/LICENSE +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/MIGRATION_GUIDE.md +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/QUICK_START.md +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/READY_TO_PUBLISH.md +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/docs/INVESTMENT_CLIENT_SPEC.md +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/examples/03_financial_analysis.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/publish_to_github.bat +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/publish_to_github.sh +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/analysis/__init__.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/analysis/comparison.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/analysis/financial.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/api/__init__.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/api/client.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/exceptions.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/models/__init__.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/models/common.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/models/devices.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/models/requests.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/models/responses.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/conftest.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_api_client.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_common_models.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_device_models.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_financial_analysis.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_production.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_request_models.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_scenario_comparison.py +0 -0
- {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/verify_ready.py +0 -0
|
@@ -5,6 +5,41 @@ All notable changes to the Site-Calc Investment Client will be documented in thi
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.2.3] - 2026-02-04
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **`save_data_file` MCP tool**: New tool (#15) that writes generated data (price arrays, demand
|
|
12
|
+
profiles) to CSV files on the local filesystem. Solves the problem where the LLM cannot write
|
|
13
|
+
files directly but the MCP server can.
|
|
14
|
+
- Supports named columns with automatic `.csv` extension
|
|
15
|
+
- Relative paths resolve against `INVESTMENT_DATA_DIR` environment variable
|
|
16
|
+
- Returned file path can be used directly in `add_device` via `{"file": "...", "column": "..."}`
|
|
17
|
+
- **`INVESTMENT_DATA_DIR` environment variable**: Optional config for `save_data_file` base directory
|
|
18
|
+
- **MCP Server specification**: Full docs at `docs/MCP_SERVER_SPEC.md`
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- MCP server instructions updated to inform the LLM about `save_data_file` capability
|
|
22
|
+
- MCP tool count: 14 -> 15
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## [1.2.2] - 2026-02-04
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- **MCP Server**: FastMCP-based MCP server exposing 14 tools for LLM-driven investment planning
|
|
31
|
+
- Stateful builder pattern: create scenario -> add devices -> set timespan -> review -> submit -> get results
|
|
32
|
+
- All 10 device types supported with data shorthand (scalar expansion, CSV/JSON file loading)
|
|
33
|
+
- 3 result detail levels: summary, monthly, full
|
|
34
|
+
- Install via `pip install site-calc-investment[mcp]`
|
|
35
|
+
- CLI entry point: `site-calc-investment-mcp`
|
|
36
|
+
- **`get_device_schema` tool**: Returns property schemas for each device type with types, units, and examples
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
- Package now has `[mcp]` optional dependency group (`fastmcp>=2.0`)
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
8
43
|
## [1.2.1] - 2026-02-03
|
|
9
44
|
|
|
10
45
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: site-calc-investment
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3
|
|
4
4
|
Summary: Python client for Site-Calc investment planning (capacity sizing, ROI analysis)
|
|
5
5
|
Project-URL: Homepage, https://github.com/stranma/site-calc-investment
|
|
6
6
|
Project-URL: Documentation, https://github.com/stranma/site-calc-investment#readme
|
|
@@ -25,6 +25,7 @@ Requires-Dist: numpy>=1.24
|
|
|
25
25
|
Requires-Dist: pydantic>=2.0
|
|
26
26
|
Requires-Dist: python-dateutil>=2.8
|
|
27
27
|
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: fastmcp>=2.0; extra == 'dev'
|
|
28
29
|
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
29
30
|
Requires-Dist: pandas>=2.0; extra == 'dev'
|
|
30
31
|
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
@@ -33,6 +34,8 @@ Requires-Dist: pytest-timeout>=2.2; extra == 'dev'
|
|
|
33
34
|
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
34
35
|
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
35
36
|
Requires-Dist: tzdata>=2024.1; extra == 'dev'
|
|
37
|
+
Provides-Extra: mcp
|
|
38
|
+
Requires-Dist: fastmcp>=2.0; extra == 'mcp'
|
|
36
39
|
Description-Content-Type: text/markdown
|
|
37
40
|
|
|
38
41
|
# Site-Calc Investment Client
|
|
@@ -209,6 +212,60 @@ comparison = compare_scenarios(
|
|
|
209
212
|
print(comparison) # DataFrame with NPV, IRR, costs, revenues
|
|
210
213
|
```
|
|
211
214
|
|
|
215
|
+
## MCP Server (Claude Desktop Integration)
|
|
216
|
+
|
|
217
|
+
The package includes an MCP server for use with Claude Desktop and other LLM tools.
|
|
218
|
+
|
|
219
|
+
### Installation
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
pip install site-calc-investment[mcp]
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Claude Desktop Configuration
|
|
226
|
+
|
|
227
|
+
Add to `claude_desktop_config.json`:
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"mcpServers": {
|
|
232
|
+
"site-calc-investment": {
|
|
233
|
+
"command": "uv",
|
|
234
|
+
"args": ["run", "--directory", "/path/to/client-investment", "site-calc-investment-mcp"],
|
|
235
|
+
"env": {
|
|
236
|
+
"INVESTMENT_API_URL": "http://your-api-url",
|
|
237
|
+
"INVESTMENT_API_KEY": "inv_your_key_here",
|
|
238
|
+
"INVESTMENT_DATA_DIR": "/path/to/data/directory"
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Tools (15)
|
|
246
|
+
|
|
247
|
+
| Tool | Description |
|
|
248
|
+
|------|-------------|
|
|
249
|
+
| `create_scenario` | Create a new draft scenario |
|
|
250
|
+
| `add_device` | Add a device (battery, CHP, PV, etc.) |
|
|
251
|
+
| `set_timespan` | Set optimization time horizon |
|
|
252
|
+
| `set_investment_params` | Set financial parameters (NPV, IRR) |
|
|
253
|
+
| `review_scenario` | Review scenario before submission |
|
|
254
|
+
| `remove_device` | Remove a device |
|
|
255
|
+
| `delete_scenario` | Delete a scenario |
|
|
256
|
+
| `list_scenarios` | List all draft scenarios |
|
|
257
|
+
| `submit_scenario` | Submit for optimization |
|
|
258
|
+
| `get_job_status` | Check job progress |
|
|
259
|
+
| `get_job_result` | Get optimization results |
|
|
260
|
+
| `cancel_job` | Cancel a job |
|
|
261
|
+
| `list_jobs` | List all jobs |
|
|
262
|
+
| `get_device_schema` | Get device property schema |
|
|
263
|
+
| `save_data_file` | Save generated data as CSV |
|
|
264
|
+
|
|
265
|
+
`save_data_file` lets the LLM write generated data (price arrays, demand profiles) to local CSV files, which can then be referenced in `add_device` properties.
|
|
266
|
+
|
|
267
|
+
See [docs/MCP_SERVER_SPEC.md](docs/MCP_SERVER_SPEC.md) for full specification.
|
|
268
|
+
|
|
212
269
|
## Documentation
|
|
213
270
|
|
|
214
271
|
Full documentation available at: https://github.com/stranma/site-calc-investment#readme
|
|
@@ -172,6 +172,60 @@ comparison = compare_scenarios(
|
|
|
172
172
|
print(comparison) # DataFrame with NPV, IRR, costs, revenues
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
+
## MCP Server (Claude Desktop Integration)
|
|
176
|
+
|
|
177
|
+
The package includes an MCP server for use with Claude Desktop and other LLM tools.
|
|
178
|
+
|
|
179
|
+
### Installation
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
pip install site-calc-investment[mcp]
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Claude Desktop Configuration
|
|
186
|
+
|
|
187
|
+
Add to `claude_desktop_config.json`:
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"mcpServers": {
|
|
192
|
+
"site-calc-investment": {
|
|
193
|
+
"command": "uv",
|
|
194
|
+
"args": ["run", "--directory", "/path/to/client-investment", "site-calc-investment-mcp"],
|
|
195
|
+
"env": {
|
|
196
|
+
"INVESTMENT_API_URL": "http://your-api-url",
|
|
197
|
+
"INVESTMENT_API_KEY": "inv_your_key_here",
|
|
198
|
+
"INVESTMENT_DATA_DIR": "/path/to/data/directory"
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Tools (15)
|
|
206
|
+
|
|
207
|
+
| Tool | Description |
|
|
208
|
+
|------|-------------|
|
|
209
|
+
| `create_scenario` | Create a new draft scenario |
|
|
210
|
+
| `add_device` | Add a device (battery, CHP, PV, etc.) |
|
|
211
|
+
| `set_timespan` | Set optimization time horizon |
|
|
212
|
+
| `set_investment_params` | Set financial parameters (NPV, IRR) |
|
|
213
|
+
| `review_scenario` | Review scenario before submission |
|
|
214
|
+
| `remove_device` | Remove a device |
|
|
215
|
+
| `delete_scenario` | Delete a scenario |
|
|
216
|
+
| `list_scenarios` | List all draft scenarios |
|
|
217
|
+
| `submit_scenario` | Submit for optimization |
|
|
218
|
+
| `get_job_status` | Check job progress |
|
|
219
|
+
| `get_job_result` | Get optimization results |
|
|
220
|
+
| `cancel_job` | Cancel a job |
|
|
221
|
+
| `list_jobs` | List all jobs |
|
|
222
|
+
| `get_device_schema` | Get device property schema |
|
|
223
|
+
| `save_data_file` | Save generated data as CSV |
|
|
224
|
+
|
|
225
|
+
`save_data_file` lets the LLM write generated data (price arrays, demand profiles) to local CSV files, which can then be referenced in `add_device` properties.
|
|
226
|
+
|
|
227
|
+
See [docs/MCP_SERVER_SPEC.md](docs/MCP_SERVER_SPEC.md) for full specification.
|
|
228
|
+
|
|
175
229
|
## Documentation
|
|
176
230
|
|
|
177
231
|
Full documentation available at: https://github.com/stranma/site-calc-investment#readme
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
# MCP Server Specification
|
|
2
|
+
|
|
3
|
+
**Package:** `site-calc-investment[mcp]`
|
|
4
|
+
**Server name:** `site-calc-investment`
|
|
5
|
+
**Protocol:** MCP (Model Context Protocol) via FastMCP
|
|
6
|
+
**Tools:** 15
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. Overview
|
|
11
|
+
|
|
12
|
+
The MCP server exposes the Site-Calc investment planning API as tools that LLMs (e.g., Claude Desktop) can call interactively. Users describe what they want to optimize in natural language, and the LLM assembles scenarios, submits jobs, and retrieves results through these tools.
|
|
13
|
+
|
|
14
|
+
### 1.1 Architecture
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
Claude Desktop (LLM)
|
|
18
|
+
|
|
|
19
|
+
| MCP protocol (stdio)
|
|
20
|
+
v
|
|
21
|
+
site-calc-investment-mcp (local process)
|
|
22
|
+
|
|
|
23
|
+
| HTTPS / REST
|
|
24
|
+
v
|
|
25
|
+
Site-Calc API (remote server)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The MCP server runs **locally** on the user's machine. It has full filesystem access (for CSV data files) and network access (for the optimization API).
|
|
29
|
+
|
|
30
|
+
### 1.2 Key Capabilities
|
|
31
|
+
|
|
32
|
+
| Feature | Value |
|
|
33
|
+
|---------|-------|
|
|
34
|
+
| Tools | 15 |
|
|
35
|
+
| Device types | 10 |
|
|
36
|
+
| Max horizon | 100,000 intervals (~11 years) |
|
|
37
|
+
| Resolution | 1-hour |
|
|
38
|
+
| Local filesystem | Read + Write (CSV data files) |
|
|
39
|
+
| API connection | HTTPS to Site-Calc server |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 2. Configuration
|
|
44
|
+
|
|
45
|
+
### 2.1 Environment Variables
|
|
46
|
+
|
|
47
|
+
| Variable | Required | Description |
|
|
48
|
+
|----------|----------|-------------|
|
|
49
|
+
| `INVESTMENT_API_URL` | Yes | Site-Calc API base URL |
|
|
50
|
+
| `INVESTMENT_API_KEY` | Yes | API key (starts with `inv_`) |
|
|
51
|
+
| `INVESTMENT_DATA_DIR` | No | Default directory for `save_data_file` relative paths |
|
|
52
|
+
|
|
53
|
+
`INVESTMENT_API_URL` and `INVESTMENT_API_KEY` are required for job submission tools (`submit_scenario`, `get_job_status`, `get_job_result`, `cancel_job`). Scenario assembly tools work without them.
|
|
54
|
+
|
|
55
|
+
`INVESTMENT_DATA_DIR` sets the base directory for resolving relative paths in `save_data_file`. If not set, relative paths resolve against the current working directory.
|
|
56
|
+
|
|
57
|
+
### 2.2 Claude Desktop Configuration
|
|
58
|
+
|
|
59
|
+
Add to `claude_desktop_config.json`:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"site-calc-investment": {
|
|
65
|
+
"command": "C:\\Users\\Admin\\.local\\bin\\uv.exe",
|
|
66
|
+
"args": [
|
|
67
|
+
"run",
|
|
68
|
+
"--directory", "C:\\my_source\\site-calc\\client-investment",
|
|
69
|
+
"site-calc-investment-mcp"
|
|
70
|
+
],
|
|
71
|
+
"env": {
|
|
72
|
+
"INVESTMENT_API_URL": "https://api.site-calc.example.com",
|
|
73
|
+
"INVESTMENT_API_KEY": "inv_your_api_key_here",
|
|
74
|
+
"INVESTMENT_DATA_DIR": "C:\\my_source\\BESS_Optimization_Tool"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 2.3 Installation
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pip install site-calc-investment[mcp]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Or with uv (recommended for development):
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
cd client-investment
|
|
91
|
+
uv sync --group dev
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 3. Tool Reference
|
|
97
|
+
|
|
98
|
+
### 3.1 Scenario Assembly Tools
|
|
99
|
+
|
|
100
|
+
#### `create_scenario`
|
|
101
|
+
|
|
102
|
+
Create a new draft optimization scenario.
|
|
103
|
+
|
|
104
|
+
| Parameter | Type | Required | Description |
|
|
105
|
+
|-----------|------|----------|-------------|
|
|
106
|
+
| `name` | string | Yes | Human-readable name |
|
|
107
|
+
| `description` | string | No | Longer description |
|
|
108
|
+
|
|
109
|
+
**Returns:** `{"scenario_id": "sc_...", "name": "..."}`
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
#### `add_device`
|
|
114
|
+
|
|
115
|
+
Add a device to a draft scenario.
|
|
116
|
+
|
|
117
|
+
| Parameter | Type | Required | Description |
|
|
118
|
+
|-----------|------|----------|-------------|
|
|
119
|
+
| `scenario_id` | string | Yes | Target scenario |
|
|
120
|
+
| `device_type` | string | Yes | One of 10 device types (see Section 4) |
|
|
121
|
+
| `name` | string | Yes | Unique device name within scenario |
|
|
122
|
+
| `properties` | object | Yes | Device-specific properties |
|
|
123
|
+
| `schedule` | object | No | Runtime constraints |
|
|
124
|
+
|
|
125
|
+
Properties support data shorthand:
|
|
126
|
+
- A number (e.g., `50.0`) -- expanded to constant array matching the timespan
|
|
127
|
+
- A list (e.g., `[30, 40, 80, 50]`) -- used directly
|
|
128
|
+
- A file reference (e.g., `{"file": "prices.csv", "column": "price_eur"}`) -- loaded from local CSV
|
|
129
|
+
|
|
130
|
+
**Returns:** Summary string.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
#### `set_timespan`
|
|
135
|
+
|
|
136
|
+
Set the optimization time horizon.
|
|
137
|
+
|
|
138
|
+
| Parameter | Type | Required | Default | Description |
|
|
139
|
+
|-----------|------|----------|---------|-------------|
|
|
140
|
+
| `scenario_id` | string | Yes | | Target scenario |
|
|
141
|
+
| `start_year` | int | Yes | | Start year (e.g., 2025) |
|
|
142
|
+
| `years` | int | No | 1 | Number of years |
|
|
143
|
+
|
|
144
|
+
One year = 8,760 intervals. Maximum ~11 years (100,000 intervals).
|
|
145
|
+
|
|
146
|
+
**Returns:** Confirmation string with interval count.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
#### `set_investment_params`
|
|
151
|
+
|
|
152
|
+
Set financial parameters for ROI calculation (NPV, IRR, payback).
|
|
153
|
+
|
|
154
|
+
| Parameter | Type | Required | Default | Description |
|
|
155
|
+
|-----------|------|----------|---------|-------------|
|
|
156
|
+
| `scenario_id` | string | Yes | | Target scenario |
|
|
157
|
+
| `discount_rate` | float | No | 0.05 | Annual discount rate (0-0.5) |
|
|
158
|
+
| `project_lifetime_years` | int | No | timespan years | Project lifetime |
|
|
159
|
+
| `device_capital_costs` | object | No | | CAPEX by device name (EUR) |
|
|
160
|
+
| `device_annual_opex` | object | No | | Annual O&M by device name (EUR) |
|
|
161
|
+
|
|
162
|
+
**Returns:** Confirmation string.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
#### `review_scenario`
|
|
167
|
+
|
|
168
|
+
Show a summary of the draft scenario before submitting.
|
|
169
|
+
|
|
170
|
+
| Parameter | Type | Required | Description |
|
|
171
|
+
|-----------|------|----------|-------------|
|
|
172
|
+
| `scenario_id` | string | Yes | Scenario to review |
|
|
173
|
+
|
|
174
|
+
**Returns:** Dict with `name`, `devices`, `timespan`, `investment_params`, `validation`.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
#### `remove_device`
|
|
179
|
+
|
|
180
|
+
Remove a device from a draft scenario.
|
|
181
|
+
|
|
182
|
+
| Parameter | Type | Required | Description |
|
|
183
|
+
|-----------|------|----------|-------------|
|
|
184
|
+
| `scenario_id` | string | Yes | Target scenario |
|
|
185
|
+
| `device_name` | string | Yes | Device to remove |
|
|
186
|
+
|
|
187
|
+
**Returns:** Confirmation string.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
#### `delete_scenario`
|
|
192
|
+
|
|
193
|
+
Delete a draft scenario entirely.
|
|
194
|
+
|
|
195
|
+
| Parameter | Type | Required | Description |
|
|
196
|
+
|-----------|------|----------|-------------|
|
|
197
|
+
| `scenario_id` | string | Yes | Scenario to delete |
|
|
198
|
+
|
|
199
|
+
**Returns:** Confirmation string.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
#### `list_scenarios`
|
|
204
|
+
|
|
205
|
+
List all active draft scenarios.
|
|
206
|
+
|
|
207
|
+
**Returns:** List of `{"id", "name", "device_count", "has_timespan", "job_count"}`.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### 3.2 Job Submission and Management Tools
|
|
212
|
+
|
|
213
|
+
#### `submit_scenario`
|
|
214
|
+
|
|
215
|
+
Submit a draft scenario for server-side optimization.
|
|
216
|
+
|
|
217
|
+
| Parameter | Type | Required | Default | Description |
|
|
218
|
+
|-----------|------|----------|---------|-------------|
|
|
219
|
+
| `scenario_id` | string | Yes | | Scenario to submit |
|
|
220
|
+
| `objective` | string | No | `maximize_profit` | Optimization objective |
|
|
221
|
+
| `solver_timeout` | int | No | 300 | Time limit in seconds (max 900) |
|
|
222
|
+
|
|
223
|
+
Objectives: `maximize_profit`, `minimize_cost`, `maximize_self_consumption`.
|
|
224
|
+
|
|
225
|
+
**Returns:** `{"job_id": "...", "status": "pending"}`
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
#### `get_job_status`
|
|
230
|
+
|
|
231
|
+
Check job status and progress.
|
|
232
|
+
|
|
233
|
+
| Parameter | Type | Required | Description |
|
|
234
|
+
|-----------|------|----------|-------------|
|
|
235
|
+
| `job_id` | string | Yes | Job identifier |
|
|
236
|
+
|
|
237
|
+
**Returns:** Dict with `job_id`, `status`, and optionally `progress`, `message`, `estimated_completion_seconds`, `solver_time_seconds`, `error`.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
#### `get_job_result`
|
|
242
|
+
|
|
243
|
+
Retrieve completed optimization results.
|
|
244
|
+
|
|
245
|
+
| Parameter | Type | Required | Default | Description |
|
|
246
|
+
|-----------|------|----------|---------|-------------|
|
|
247
|
+
| `job_id` | string | Yes | | Job identifier |
|
|
248
|
+
| `detail_level` | string | No | `summary` | `summary`, `monthly`, or `full` |
|
|
249
|
+
|
|
250
|
+
Detail levels:
|
|
251
|
+
- **summary** -- Aggregated totals (profit, cost, solve time, investment metrics). Compact.
|
|
252
|
+
- **monthly** -- Summary + per-device monthly breakdowns.
|
|
253
|
+
- **full** -- All data including hourly schedules. Can be very large.
|
|
254
|
+
|
|
255
|
+
**Returns:** Result dict at requested detail level.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
#### `cancel_job`
|
|
260
|
+
|
|
261
|
+
Cancel a pending or running job.
|
|
262
|
+
|
|
263
|
+
| Parameter | Type | Required | Description |
|
|
264
|
+
|-----------|------|----------|-------------|
|
|
265
|
+
| `job_id` | string | Yes | Job to cancel |
|
|
266
|
+
|
|
267
|
+
**Returns:** `{"job_id": "...", "status": "cancelled"}`
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
#### `list_jobs`
|
|
272
|
+
|
|
273
|
+
List all scenarios and their associated jobs.
|
|
274
|
+
|
|
275
|
+
**Returns:** List of `{"scenario_id", "scenario_name", "job_ids", "job_count"}`.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
### 3.3 Data File Tools
|
|
280
|
+
|
|
281
|
+
#### `save_data_file`
|
|
282
|
+
|
|
283
|
+
Save generated data to a CSV file on the local filesystem.
|
|
284
|
+
|
|
285
|
+
This tool exists because the LLM cannot write files directly, but this MCP server runs locally and can. Use it to persist generated data arrays (prices, demand profiles, etc.) so they can be referenced in `add_device` via `{"file": "<path>", "column": "<name>"}`.
|
|
286
|
+
|
|
287
|
+
| Parameter | Type | Required | Default | Description |
|
|
288
|
+
|-----------|------|----------|---------|-------------|
|
|
289
|
+
| `file_path` | string | Yes | | Filename or path (e.g., `"prices_2025.csv"`) |
|
|
290
|
+
| `columns` | object | Yes | | Named columns: `{"col_name": [float, ...]}` |
|
|
291
|
+
| `overwrite` | bool | No | false | Allow overwriting existing files |
|
|
292
|
+
|
|
293
|
+
Path resolution:
|
|
294
|
+
- Absolute paths are used as-is
|
|
295
|
+
- Relative paths resolve against `INVESTMENT_DATA_DIR` (or cwd if not set)
|
|
296
|
+
- `.csv` extension is appended if missing
|
|
297
|
+
- Non-`.csv` extensions are rejected
|
|
298
|
+
|
|
299
|
+
**Returns:**
|
|
300
|
+
```json
|
|
301
|
+
{
|
|
302
|
+
"file_path": "C:\\Users\\Admin\\data\\prices.csv",
|
|
303
|
+
"columns": ["hour", "price_eur_mwh"],
|
|
304
|
+
"rows": 8760,
|
|
305
|
+
"message": "Saved 8760 rows to C:\\Users\\Admin\\data\\prices.csv"
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
**Typical workflow:**
|
|
310
|
+
```
|
|
311
|
+
1. LLM generates price array (8760 values)
|
|
312
|
+
2. LLM calls save_data_file(file_path="prices_2025.csv", columns={"price_eur": [...]})
|
|
313
|
+
3. LLM calls add_device(properties={"price": {"file": "C:/.../prices_2025.csv", "column": "price_eur"}, ...})
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
### 3.4 Helper Tools
|
|
319
|
+
|
|
320
|
+
#### `get_device_schema`
|
|
321
|
+
|
|
322
|
+
Get the properties schema for a device type.
|
|
323
|
+
|
|
324
|
+
| Parameter | Type | Required | Description |
|
|
325
|
+
|-----------|------|----------|-------------|
|
|
326
|
+
| `device_type` | string | Yes | Device type name |
|
|
327
|
+
|
|
328
|
+
**Returns:** Schema dict with `properties`, `supports_schedule`, `example`.
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## 4. Supported Device Types
|
|
333
|
+
|
|
334
|
+
| Device Type | Description | Key Properties |
|
|
335
|
+
|-------------|-------------|----------------|
|
|
336
|
+
| `battery` | Battery energy storage | capacity, max_power, efficiency |
|
|
337
|
+
| `chp` | Combined heat and power | gas_input, el_output, heat_output |
|
|
338
|
+
| `heat_accumulator` | Thermal storage | capacity, max_power, efficiency |
|
|
339
|
+
| `photovoltaic` | Solar PV | peak_power_mw, location, tilt, azimuth |
|
|
340
|
+
| `electricity_import` | Buy from grid | price, max_import |
|
|
341
|
+
| `electricity_export` | Sell to grid | price, max_export |
|
|
342
|
+
| `gas_import` | Gas supply | price, max_import |
|
|
343
|
+
| `heat_export` | Sell heat | price, max_export |
|
|
344
|
+
| `electricity_demand` | Electricity load | max_demand_profile |
|
|
345
|
+
| `heat_demand` | Heat load | max_demand_profile |
|
|
346
|
+
|
|
347
|
+
Use `get_device_schema(device_type)` for full property documentation.
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 5. End-to-End Example
|
|
352
|
+
|
|
353
|
+
A typical session for battery arbitrage analysis:
|
|
354
|
+
|
|
355
|
+
```
|
|
356
|
+
User: "Evaluate a 10 MWh battery with 2025 German electricity prices"
|
|
357
|
+
|
|
358
|
+
LLM actions:
|
|
359
|
+
1. Generate 8760 hourly prices for 2025
|
|
360
|
+
2. save_data_file(file_path="de_prices_2025.csv",
|
|
361
|
+
columns={"hour": [0..8759], "price_eur_mwh": [32.1, 28.5, ...]})
|
|
362
|
+
3. create_scenario(name="10 MWh Battery - DE 2025")
|
|
363
|
+
4. set_timespan(scenario_id=sid, start_year=2025)
|
|
364
|
+
5. add_device(scenario_id=sid, device_type="battery", name="BESS",
|
|
365
|
+
properties={"capacity": 10.0, "max_power": 5.0, "efficiency": 0.90})
|
|
366
|
+
6. add_device(scenario_id=sid, device_type="electricity_import", name="GridBuy",
|
|
367
|
+
properties={"price": {"file": ".../de_prices_2025.csv", "column": "price_eur_mwh"},
|
|
368
|
+
"max_import": 5.0})
|
|
369
|
+
7. add_device(scenario_id=sid, device_type="electricity_export", name="GridSell",
|
|
370
|
+
properties={"price": {"file": ".../de_prices_2025.csv", "column": "price_eur_mwh"},
|
|
371
|
+
"max_export": 5.0})
|
|
372
|
+
8. set_investment_params(scenario_id=sid, discount_rate=0.05,
|
|
373
|
+
device_capital_costs={"BESS": 500000})
|
|
374
|
+
9. review_scenario(scenario_id=sid)
|
|
375
|
+
10. submit_scenario(scenario_id=sid)
|
|
376
|
+
11. get_job_status(job_id=jid) -- poll until complete
|
|
377
|
+
12. get_job_result(job_id=jid, detail_level="summary")
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
LLM then presents the results: profit, NPV, IRR, payback period.
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## 6. Error Handling
|
|
385
|
+
|
|
386
|
+
Tools raise standard Python exceptions that FastMCP translates to MCP error responses:
|
|
387
|
+
|
|
388
|
+
| Exception | Cause |
|
|
389
|
+
|-----------|-------|
|
|
390
|
+
| `ValueError` | Invalid parameters (wrong device type, missing properties, bad column data) |
|
|
391
|
+
| `FileNotFoundError` | Referenced CSV/JSON file does not exist |
|
|
392
|
+
| `FileExistsError` | `save_data_file` with `overwrite=False` on existing file |
|
|
393
|
+
| `KeyError` | Nonexistent scenario_id or device_name |
|
|
394
|
+
|
|
395
|
+
The LLM receives error messages and can retry with corrected parameters.
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## 7. Testing
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
# Run MCP server tests
|
|
403
|
+
cd client-investment && uv run pytest tests/test_mcp/ -v
|
|
404
|
+
|
|
405
|
+
# Run full test suite
|
|
406
|
+
cd client-investment && uv run pytest tests/ -v
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Test coverage includes:
|
|
410
|
+
- 11 tests for `save_csv` data layer
|
|
411
|
+
- 2 tests for `save_data_file` tool integration
|
|
412
|
+
- 7 MCP protocol integration tests (via FastMCP Client)
|
|
413
|
+
- 77+ tests for scenario assembly and job management tools
|
{site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/examples/01_basic_capacity_planning.py
RENAMED
|
@@ -22,6 +22,7 @@ from site_calc_investment.models.requests import TimeSpanInvestment
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def main():
|
|
25
|
+
"""Run basic capacity planning example with 1-week battery optimization."""
|
|
25
26
|
# Get credentials from environment
|
|
26
27
|
api_url = os.environ.get("INVESTMENT_API_URL_DEV") or os.environ.get("INVESTMENT_API_URL")
|
|
27
28
|
api_key = os.environ.get("INVESTMENT_API_KEY_DEV") or os.environ.get("INVESTMENT_API_KEY")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "site-calc-investment"
|
|
3
|
-
version = "1.2.
|
|
3
|
+
version = "1.2.3"
|
|
4
4
|
description = "Python client for Site-Calc investment planning (capacity sizing, ROI analysis)"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -29,6 +29,7 @@ dependencies = [
|
|
|
29
29
|
]
|
|
30
30
|
|
|
31
31
|
[project.optional-dependencies]
|
|
32
|
+
mcp = ["fastmcp>=2.0"]
|
|
32
33
|
dev = [
|
|
33
34
|
"pytest>=7.0",
|
|
34
35
|
"pytest-cov>=4.0",
|
|
@@ -38,8 +39,12 @@ dev = [
|
|
|
38
39
|
"mypy>=1.0",
|
|
39
40
|
"pandas>=2.0", # For scenario comparison
|
|
40
41
|
"tzdata>=2024.1", # Timezone data for Windows
|
|
42
|
+
"fastmcp>=2.0", # For MCP server tests
|
|
41
43
|
]
|
|
42
44
|
|
|
45
|
+
[project.scripts]
|
|
46
|
+
site-calc-investment-mcp = "site_calc_investment.mcp:main"
|
|
47
|
+
|
|
43
48
|
[project.urls]
|
|
44
49
|
Homepage = "https://github.com/stranma/site-calc-investment"
|
|
45
50
|
Documentation = "https://github.com/stranma/site-calc-investment#readme"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""MCP server for Site-Calc investment planning.
|
|
2
|
+
|
|
3
|
+
Exposes investment optimization tools to LLM agents via FastMCP.
|
|
4
|
+
Install with: pip install site-calc-investment[mcp]
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from site_calc_investment.mcp.server import mcp
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main() -> None:
|
|
11
|
+
"""Entry point for the MCP server."""
|
|
12
|
+
mcp.run()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = ["main", "mcp"]
|