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.
Files changed (54) hide show
  1. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/CHANGELOG.md +35 -0
  2. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/PKG-INFO +58 -1
  3. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/README.md +54 -0
  4. site_calc_investment-1.2.3/docs/MCP_SERVER_SPEC.md +413 -0
  5. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/examples/01_basic_capacity_planning.py +1 -0
  6. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/examples/02_scenario_comparison.py +1 -0
  7. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/pyproject.toml +6 -1
  8. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/__init__.py +1 -1
  9. site_calc_investment-1.2.3/site_calc_investment/mcp/__init__.py +15 -0
  10. site_calc_investment-1.2.3/site_calc_investment/mcp/config.py +40 -0
  11. site_calc_investment-1.2.3/site_calc_investment/mcp/data_loaders.py +241 -0
  12. site_calc_investment-1.2.3/site_calc_investment/mcp/scenario.py +515 -0
  13. site_calc_investment-1.2.3/site_calc_investment/mcp/server.py +758 -0
  14. site_calc_investment-1.2.3/tests/test_mcp/__init__.py +0 -0
  15. site_calc_investment-1.2.3/tests/test_mcp/conftest.py +114 -0
  16. site_calc_investment-1.2.3/tests/test_mcp/test_data_loaders.py +224 -0
  17. site_calc_investment-1.2.3/tests/test_mcp/test_integration.py +252 -0
  18. site_calc_investment-1.2.3/tests/test_mcp/test_mcp_production.py +184 -0
  19. site_calc_investment-1.2.3/tests/test_mcp/test_scenario.py +437 -0
  20. site_calc_investment-1.2.3/tests/test_mcp/test_tools.py +489 -0
  21. site_calc_investment-1.2.3/uv.lock +2430 -0
  22. site_calc_investment-1.2.1/uv.lock +0 -1052
  23. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/.github/workflows/ci.yml +0 -0
  24. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/.github/workflows/publish.yml +0 -0
  25. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/.gitignore +0 -0
  26. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/CONTRIBUTING.md +0 -0
  27. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/LICENSE +0 -0
  28. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/MIGRATION_GUIDE.md +0 -0
  29. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/QUICK_START.md +0 -0
  30. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/READY_TO_PUBLISH.md +0 -0
  31. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/docs/INVESTMENT_CLIENT_SPEC.md +0 -0
  32. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/examples/03_financial_analysis.py +0 -0
  33. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/publish_to_github.bat +0 -0
  34. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/publish_to_github.sh +0 -0
  35. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/analysis/__init__.py +0 -0
  36. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/analysis/comparison.py +0 -0
  37. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/analysis/financial.py +0 -0
  38. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/api/__init__.py +0 -0
  39. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/api/client.py +0 -0
  40. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/exceptions.py +0 -0
  41. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/models/__init__.py +0 -0
  42. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/models/common.py +0 -0
  43. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/models/devices.py +0 -0
  44. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/models/requests.py +0 -0
  45. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/site_calc_investment/models/responses.py +0 -0
  46. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/conftest.py +0 -0
  47. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_api_client.py +0 -0
  48. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_common_models.py +0 -0
  49. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_device_models.py +0 -0
  50. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_financial_analysis.py +0 -0
  51. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_production.py +0 -0
  52. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_request_models.py +0 -0
  53. {site_calc_investment-1.2.1 → site_calc_investment-1.2.3}/tests/test_scenario_comparison.py +0 -0
  54. {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.1
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
@@ -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")
@@ -125,6 +125,7 @@ def create_scenario(
125
125
 
126
126
 
127
127
  def main():
128
+ """Run scenario comparison example comparing three battery sizes."""
128
129
  print("=" * 60)
129
130
  print("BATTERY CAPACITY SIZING: SCENARIO COMPARISON")
130
131
  print("=" * 60)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "site-calc-investment"
3
- version = "1.2.1"
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"
@@ -3,7 +3,7 @@
3
3
  Python client for long-term capacity planning and investment ROI analysis.
4
4
  """
5
5
 
6
- __version__ = "1.2.1"
6
+ __version__ = "1.2.3"
7
7
 
8
8
  from site_calc_investment.analysis import (
9
9
  aggregate_annual,
@@ -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"]