epanet-mcp-server 0.1.0__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.
- epanet_mcp_server-0.1.0/LICENSE +21 -0
- epanet_mcp_server-0.1.0/PKG-INFO +196 -0
- epanet_mcp_server-0.1.0/README.md +177 -0
- epanet_mcp_server-0.1.0/pyproject.toml +35 -0
- epanet_mcp_server-0.1.0/setup.cfg +4 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp/__init__.py +3 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp/server.py +851 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp/session.py +88 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp/tools/__init__.py +1 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp/tools/inspection.py +295 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp/tools/modification.py +635 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp/tools/scenarios.py +497 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp/tools/simulation.py +197 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp/utils.py +58 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp_server.egg-info/PKG-INFO +196 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp_server.egg-info/SOURCES.txt +22 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp_server.egg-info/dependency_links.txt +1 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp_server.egg-info/entry_points.txt +2 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp_server.egg-info/requires.txt +9 -0
- epanet_mcp_server-0.1.0/src/epanet_mcp_server.egg-info/top_level.txt +1 -0
- epanet_mcp_server-0.1.0/tests/test_inspection.py +91 -0
- epanet_mcp_server-0.1.0/tests/test_modification.py +117 -0
- epanet_mcp_server-0.1.0/tests/test_scenarios.py +149 -0
- epanet_mcp_server-0.1.0/tests/test_simulation.py +50 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026- EURECAT.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: epanet-mcp-server
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server for EPANET water distribution network simulation via ePyT
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: epanet,epyt,mcp,water-distribution,hydraulic-simulation
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: mcp>=1.0.0
|
|
11
|
+
Requires-Dist: epyt>=2.0.0
|
|
12
|
+
Requires-Dist: numpy>=1.24.0
|
|
13
|
+
Requires-Dist: pandas>=2.0.0
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
16
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
17
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# EPANET MCP Server
|
|
21
|
+
|
|
22
|
+
[](https://github.com/Applied-Artificial-Intelligence-Eurecat/epanet-mcp-server/actions/workflows/linter.yml)
|
|
23
|
+
[](https://github.com/Applied-Artificial-Intelligence-Eurecat/epanet-mcp-server/actions/workflows/test.yml)
|
|
24
|
+
|
|
25
|
+
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that
|
|
26
|
+
exposes EPANET water-distribution network modelling capabilities through
|
|
27
|
+
[ePyT](https://github.com/KIOS-Research/EPyT) - the EPANET Python Toolkit.
|
|
28
|
+
|
|
29
|
+
Any MCP-compatible LLM can load water network models, run
|
|
30
|
+
simulations, modify parameters, and generate complex what-if scenarios through
|
|
31
|
+
natural language.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
| Category | Tools |
|
|
38
|
+
|---|---|
|
|
39
|
+
| **Load & Inspect** | `load_network`, `unload_network`, `list_networks`, `list_bundled_networks`, `get_network_summary`, `get_nodes`, `get_links`, `get_patterns`, `get_controls`, `get_curves`, `get_options` |
|
|
40
|
+
| **Simulate** | `run_hydraulic_simulation`, `run_quality_simulation`, `run_full_simulation`, `get_pressure_at_time`, `get_flow_at_time` |
|
|
41
|
+
| **Modify** | `set_node_base_demand`, `set_pattern`, `add_pattern`, `set_pipe_diameter`, `set_pipe_roughness`, `set_pipe_status`, `set_pipe_length`, `set_pump_status`, `set_pump_speed`, `set_pump_head_curve`, `set_valve_setting`, `set_valve_status`, `set_tank_parameters`, `set_reservoir_head`, `set_simulation_duration`, `set_hydraulic_timestep`, `set_quality_timestep`, `set_quality_type`, `add_control`, `delete_control`, `save_network` |
|
|
42
|
+
| **Scenarios** | `create_demand_perturbation`, `create_leakage_event`, `create_contamination_event`, `create_pressure_change_scenario`, `create_pump_control_scenario`, `create_valve_control_scenario`, `create_multi_failure_scenario` |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Requirements
|
|
47
|
+
|
|
48
|
+
- Python ≥ 3.10
|
|
49
|
+
- [ePyT](https://pypi.org/project/epyt/) ≥ 2.0
|
|
50
|
+
- [mcp](https://pypi.org/project/mcp/) ≥ 1.0
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install epyt mcp
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/Applied-Artificial-Intelligence-Eurecat/epanet-mcp-server.git
|
|
62
|
+
cd epanet-mcp-server
|
|
63
|
+
pip install -e .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Running the server
|
|
69
|
+
|
|
70
|
+
### stdio (for Claude Desktop / Claude Code)
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
epanet-mcp-server
|
|
74
|
+
# or
|
|
75
|
+
python -m epanet_mcp.server
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### SSE / HTTP
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
epanet-mcp-server --transport sse --port 8000
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Claude Desktop configuration
|
|
87
|
+
|
|
88
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
89
|
+
(macOS) or the equivalent on your platform:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"mcpServers": {
|
|
94
|
+
"epanet": {
|
|
95
|
+
"command": "epanet-mcp-server",
|
|
96
|
+
"args": []
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
If not on `PATH`:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"mcpServers": {
|
|
107
|
+
"epanet": {
|
|
108
|
+
"command": "python",
|
|
109
|
+
"args": ["-m", "epanet_mcp.server"],
|
|
110
|
+
"cwd": "/path/to/epanet-mcp-server/src"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Claude Code (`.mcp.json`)
|
|
119
|
+
|
|
120
|
+
Place this in the root of your project or `~/.claude/`:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"mcpServers": {
|
|
125
|
+
"epanet": {
|
|
126
|
+
"command": "epanet-mcp-server",
|
|
127
|
+
"args": []
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Example interactions
|
|
136
|
+
|
|
137
|
+
Once the server is connected, you can ask things like:
|
|
138
|
+
|
|
139
|
+
> **"Load Net1.inp and show me a summary of the network."**
|
|
140
|
+
|
|
141
|
+
> **"Run a hydraulic simulation and tell me which node has the lowest pressure at hour 12."**
|
|
142
|
+
|
|
143
|
+
> **"Double the base demand at junction 11 and re-run the simulation. How does pressure change?"**
|
|
144
|
+
|
|
145
|
+
> **"Simulate a burst on pipe 10 with a 20% leakage fraction."**
|
|
146
|
+
|
|
147
|
+
> **"Inject 10 mg/L of chlorine at node 11 between hours 1 and 3 and show me the contamination spread."**
|
|
148
|
+
|
|
149
|
+
> **"What happens to pressures if the reservoir head drops from 150 m to 120 m?"**
|
|
150
|
+
|
|
151
|
+
> **"Schedule Pump 9 to start at 06:00 and stop at 22:00."**
|
|
152
|
+
|
|
153
|
+
> **"Close pipes 10 and 11 and the pump simultaneously. Where are service disruptions?"**
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Architecture
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
src/epanet_mcp/
|
|
161
|
+
├── server.py # FastMCP server – tool registration + entry point
|
|
162
|
+
├── session.py # Thread-safe registry of open ePyT sessions
|
|
163
|
+
├── utils.py # numpy → Python serialisation helpers
|
|
164
|
+
└── tools/
|
|
165
|
+
├── inspection.py # load / inspect network models
|
|
166
|
+
├── simulation.py # run hydraulic & quality simulations
|
|
167
|
+
├── modification.py# in-memory parameter changes
|
|
168
|
+
└── scenarios.py # what-if scenario generators (clone + modify + run)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Session model**: Each loaded network lives in a named session. Scenario
|
|
172
|
+
tools automatically clone the source session into a new independent session so
|
|
173
|
+
the baseline network is never mutated.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Running the tests
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
pip install pytest
|
|
181
|
+
pytest tests/ -v
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Bundled networks
|
|
187
|
+
|
|
188
|
+
ePyT ships with many standard benchmark networks including Net1, Net2, L-TOWN,
|
|
189
|
+
Hanoi, Anytown, Balerma and others. Use `list_bundled_networks` to discover
|
|
190
|
+
them all.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
MIT
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# EPANET MCP Server
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Applied-Artificial-Intelligence-Eurecat/epanet-mcp-server/actions/workflows/linter.yml)
|
|
4
|
+
[](https://github.com/Applied-Artificial-Intelligence-Eurecat/epanet-mcp-server/actions/workflows/test.yml)
|
|
5
|
+
|
|
6
|
+
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that
|
|
7
|
+
exposes EPANET water-distribution network modelling capabilities through
|
|
8
|
+
[ePyT](https://github.com/KIOS-Research/EPyT) - the EPANET Python Toolkit.
|
|
9
|
+
|
|
10
|
+
Any MCP-compatible LLM can load water network models, run
|
|
11
|
+
simulations, modify parameters, and generate complex what-if scenarios through
|
|
12
|
+
natural language.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
| Category | Tools |
|
|
19
|
+
|---|---|
|
|
20
|
+
| **Load & Inspect** | `load_network`, `unload_network`, `list_networks`, `list_bundled_networks`, `get_network_summary`, `get_nodes`, `get_links`, `get_patterns`, `get_controls`, `get_curves`, `get_options` |
|
|
21
|
+
| **Simulate** | `run_hydraulic_simulation`, `run_quality_simulation`, `run_full_simulation`, `get_pressure_at_time`, `get_flow_at_time` |
|
|
22
|
+
| **Modify** | `set_node_base_demand`, `set_pattern`, `add_pattern`, `set_pipe_diameter`, `set_pipe_roughness`, `set_pipe_status`, `set_pipe_length`, `set_pump_status`, `set_pump_speed`, `set_pump_head_curve`, `set_valve_setting`, `set_valve_status`, `set_tank_parameters`, `set_reservoir_head`, `set_simulation_duration`, `set_hydraulic_timestep`, `set_quality_timestep`, `set_quality_type`, `add_control`, `delete_control`, `save_network` |
|
|
23
|
+
| **Scenarios** | `create_demand_perturbation`, `create_leakage_event`, `create_contamination_event`, `create_pressure_change_scenario`, `create_pump_control_scenario`, `create_valve_control_scenario`, `create_multi_failure_scenario` |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Requirements
|
|
28
|
+
|
|
29
|
+
- Python ≥ 3.10
|
|
30
|
+
- [ePyT](https://pypi.org/project/epyt/) ≥ 2.0
|
|
31
|
+
- [mcp](https://pypi.org/project/mcp/) ≥ 1.0
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install epyt mcp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git clone https://github.com/Applied-Artificial-Intelligence-Eurecat/epanet-mcp-server.git
|
|
43
|
+
cd epanet-mcp-server
|
|
44
|
+
pip install -e .
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Running the server
|
|
50
|
+
|
|
51
|
+
### stdio (for Claude Desktop / Claude Code)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
epanet-mcp-server
|
|
55
|
+
# or
|
|
56
|
+
python -m epanet_mcp.server
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### SSE / HTTP
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
epanet-mcp-server --transport sse --port 8000
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Claude Desktop configuration
|
|
68
|
+
|
|
69
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
70
|
+
(macOS) or the equivalent on your platform:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"mcpServers": {
|
|
75
|
+
"epanet": {
|
|
76
|
+
"command": "epanet-mcp-server",
|
|
77
|
+
"args": []
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
If not on `PATH`:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"mcpServers": {
|
|
88
|
+
"epanet": {
|
|
89
|
+
"command": "python",
|
|
90
|
+
"args": ["-m", "epanet_mcp.server"],
|
|
91
|
+
"cwd": "/path/to/epanet-mcp-server/src"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Claude Code (`.mcp.json`)
|
|
100
|
+
|
|
101
|
+
Place this in the root of your project or `~/.claude/`:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"mcpServers": {
|
|
106
|
+
"epanet": {
|
|
107
|
+
"command": "epanet-mcp-server",
|
|
108
|
+
"args": []
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Example interactions
|
|
117
|
+
|
|
118
|
+
Once the server is connected, you can ask things like:
|
|
119
|
+
|
|
120
|
+
> **"Load Net1.inp and show me a summary of the network."**
|
|
121
|
+
|
|
122
|
+
> **"Run a hydraulic simulation and tell me which node has the lowest pressure at hour 12."**
|
|
123
|
+
|
|
124
|
+
> **"Double the base demand at junction 11 and re-run the simulation. How does pressure change?"**
|
|
125
|
+
|
|
126
|
+
> **"Simulate a burst on pipe 10 with a 20% leakage fraction."**
|
|
127
|
+
|
|
128
|
+
> **"Inject 10 mg/L of chlorine at node 11 between hours 1 and 3 and show me the contamination spread."**
|
|
129
|
+
|
|
130
|
+
> **"What happens to pressures if the reservoir head drops from 150 m to 120 m?"**
|
|
131
|
+
|
|
132
|
+
> **"Schedule Pump 9 to start at 06:00 and stop at 22:00."**
|
|
133
|
+
|
|
134
|
+
> **"Close pipes 10 and 11 and the pump simultaneously. Where are service disruptions?"**
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Architecture
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
src/epanet_mcp/
|
|
142
|
+
├── server.py # FastMCP server – tool registration + entry point
|
|
143
|
+
├── session.py # Thread-safe registry of open ePyT sessions
|
|
144
|
+
├── utils.py # numpy → Python serialisation helpers
|
|
145
|
+
└── tools/
|
|
146
|
+
├── inspection.py # load / inspect network models
|
|
147
|
+
├── simulation.py # run hydraulic & quality simulations
|
|
148
|
+
├── modification.py# in-memory parameter changes
|
|
149
|
+
└── scenarios.py # what-if scenario generators (clone + modify + run)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Session model**: Each loaded network lives in a named session. Scenario
|
|
153
|
+
tools automatically clone the source session into a new independent session so
|
|
154
|
+
the baseline network is never mutated.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Running the tests
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
pip install pytest
|
|
162
|
+
pytest tests/ -v
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Bundled networks
|
|
168
|
+
|
|
169
|
+
ePyT ships with many standard benchmark networks including Net1, Net2, L-TOWN,
|
|
170
|
+
Hanoi, Anytown, Balerma and others. Use `list_bundled_networks` to discover
|
|
171
|
+
them all.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
MIT
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "epanet-mcp-server"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "MCP server for EPANET water distribution network simulation via ePyT"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
keywords = ["epanet", "epyt", "mcp", "water-distribution", "hydraulic-simulation"]
|
|
13
|
+
dependencies = [
|
|
14
|
+
"mcp>=1.0.0",
|
|
15
|
+
"epyt>=2.0.0",
|
|
16
|
+
"numpy>=1.24.0",
|
|
17
|
+
"pandas>=2.0.0",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.optional-dependencies]
|
|
21
|
+
dev = [
|
|
22
|
+
"pytest>=7.0",
|
|
23
|
+
"pytest-asyncio>=0.21",
|
|
24
|
+
"ruff>=0.1.0",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
epanet-mcp-server = "epanet_mcp.server:main"
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.packages.find]
|
|
31
|
+
where = ["src"]
|
|
32
|
+
|
|
33
|
+
[tool.pytest.ini_options]
|
|
34
|
+
testpaths = ["tests"]
|
|
35
|
+
asyncio_mode = "auto"
|