File size: 9,360 Bytes
03e5849
85ece5b
 
 
 
 
 
 
 
 
 
 
 
 
 
03e5849
85ece5b
c8f17d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9e14867
c8f17d6
 
98c386f
 
 
0090fb6
 
9e14867
 
0090fb6
c8f17d6
98c386f
 
0090fb6
 
98c386f
 
 
 
 
 
 
 
 
 
 
 
 
c8f17d6
9e14867
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c8f17d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9e14867
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
---
title: SWMM Analysis MCP Server
emoji: 🌧️
colorFrom: blue
colorTo: red
sdk: docker
app_port: 7860
pinned: false
short_description: Dual-surface MCP + REST EPA-SWMM analysis server.
tags:
  - mcp-server
  - stormwater
  - swmm
  - hydrology
  - agent
---

# 🌧️ SWMM Analysis MCP Server

A dual-surface **MCP + REST** server for deterministic EPA-SWMM stormwater analysis,
with a **built-in multi-provider agent**. Wraps the SWMM6 GIS Tool engine (Rev 23.2):
crash-isolated OpenSWMM simulation, result summaries, Calgary-style criteria
screening, deterministic QA/QC findings, engine-report (`.rpt`) reconciliation,
controlled scenario comparison, and Calgary SWMR draft report generation.

**All outputs are preliminary engineering screening β€” not professional
determinations.** Screening thresholds require confirmation by the responsible
engineer.

## Surfaces

| Surface | Endpoint | For |
|---|---|---|
| **MCP (Streamable HTTP)** | `https://<space-url>/mcp` | Claude Desktop / claude.ai, ChatGPT connectors, Gemini, Codex CLI, LangChain, n8n MCP node, Flowise, Langflow, local MCP clients |
| **REST / OpenAPI** | `POST /api/tool/{name}` Β· catalog `/api/tools` Β· schema `/openapi.json` | Custom GPT Actions, n8n HTTP nodes, webhooks, anything speaking OpenAPI |
| **Built-in agent** | `POST /api/agent` and MCP tool `agent_analyze` | One natural-language call; the server's own LLM loop plans and runs the tools |
| **Files** | `GET /files/{session_id}/{filename}` | Generated SWMR docx / audit-zip downloads |

## Tools (19)

`upload_model` β†’ `run_simulation` β†’ then: `get_node_results`, `get_link_results`,
`get_subcatchment_results`, `get_timeseries` (bounded series with authoritative
`time_of_peak`), `query_results` (validated JSON plans against a 34-table SQLite
store incl. the complete tokenized INP), `get_table_catalog`,
`calgary_screening`, `set_report_details` (site description, design objectives,
methodology, project metadata β€” see the swmr-site-details skill),
`set_report_configuration` (project-specific major routes, criteria,
classifications, drawing inventory, applicable reports and checklist overrides),
`preliminary_design_review` (deterministic findings register incl.
RPT-### reconciliation findings), `get_reconciliation`, `run_scenario` (base never
mutated; deterministic comparison), `attach_figure` (embed client-generated
PNG/JPEG figures into the audited report), `generate_report` (SWMR docx + audit
zip; APPENDIX D reproduces the model .inp and .rpt as fixed-width listings
per the Calgary checklist, with untruncated copies archived under `model/`), `list_sessions`, `close_session`, `agent_analyze`.

### Client-figure workflow (recommended)

When your LLM client plots a hydrograph or map from `get_timeseries` data,
do **not** let it rebuild the report document itself β€” that bypasses the
audited tables and provenance package. Instead:

1. Client generates the figure (its own sandbox / code interpreter).
2. `attach_figure(session_id, image_base64, caption, section="results")`.
3. `generate_report(...)` β€” the figure is embedded at the end of the matching
   Heading-1 section with a caption labelling it *client-attached,
   illustrative*, and it is archived in the audit zip under `figures/` with a
   manifest. The report itself remains the server's verified artifact.

Typical CoC flow: **upload_model β†’ set_report_details β†’
set_report_configuration β†’ run_simulation β†’ deterministic QA/QC and Calgary
screening β†’ generate_report**, reusing the returned `session_id`. Sessions
expire after 6 h of inactivity.

Generated Calgary-style SWMR drafts include a deterministic depth-velocity
criteria figure immediately below Table 9. It plots the tabulated 2011
Alberta/Calgary envelope, the modeled overland-route depth/velocity pairs, and
peak flow by marker colour. The figure PNG and its criterion CSV are retained
in the audit ZIP. The report discloses straight-line interpolation and the need
to verify current and project-specific requirements.

The report also generates Figure 3-1, an automated SWMM model schematic, from
the tokenized INP. It uses `[COORDINATES]` and `[VERTICES]` when available,
falls back to a stable topology layout when coordinates are incomplete, shows
subcatchment runoff routing and hydraulic-link direction, and archives both the
PNG and a generation manifest. It is a topology aid and remains subject to
drawing-to-model reconciliation.

### Legacy zero-value solver options

For dynamic-wave models, explicit zero values for `MAX_TRIALS`,
`HEAD_TOLERANCE`, and `MIN_SURFAREA` are treated as legacy/default sentinels.
The uploaded INP remains immutable. The server creates and runs a derivative
execution copy with unit-aware EPA SWMM defaults, and records every
substitution plus the SHA-256 hashes of both files. Negative or non-numeric
values remain blocking configuration errors. The report audit ZIP retains both
the original and derivative INP files whenever normalization occurs.

## Connecting from each platform

Replace `SPACE` with this Space's direct URL, e.g.
`https://username-swmm-mcp.hf.space` (use the *direct* subdomain, not the
huggingface.co page URL).

### Claude (claude.ai web / desktop, remote connector)
Settings β†’ Connectors β†’ Add custom connector β†’ URL: `SPACE/mcp`.

### Claude Desktop (mcp-remote bridge, or any stdio-only client)
```json
{
  "mcpServers": {
    "swmm-analysis": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "SPACE/mcp"]
    }
  }
}
```

### ChatGPT
Settings β†’ Connectors β†’ Create β†’ MCP server URL: `SPACE/mcp` (Developer mode).
Alternatively build a **Custom GPT** with Actions: import the schema from
`SPACE/openapi.json` β€” the REST surface is designed for this.

### Gemini CLI
```json
// ~/.gemini/settings.json
{ "mcpServers": { "swmm-analysis": { "httpUrl": "SPACE/mcp" } } }
```

### Codex CLI
```toml
# ~/.codex/config.toml
[mcp_servers.swmm-analysis]
url = "SPACE/mcp"
```

### n8n
- **MCP Client Tool node**: endpoint `SPACE/mcp`, transport *HTTP Streamable*.
- Or plain **HTTP Request** nodes against `POST SPACE/api/tool/{name}`.
- Or one-shot: `POST SPACE/api/agent` with `{"question": "...", "provider": "gemini"}`.

### Flowise / Langflow
Add the **Custom MCP** (Flowise) / **MCP Tools** (Langflow) component with a
Streamable-HTTP config pointing at `SPACE/mcp`; the tool list auto-populates.

### LangChain / LangGraph
```python
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({
    "swmm": {"url": "SPACE/mcp", "transport": "streamable_http"}
})
tools = await client.get_tools()   # bind to any model
```

### Local LLMs (Ollama, LM Studio, vLLM)
Two options:
1. Point any local MCP-capable client (e.g. LM Studio, mcp-use) at `SPACE/mcp`.
2. Reverse: let the **server's agent** use your local model β€”
   `POST /api/agent` with `{"provider": "local", "base_url": "http://host:11434/v1", "model": "llama3.1", "question": "..."}`.

## Built-in agent

`POST /api/agent` body:
```json
{
  "question": "Upload this model, run it, and screen velocities against Calgary criteria.",
  "provider": "anthropic",
  "inp_content": "<.inp text or base64>",
  "session_id": "optional-existing-session",
  "allow_report": false
}
```
Providers: `anthropic`, `openai`, `gemini`, `groq`, `mistral`, `local`
(OpenAI-compatible `base_url`). Keys come from **Space secrets**
(`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `GROQ_API_KEY`,
`MISTRAL_API_KEY`) or a per-request `api_key`. Every response includes the
complete `tool_trace` audit trail (tool, arguments, elapsed time, result
preview) β€” the agent may only report numbers that came from tools.

> If your platform is already an MCP client, prefer driving the tools directly:
> your model is the agent, and it sees full (not previewed) tool results.

## Architecture notes

- **Crash isolation**: the native OpenSWMM engine runs only in a one-shot
  subprocess in its own venv (`/opt/swmm-venv`); a segfaulting model cannot
  take down the server.
- **Single source of truth**: MCP, REST, and the agent all dispatch to the
  same typed registry (`tools.py`), so behaviour is identical per platform.
- **Result integrity**: every simulation is cross-checked against the
  engine's own `.rpt` (velocity/flow/depth/continuity); disagreements surface
  as `RPT-###` findings and the verdict is embedded in report manifests.
- **HF Spaces specifics baked in**: DNS-rebinding protection disabled for the
  Spaces proxy, MCP session-manager lifespan wired into FastAPI, stateless
  HTTP + JSON responses for maximum connector compatibility.
- **Sessions**: process-local with TTL sweep; Space restarts clear state
  (persistent storage is not required for the workflow).

## Security

No authentication is enabled by default β€” anyone with the URL can run models
and (if Space secrets are set) spend your LLM keys via `/api/agent`. For
non-demo use, set the Space to private, or front it with an auth proxy, and
prefer per-request `api_key` over Space secrets.

## Local development

```bash
pip install -r requirements.txt
python -m venv /opt/swmm-venv && /opt/swmm-venv/bin/pip install -r worker-requirements.txt
SWMM_WORKER_PYTHON=/opt/swmm-venv/bin/python uvicorn server:app --port 7860
```

Free and non-commercial, for the water-engineering community.