paraview-mcp-python 0.1.1__tar.gz → 0.1.2__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.
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/PKG-INFO +208 -33
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/README.md +207 -32
- paraview_mcp_python-0.1.2/bridge/gui_bridge.py +55 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/bridge/models.py +2 -2
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/bridge/server.py +13 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/docs/architecture.md +27 -7
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/docs/python-execute-design.md +8 -4
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/pyproject.toml +2 -2
- paraview_mcp_python-0.1.2/scripts/start_paraview_gui_bridge.py +42 -0
- paraview_mcp_python-0.1.2/tests/test_gui_bridge.py +55 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/.gitignore +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/LICENSE +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/bridge/__init__.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/bridge/command_handler.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/bridge/execution.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/scripts/library/color_by.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/scripts/library/create_contour.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/scripts/library/create_slice.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/scripts/library/open_dataset.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/scripts/library/reset_camera.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/scripts/library/save_screenshot.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/scripts/paraview_bridge_request.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/scripts/start_paraview_bridge.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/src/paraview_mcp_server/__init__.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/src/paraview_mcp_server/headless.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/src/paraview_mcp_server/server.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/tests/__init__.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/tests/test_bridge_server.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/tests/test_command_handler.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/tests/test_protocol.py +0 -0
- {paraview_mcp_python-0.1.1 → paraview_mcp_python-0.1.2}/tests/test_server.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: paraview-mcp-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: MCP server for controlling ParaView via AI assistants
|
|
5
5
|
Project-URL: Homepage, https://github.com/djeada/paraview-mcp-server
|
|
6
6
|
Project-URL: Repository, https://github.com/djeada/paraview-mcp-server
|
|
@@ -31,50 +31,99 @@ Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
|
31
31
|
Requires-Dist: ruff>=0.11; extra == 'dev'
|
|
32
32
|
Description-Content-Type: text/markdown
|
|
33
33
|
|
|
34
|
-
#
|
|
34
|
+
# ParaView MCP Server
|
|
35
35
|
|
|
36
36
|
**Control ParaView with AI assistants through the Model Context Protocol.**
|
|
37
37
|
|
|
38
|
-
`paraview-mcp-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
`paraview-mcp-python` provides an MCP server plus a ParaView-side bridge so
|
|
39
|
+
AI assistants such as Codex CLI and Claude Desktop can inspect a ParaView
|
|
40
|
+
session, open datasets, apply filters, color data, run ParaView Python, and
|
|
41
|
+
export screenshots.
|
|
42
|
+
|
|
43
|
+
The command installed for MCP clients is still:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
paraview-mcp-server
|
|
47
|
+
```
|
|
41
48
|
|
|
42
49
|
---
|
|
43
50
|
|
|
44
|
-
##
|
|
51
|
+
## What Parts Are There?
|
|
52
|
+
|
|
53
|
+
There are three moving pieces:
|
|
54
|
+
|
|
55
|
+
| Part | Runs where | Purpose |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| **MCP client** | Codex CLI, Claude Desktop, or another MCP host | Starts the MCP server and calls tools. |
|
|
58
|
+
| **MCP server** | Normal Python environment | Speaks MCP over stdio and forwards tool calls to ParaView over TCP. |
|
|
59
|
+
| **ParaView GUI bridge** | Already-open ParaView GUI process | Receives TCP JSON commands and executes `paraview.simple` operations in that live GUI session. |
|
|
60
|
+
|
|
61
|
+
The ParaView bridge is the ParaView-side component. It plays the same role as
|
|
62
|
+
the Blender add-on in `blender-mcp-server`: it must run inside the application
|
|
63
|
+
you want to control. For live GUI control, start the bridge from ParaView's
|
|
64
|
+
Python Shell using `scripts/start_paraview_gui_bridge.py`.
|
|
45
65
|
|
|
46
66
|
```
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
67
|
+
┌──────────────────────────────┐ stdio ┌────────────────────────┐
|
|
68
|
+
│ MCP Client │ ◄──────────────► │ MCP Server │
|
|
69
|
+
│ Codex / Claude / other host │ │ paraview-mcp-server │
|
|
70
|
+
└──────────────────────────────┘ └──────────┬─────────────┘
|
|
71
|
+
│ JSON/TCP
|
|
72
|
+
│ 127.0.0.1:9876
|
|
73
|
+
┌──────────▼─────────────┐
|
|
74
|
+
│ ParaView Bridge │
|
|
75
|
+
│ live GUI process │
|
|
76
|
+
└──────────┬─────────────┘
|
|
77
|
+
│
|
|
78
|
+
┌──────────▼─────────────┐
|
|
79
|
+
│ paraview.simple │
|
|
80
|
+
│ ParaView runtime │
|
|
81
|
+
└────────────────────────┘
|
|
54
82
|
```
|
|
55
83
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
84
|
+
Why a ParaView-side bridge? ParaView's useful automation API is
|
|
85
|
+
`paraview.simple`, and it must execute inside a ParaView Python runtime. The
|
|
86
|
+
MCP server itself is only a protocol adapter; it cannot modify a ParaView GUI
|
|
87
|
+
unless the bridge is running inside that GUI process.
|
|
88
|
+
|
|
89
|
+
For live GUI modification, use:
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
Codex/Claude -> MCP server -> bridge inside open ParaView GUI -> live GUI session
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
For headless automation, use:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
Codex/Claude -> MCP server -> bridge inside pvpython -> headless ParaView runtime
|
|
99
|
+
```
|
|
63
100
|
|
|
64
101
|
See [`docs/architecture.md`](docs/architecture.md) for a full diagram, protocol reference,
|
|
65
102
|
and tool namespace table.
|
|
66
103
|
|
|
67
104
|
---
|
|
68
105
|
|
|
69
|
-
##
|
|
106
|
+
## Install
|
|
70
107
|
|
|
71
|
-
###
|
|
108
|
+
### Option A: Install the MCP server from PyPI
|
|
109
|
+
|
|
110
|
+
Use this when you only need the MCP server executable in your normal Python
|
|
111
|
+
environment:
|
|
72
112
|
|
|
73
113
|
```bash
|
|
74
114
|
pip install paraview-mcp-python
|
|
75
115
|
```
|
|
76
116
|
|
|
77
|
-
|
|
117
|
+
This installs:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
paraview-mcp-server
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Option B: Clone this repository for the ParaView bridge
|
|
124
|
+
|
|
125
|
+
The bridge code must be available to ParaView's Python runtime. For live GUI
|
|
126
|
+
control and local development, clone the repository:
|
|
78
127
|
|
|
79
128
|
```bash
|
|
80
129
|
git clone https://github.com/djeada/paraview-mcp-server.git
|
|
@@ -84,18 +133,112 @@ source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
|
84
133
|
pip install -e .
|
|
85
134
|
```
|
|
86
135
|
|
|
87
|
-
|
|
136
|
+
This creates:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
.venv/bin/paraview-mcp-server
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Start Everything
|
|
145
|
+
|
|
146
|
+
Start the pieces in this order.
|
|
147
|
+
|
|
148
|
+
### 1. Start the ParaView GUI Bridge
|
|
149
|
+
|
|
150
|
+
Open ParaView, then run the GUI bridge script from the Python Shell:
|
|
151
|
+
|
|
152
|
+
1. In ParaView, open **Tools -> Python Shell**.
|
|
153
|
+
2. Click **Run Script**.
|
|
154
|
+
3. Select:
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
/absolute/path/to/paraview-mcp-server/scripts/start_paraview_gui_bridge.py
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Expected output:
|
|
161
|
+
|
|
162
|
+
```text
|
|
163
|
+
ParaView MCP GUI bridge started on 127.0.0.1:9876
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
If `paraview-mcp-python` is installed into ParaView's Python environment, you
|
|
167
|
+
can also start the live GUI bridge directly from the Python Shell:
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from bridge.gui_bridge import start_gui_bridge, stop_gui_bridge
|
|
171
|
+
start_gui_bridge()
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Leave ParaView open. MCP commands now modify this live GUI session.
|
|
175
|
+
|
|
176
|
+
To stop the bridge from the ParaView Python Shell:
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
stop_gui_bridge()
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 2. Optional: Start a Headless `pvpython` Bridge
|
|
88
183
|
|
|
89
|
-
|
|
184
|
+
Use this only when you do not need to modify an already-open ParaView GUI:
|
|
90
185
|
|
|
91
186
|
```bash
|
|
187
|
+
cd /path/to/paraview-mcp-server
|
|
92
188
|
pvpython scripts/start_paraview_bridge.py
|
|
93
|
-
# → ParaView bridge ready on 127.0.0.1:9876
|
|
94
189
|
```
|
|
95
190
|
|
|
96
|
-
|
|
191
|
+
Expected output:
|
|
192
|
+
|
|
193
|
+
```text
|
|
194
|
+
ParaView bridge ready on 127.0.0.1:9876
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Keep that terminal running. This controls the `pvpython` session, not a GUI
|
|
198
|
+
window opened separately.
|
|
199
|
+
|
|
200
|
+
### 3. Verify the Bridge Directly
|
|
201
|
+
|
|
202
|
+
Before involving an MCP client, send one raw bridge command:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
python scripts/paraview_bridge_request.py scene.get_info
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Expected response shape:
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"success": true,
|
|
213
|
+
"result": {
|
|
214
|
+
"source_count": 0,
|
|
215
|
+
"active_view_type": "RenderView"
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
If this fails, fix the bridge before configuring Codex or Claude.
|
|
221
|
+
|
|
222
|
+
### 4. Register the MCP Server with Codex CLI
|
|
223
|
+
|
|
224
|
+
If you installed from PyPI:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
codex mcp add paraview -- paraview-mcp-server
|
|
228
|
+
codex mcp list
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
If you are using the local repository:
|
|
97
232
|
|
|
98
|
-
|
|
233
|
+
```bash
|
|
234
|
+
codex mcp add paraview -- /absolute/path/to/paraview-mcp-server/.venv/bin/paraview-mcp-server
|
|
235
|
+
codex mcp list
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Codex starts the MCP server automatically when needed. The ParaView bridge
|
|
239
|
+
must already be running separately.
|
|
240
|
+
|
|
241
|
+
### 5. Register with Claude Desktop
|
|
99
242
|
|
|
100
243
|
**Claude Desktop** — add to `claude_desktop_config.json`:
|
|
101
244
|
|
|
@@ -109,12 +252,42 @@ The bridge listens for JSON commands from the MCP server.
|
|
|
109
252
|
}
|
|
110
253
|
```
|
|
111
254
|
|
|
112
|
-
|
|
255
|
+
For a PyPI install, use the absolute path returned by:
|
|
113
256
|
|
|
114
257
|
```bash
|
|
115
|
-
|
|
258
|
+
which paraview-mcp-server
|
|
116
259
|
```
|
|
117
260
|
|
|
261
|
+
Restart Claude Desktop after editing the config.
|
|
262
|
+
|
|
263
|
+
### 6. Verify Through Your MCP Client
|
|
264
|
+
|
|
265
|
+
With the bridge still running, ask your MCP client:
|
|
266
|
+
|
|
267
|
+
```text
|
|
268
|
+
List all sources in the current ParaView session.
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
The client should call `paraview_scene_list_sources` and return the current
|
|
272
|
+
ParaView pipeline sources from the live GUI session if you started
|
|
273
|
+
`start_paraview_gui_bridge.py`.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## What Can It Control?
|
|
278
|
+
|
|
279
|
+
There are two levels of control:
|
|
280
|
+
|
|
281
|
+
1. **Fixed MCP tools** for common workflows: scene inspection, loading data,
|
|
282
|
+
filters, display/coloring, camera, screenshots, data export, and animation
|
|
283
|
+
export.
|
|
284
|
+
2. **Python execution** through `paraview_python_exec`, which can run trusted
|
|
285
|
+
local Python inside the ParaView bridge session. Use this for anything not
|
|
286
|
+
covered by a fixed tool, including arbitrary `paraview.simple` scripts.
|
|
287
|
+
|
|
288
|
+
So the fixed tool list is intentionally finite, but the Python execution tool
|
|
289
|
+
is the general escape hatch for the broader ParaView API.
|
|
290
|
+
|
|
118
291
|
---
|
|
119
292
|
|
|
120
293
|
## Example prompts
|
|
@@ -261,12 +434,12 @@ Async jobs run in a separate headless `pvpython` process via `HeadlessPvpythonEx
|
|
|
261
434
|
|
|
262
435
|
## Python execution trust model
|
|
263
436
|
|
|
264
|
-
- **Trusted local execution** — `paraview_python_exec` can run arbitrary Python available to
|
|
265
|
-
including imports and full `paraview.simple` workflows.
|
|
437
|
+
- **Trusted local execution** — `paraview_python_exec` can run arbitrary Python available to the active
|
|
438
|
+
ParaView Python process, including imports and full `paraview.simple` workflows.
|
|
266
439
|
- **Output bounding** — stdout/stderr capped at **50 KB**.
|
|
267
440
|
- **Cooperative timeout** — default 30 seconds per script execution.
|
|
268
441
|
- **Script path validation** — optionally restrict execution to approved root directories.
|
|
269
|
-
- The bridge runs inside
|
|
442
|
+
- The bridge runs inside ParaView's Python runtime with the same trust level as that local session.
|
|
270
443
|
- This is a local desktop automation tool — not a public API sandbox.
|
|
271
444
|
|
|
272
445
|
---
|
|
@@ -311,9 +484,11 @@ paraview-mcp-server/
|
|
|
311
484
|
├── bridge/
|
|
312
485
|
│ ├── __init__.py
|
|
313
486
|
│ ├── server.py # TCP socket bridge server
|
|
487
|
+
│ ├── gui_bridge.py # Non-blocking live GUI bridge lifecycle
|
|
314
488
|
│ ├── command_handler.py # Command registry + paraview.simple handlers (27 commands)
|
|
315
489
|
│ └── execution.py # trusted local python.execute helper
|
|
316
490
|
├── scripts/
|
|
491
|
+
│ ├── start_paraview_gui_bridge.py
|
|
317
492
|
│ ├── start_paraview_bridge.py
|
|
318
493
|
│ ├── paraview_bridge_request.py
|
|
319
494
|
│ └── library/ # Reusable pvpython snippets
|
|
@@ -1,47 +1,96 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ParaView MCP Server
|
|
2
2
|
|
|
3
3
|
**Control ParaView with AI assistants through the Model Context Protocol.**
|
|
4
4
|
|
|
5
|
-
`paraview-mcp-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
`paraview-mcp-python` provides an MCP server plus a ParaView-side bridge so
|
|
6
|
+
AI assistants such as Codex CLI and Claude Desktop can inspect a ParaView
|
|
7
|
+
session, open datasets, apply filters, color data, run ParaView Python, and
|
|
8
|
+
export screenshots.
|
|
9
|
+
|
|
10
|
+
The command installed for MCP clients is still:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
paraview-mcp-server
|
|
14
|
+
```
|
|
8
15
|
|
|
9
16
|
---
|
|
10
17
|
|
|
11
|
-
##
|
|
18
|
+
## What Parts Are There?
|
|
19
|
+
|
|
20
|
+
There are three moving pieces:
|
|
21
|
+
|
|
22
|
+
| Part | Runs where | Purpose |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| **MCP client** | Codex CLI, Claude Desktop, or another MCP host | Starts the MCP server and calls tools. |
|
|
25
|
+
| **MCP server** | Normal Python environment | Speaks MCP over stdio and forwards tool calls to ParaView over TCP. |
|
|
26
|
+
| **ParaView GUI bridge** | Already-open ParaView GUI process | Receives TCP JSON commands and executes `paraview.simple` operations in that live GUI session. |
|
|
27
|
+
|
|
28
|
+
The ParaView bridge is the ParaView-side component. It plays the same role as
|
|
29
|
+
the Blender add-on in `blender-mcp-server`: it must run inside the application
|
|
30
|
+
you want to control. For live GUI control, start the bridge from ParaView's
|
|
31
|
+
Python Shell using `scripts/start_paraview_gui_bridge.py`.
|
|
12
32
|
|
|
13
33
|
```
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
34
|
+
┌──────────────────────────────┐ stdio ┌────────────────────────┐
|
|
35
|
+
│ MCP Client │ ◄──────────────► │ MCP Server │
|
|
36
|
+
│ Codex / Claude / other host │ │ paraview-mcp-server │
|
|
37
|
+
└──────────────────────────────┘ └──────────┬─────────────┘
|
|
38
|
+
│ JSON/TCP
|
|
39
|
+
│ 127.0.0.1:9876
|
|
40
|
+
┌──────────▼─────────────┐
|
|
41
|
+
│ ParaView Bridge │
|
|
42
|
+
│ live GUI process │
|
|
43
|
+
└──────────┬─────────────┘
|
|
44
|
+
│
|
|
45
|
+
┌──────────▼─────────────┐
|
|
46
|
+
│ paraview.simple │
|
|
47
|
+
│ ParaView runtime │
|
|
48
|
+
└────────────────────────┘
|
|
21
49
|
```
|
|
22
50
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
Why a ParaView-side bridge? ParaView's useful automation API is
|
|
52
|
+
`paraview.simple`, and it must execute inside a ParaView Python runtime. The
|
|
53
|
+
MCP server itself is only a protocol adapter; it cannot modify a ParaView GUI
|
|
54
|
+
unless the bridge is running inside that GUI process.
|
|
55
|
+
|
|
56
|
+
For live GUI modification, use:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
Codex/Claude -> MCP server -> bridge inside open ParaView GUI -> live GUI session
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
For headless automation, use:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
Codex/Claude -> MCP server -> bridge inside pvpython -> headless ParaView runtime
|
|
66
|
+
```
|
|
30
67
|
|
|
31
68
|
See [`docs/architecture.md`](docs/architecture.md) for a full diagram, protocol reference,
|
|
32
69
|
and tool namespace table.
|
|
33
70
|
|
|
34
71
|
---
|
|
35
72
|
|
|
36
|
-
##
|
|
73
|
+
## Install
|
|
37
74
|
|
|
38
|
-
###
|
|
75
|
+
### Option A: Install the MCP server from PyPI
|
|
76
|
+
|
|
77
|
+
Use this when you only need the MCP server executable in your normal Python
|
|
78
|
+
environment:
|
|
39
79
|
|
|
40
80
|
```bash
|
|
41
81
|
pip install paraview-mcp-python
|
|
42
82
|
```
|
|
43
83
|
|
|
44
|
-
|
|
84
|
+
This installs:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
paraview-mcp-server
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Option B: Clone this repository for the ParaView bridge
|
|
91
|
+
|
|
92
|
+
The bridge code must be available to ParaView's Python runtime. For live GUI
|
|
93
|
+
control and local development, clone the repository:
|
|
45
94
|
|
|
46
95
|
```bash
|
|
47
96
|
git clone https://github.com/djeada/paraview-mcp-server.git
|
|
@@ -51,18 +100,112 @@ source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
|
51
100
|
pip install -e .
|
|
52
101
|
```
|
|
53
102
|
|
|
54
|
-
|
|
103
|
+
This creates:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
.venv/bin/paraview-mcp-server
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Start Everything
|
|
112
|
+
|
|
113
|
+
Start the pieces in this order.
|
|
114
|
+
|
|
115
|
+
### 1. Start the ParaView GUI Bridge
|
|
116
|
+
|
|
117
|
+
Open ParaView, then run the GUI bridge script from the Python Shell:
|
|
118
|
+
|
|
119
|
+
1. In ParaView, open **Tools -> Python Shell**.
|
|
120
|
+
2. Click **Run Script**.
|
|
121
|
+
3. Select:
|
|
122
|
+
|
|
123
|
+
```text
|
|
124
|
+
/absolute/path/to/paraview-mcp-server/scripts/start_paraview_gui_bridge.py
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Expected output:
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
ParaView MCP GUI bridge started on 127.0.0.1:9876
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
If `paraview-mcp-python` is installed into ParaView's Python environment, you
|
|
134
|
+
can also start the live GUI bridge directly from the Python Shell:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from bridge.gui_bridge import start_gui_bridge, stop_gui_bridge
|
|
138
|
+
start_gui_bridge()
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Leave ParaView open. MCP commands now modify this live GUI session.
|
|
142
|
+
|
|
143
|
+
To stop the bridge from the ParaView Python Shell:
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
stop_gui_bridge()
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 2. Optional: Start a Headless `pvpython` Bridge
|
|
55
150
|
|
|
56
|
-
|
|
151
|
+
Use this only when you do not need to modify an already-open ParaView GUI:
|
|
57
152
|
|
|
58
153
|
```bash
|
|
154
|
+
cd /path/to/paraview-mcp-server
|
|
59
155
|
pvpython scripts/start_paraview_bridge.py
|
|
60
|
-
# → ParaView bridge ready on 127.0.0.1:9876
|
|
61
156
|
```
|
|
62
157
|
|
|
63
|
-
|
|
158
|
+
Expected output:
|
|
159
|
+
|
|
160
|
+
```text
|
|
161
|
+
ParaView bridge ready on 127.0.0.1:9876
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Keep that terminal running. This controls the `pvpython` session, not a GUI
|
|
165
|
+
window opened separately.
|
|
166
|
+
|
|
167
|
+
### 3. Verify the Bridge Directly
|
|
168
|
+
|
|
169
|
+
Before involving an MCP client, send one raw bridge command:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
python scripts/paraview_bridge_request.py scene.get_info
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Expected response shape:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"success": true,
|
|
180
|
+
"result": {
|
|
181
|
+
"source_count": 0,
|
|
182
|
+
"active_view_type": "RenderView"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
If this fails, fix the bridge before configuring Codex or Claude.
|
|
188
|
+
|
|
189
|
+
### 4. Register the MCP Server with Codex CLI
|
|
190
|
+
|
|
191
|
+
If you installed from PyPI:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
codex mcp add paraview -- paraview-mcp-server
|
|
195
|
+
codex mcp list
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
If you are using the local repository:
|
|
64
199
|
|
|
65
|
-
|
|
200
|
+
```bash
|
|
201
|
+
codex mcp add paraview -- /absolute/path/to/paraview-mcp-server/.venv/bin/paraview-mcp-server
|
|
202
|
+
codex mcp list
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Codex starts the MCP server automatically when needed. The ParaView bridge
|
|
206
|
+
must already be running separately.
|
|
207
|
+
|
|
208
|
+
### 5. Register with Claude Desktop
|
|
66
209
|
|
|
67
210
|
**Claude Desktop** — add to `claude_desktop_config.json`:
|
|
68
211
|
|
|
@@ -76,12 +219,42 @@ The bridge listens for JSON commands from the MCP server.
|
|
|
76
219
|
}
|
|
77
220
|
```
|
|
78
221
|
|
|
79
|
-
|
|
222
|
+
For a PyPI install, use the absolute path returned by:
|
|
80
223
|
|
|
81
224
|
```bash
|
|
82
|
-
|
|
225
|
+
which paraview-mcp-server
|
|
83
226
|
```
|
|
84
227
|
|
|
228
|
+
Restart Claude Desktop after editing the config.
|
|
229
|
+
|
|
230
|
+
### 6. Verify Through Your MCP Client
|
|
231
|
+
|
|
232
|
+
With the bridge still running, ask your MCP client:
|
|
233
|
+
|
|
234
|
+
```text
|
|
235
|
+
List all sources in the current ParaView session.
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The client should call `paraview_scene_list_sources` and return the current
|
|
239
|
+
ParaView pipeline sources from the live GUI session if you started
|
|
240
|
+
`start_paraview_gui_bridge.py`.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## What Can It Control?
|
|
245
|
+
|
|
246
|
+
There are two levels of control:
|
|
247
|
+
|
|
248
|
+
1. **Fixed MCP tools** for common workflows: scene inspection, loading data,
|
|
249
|
+
filters, display/coloring, camera, screenshots, data export, and animation
|
|
250
|
+
export.
|
|
251
|
+
2. **Python execution** through `paraview_python_exec`, which can run trusted
|
|
252
|
+
local Python inside the ParaView bridge session. Use this for anything not
|
|
253
|
+
covered by a fixed tool, including arbitrary `paraview.simple` scripts.
|
|
254
|
+
|
|
255
|
+
So the fixed tool list is intentionally finite, but the Python execution tool
|
|
256
|
+
is the general escape hatch for the broader ParaView API.
|
|
257
|
+
|
|
85
258
|
---
|
|
86
259
|
|
|
87
260
|
## Example prompts
|
|
@@ -228,12 +401,12 @@ Async jobs run in a separate headless `pvpython` process via `HeadlessPvpythonEx
|
|
|
228
401
|
|
|
229
402
|
## Python execution trust model
|
|
230
403
|
|
|
231
|
-
- **Trusted local execution** — `paraview_python_exec` can run arbitrary Python available to
|
|
232
|
-
including imports and full `paraview.simple` workflows.
|
|
404
|
+
- **Trusted local execution** — `paraview_python_exec` can run arbitrary Python available to the active
|
|
405
|
+
ParaView Python process, including imports and full `paraview.simple` workflows.
|
|
233
406
|
- **Output bounding** — stdout/stderr capped at **50 KB**.
|
|
234
407
|
- **Cooperative timeout** — default 30 seconds per script execution.
|
|
235
408
|
- **Script path validation** — optionally restrict execution to approved root directories.
|
|
236
|
-
- The bridge runs inside
|
|
409
|
+
- The bridge runs inside ParaView's Python runtime with the same trust level as that local session.
|
|
237
410
|
- This is a local desktop automation tool — not a public API sandbox.
|
|
238
411
|
|
|
239
412
|
---
|
|
@@ -278,9 +451,11 @@ paraview-mcp-server/
|
|
|
278
451
|
├── bridge/
|
|
279
452
|
│ ├── __init__.py
|
|
280
453
|
│ ├── server.py # TCP socket bridge server
|
|
454
|
+
│ ├── gui_bridge.py # Non-blocking live GUI bridge lifecycle
|
|
281
455
|
│ ├── command_handler.py # Command registry + paraview.simple handlers (27 commands)
|
|
282
456
|
│ └── execution.py # trusted local python.execute helper
|
|
283
457
|
├── scripts/
|
|
458
|
+
│ ├── start_paraview_gui_bridge.py
|
|
284
459
|
│ ├── start_paraview_bridge.py
|
|
285
460
|
│ ├── paraview_bridge_request.py
|
|
286
461
|
│ └── library/ # Reusable pvpython snippets
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Helpers for starting the bridge from an already-open ParaView GUI session."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from bridge.server import HOST, PORT, ParaViewBridgeServer
|
|
8
|
+
|
|
9
|
+
_SERVER: ParaViewBridgeServer | None = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def start_gui_bridge(host: str = HOST, port: int = PORT) -> dict[str, Any]:
|
|
13
|
+
"""Start the bridge inside the current ParaView Python process.
|
|
14
|
+
|
|
15
|
+
This function is intentionally non-blocking so it can be called from the
|
|
16
|
+
ParaView GUI Python shell without freezing the application.
|
|
17
|
+
"""
|
|
18
|
+
global _SERVER
|
|
19
|
+
if _SERVER is not None and _SERVER.is_running:
|
|
20
|
+
return {
|
|
21
|
+
"host": _SERVER.host,
|
|
22
|
+
"port": _SERVER.port,
|
|
23
|
+
"running": True,
|
|
24
|
+
"already_running": True,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
server = ParaViewBridgeServer(host=host, port=port)
|
|
28
|
+
server.start()
|
|
29
|
+
_SERVER = server
|
|
30
|
+
return {
|
|
31
|
+
"host": server.host,
|
|
32
|
+
"port": server.port,
|
|
33
|
+
"running": True,
|
|
34
|
+
"already_running": False,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def stop_gui_bridge() -> dict[str, Any]:
|
|
39
|
+
"""Stop the bridge started by :func:`start_gui_bridge`."""
|
|
40
|
+
global _SERVER
|
|
41
|
+
if _SERVER is None:
|
|
42
|
+
return {"running": False, "stopped": False}
|
|
43
|
+
|
|
44
|
+
host = _SERVER.host
|
|
45
|
+
port = _SERVER.port
|
|
46
|
+
_SERVER.stop()
|
|
47
|
+
_SERVER = None
|
|
48
|
+
return {"host": host, "port": port, "running": False, "stopped": True}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def gui_bridge_status() -> dict[str, Any]:
|
|
52
|
+
"""Return the current GUI bridge status."""
|
|
53
|
+
if _SERVER is None or not _SERVER.is_running:
|
|
54
|
+
return {"running": False}
|
|
55
|
+
return {"host": _SERVER.host, "port": _SERVER.port, "running": True}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Dependency-free bridge command parameter validation.
|
|
2
2
|
|
|
3
|
-
The bridge runs inside ParaView's
|
|
4
|
-
the MCP server's Python dependencies installed.
|
|
3
|
+
The bridge runs inside ParaView's Python runtime, which commonly does not have
|
|
4
|
+
the MCP server's Python dependencies installed. These classes intentionally
|
|
5
5
|
provide the small ``model_validate(...).model_dump(...)`` surface used by the
|
|
6
6
|
command handler without importing third-party packages.
|
|
7
7
|
"""
|
|
@@ -33,6 +33,18 @@ class ParaViewBridgeServer:
|
|
|
33
33
|
self._handler = CommandHandler()
|
|
34
34
|
self._handler_lock = threading.Lock()
|
|
35
35
|
|
|
36
|
+
@property
|
|
37
|
+
def host(self) -> str:
|
|
38
|
+
return self._host
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def port(self) -> int:
|
|
42
|
+
return self._port
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def is_running(self) -> bool:
|
|
46
|
+
return self._running
|
|
47
|
+
|
|
36
48
|
def start(self):
|
|
37
49
|
if self._running:
|
|
38
50
|
return
|
|
@@ -40,6 +52,7 @@ class ParaViewBridgeServer:
|
|
|
40
52
|
self._server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
41
53
|
self._server_socket.settimeout(1.0)
|
|
42
54
|
self._server_socket.bind((self._host, self._port))
|
|
55
|
+
self._host, self._port = self._server_socket.getsockname()[:2]
|
|
43
56
|
self._server_socket.listen(5)
|
|
44
57
|
self._running = True
|
|
45
58
|
self._thread = threading.Thread(target=self._accept_loop, daemon=True)
|
|
@@ -19,20 +19,26 @@
|
|
|
19
19
|
│ JSON / TCP localhost:9876
|
|
20
20
|
│ (newline-delimited JSON)
|
|
21
21
|
┌──────────▼─────────────┐
|
|
22
|
-
│ ParaView bridge
|
|
23
|
-
│ bridge/ │
|
|
22
|
+
│ ParaView GUI bridge │ Runs inside the open ParaView GUI
|
|
23
|
+
│ bridge/ │ via scripts/start_paraview_gui_bridge.py
|
|
24
24
|
│ · ParaViewBridgeServer│
|
|
25
25
|
│ · CommandHandler │ 27 registered commands
|
|
26
26
|
│ · execute_code() │
|
|
27
27
|
└──────────┬─────────────┘
|
|
28
28
|
│
|
|
29
29
|
┌──────────▼─────────────┐
|
|
30
|
-
│ paraview.simple │ ParaView
|
|
30
|
+
│ paraview.simple │ Live ParaView GUI session
|
|
31
31
|
│ servermanager │
|
|
32
32
|
└────────────────────────┘
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
Alternative headless
|
|
35
|
+
Alternative headless bridge:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
MCP Client → paraview-mcp-server → pvpython scripts/start_paraview_bridge.py
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Alternative headless script transport (no long-running bridge required):
|
|
36
42
|
|
|
37
43
|
```
|
|
38
44
|
┌────────────────────────┐
|
|
@@ -67,6 +73,7 @@ Alternative headless transport (no bridge required):
|
|
|
67
73
|
| Module | Responsibility |
|
|
68
74
|
|---|---|
|
|
69
75
|
| `server.py` | Threaded TCP socket server, newline-delimited JSON framing |
|
|
76
|
+
| `gui_bridge.py` | Non-blocking helpers for starting/stopping the bridge inside ParaView GUI |
|
|
70
77
|
| `command_handler.py` | Command registry mapping 27 command names to `paraview.simple` calls |
|
|
71
78
|
| `execution.py` | `execute_code()` — trusted local Python execution with timeout, output cap, and optional script path validation |
|
|
72
79
|
| `__init__.py` | Package marker |
|
|
@@ -213,20 +220,33 @@ MCP client
|
|
|
213
220
|
|
|
214
221
|
## Lifecycle
|
|
215
222
|
|
|
216
|
-
1. User starts the bridge:
|
|
223
|
+
1. User starts the live GUI bridge from ParaView: **Tools → Python Shell → Run Script**,
|
|
224
|
+
selecting `scripts/start_paraview_gui_bridge.py`.
|
|
217
225
|
2. Bridge server binds to `127.0.0.1:9876` and listens for TCP connections.
|
|
218
226
|
3. User starts an MCP client (Claude Desktop, Codex CLI, etc.)
|
|
219
227
|
4. MCP client spawns `paraview-mcp-server` over stdio.
|
|
220
228
|
5. MCP server connects to bridge on startup (or lazy-connects on first tool call).
|
|
221
229
|
6. User issues a natural language request → client calls an MCP tool → server
|
|
222
230
|
forwards as JSON → bridge dispatches → returns result.
|
|
223
|
-
7. User stops the bridge with
|
|
231
|
+
7. User stops the GUI bridge with `stop_gui_bridge()` in ParaView's Python Shell.
|
|
232
|
+
Server reconnects on next call if the bridge restarts.
|
|
224
233
|
|
|
225
234
|
---
|
|
226
235
|
|
|
227
236
|
## Configuration
|
|
228
237
|
|
|
229
|
-
### Bridge
|
|
238
|
+
### Live GUI Bridge
|
|
239
|
+
|
|
240
|
+
Run this from ParaView's Python Shell with **Run Script**:
|
|
241
|
+
|
|
242
|
+
```text
|
|
243
|
+
scripts/start_paraview_gui_bridge.py
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The script starts a background TCP server in the open ParaView GUI process and
|
|
247
|
+
returns immediately.
|
|
248
|
+
|
|
249
|
+
### Headless Bridge
|
|
230
250
|
|
|
231
251
|
```bash
|
|
232
252
|
pvpython scripts/start_paraview_bridge.py --host 127.0.0.1 --port 9876
|
|
@@ -7,7 +7,10 @@ escape hatch for workflows that require more than the fixed tool set.
|
|
|
7
7
|
|
|
8
8
|
Two transports are supported:
|
|
9
9
|
|
|
10
|
-
1. **Bridge** (default) - code runs inside the
|
|
10
|
+
1. **Bridge** (default) - code runs inside the active bridge process via exec().
|
|
11
|
+
For live GUI control, that process is the open ParaView GUI where
|
|
12
|
+
`scripts/start_paraview_gui_bridge.py` was run. For headless control, it is
|
|
13
|
+
the `pvpython scripts/start_paraview_bridge.py` process.
|
|
11
14
|
2. **Headless** - code runs in a separate pvpython subprocess via HeadlessPvpythonExecutor.
|
|
12
15
|
|
|
13
16
|
---
|
|
@@ -67,9 +70,10 @@ Headless transport adds:
|
|
|
67
70
|
|
|
68
71
|
### Trusted local execution
|
|
69
72
|
|
|
70
|
-
Bridge scripts run inside the local
|
|
71
|
-
Python modules.
|
|
72
|
-
|
|
73
|
+
Bridge scripts run inside the local ParaView Python process and may import
|
|
74
|
+
normal Python modules. In live GUI mode, that is the open ParaView GUI process.
|
|
75
|
+
This is intentional: `paraview_python_exec` is the escape hatch for full
|
|
76
|
+
ParaView automation when the fixed MCP tool set is too small.
|
|
73
77
|
|
|
74
78
|
### Output bounding
|
|
75
79
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "paraview-mcp-python"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.2"
|
|
8
8
|
description = "MCP server for controlling ParaView via AI assistants"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -46,7 +46,7 @@ dev = [
|
|
|
46
46
|
]
|
|
47
47
|
|
|
48
48
|
[tool.hatch.build.targets.wheel]
|
|
49
|
-
packages = ["src/paraview_mcp_server"]
|
|
49
|
+
packages = ["src/paraview_mcp_server", "bridge"]
|
|
50
50
|
|
|
51
51
|
[tool.hatch.build.targets.sdist]
|
|
52
52
|
include = [
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Start the MCP bridge inside an already-open ParaView GUI session.
|
|
2
|
+
|
|
3
|
+
Run from ParaView:
|
|
4
|
+
|
|
5
|
+
Tools -> Python Shell -> Run Script
|
|
6
|
+
|
|
7
|
+
Select this file. The script starts the TCP bridge in a background thread and
|
|
8
|
+
returns immediately, so the ParaView GUI remains usable. MCP commands will then
|
|
9
|
+
modify this open ParaView session.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import logging
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s")
|
|
19
|
+
|
|
20
|
+
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
21
|
+
if REPO_ROOT not in sys.path:
|
|
22
|
+
sys.path.insert(0, REPO_ROOT)
|
|
23
|
+
|
|
24
|
+
from bridge.gui_bridge import gui_bridge_status, start_gui_bridge, stop_gui_bridge # noqa: E402
|
|
25
|
+
|
|
26
|
+
globals()["stop_gui_bridge"] = stop_gui_bridge
|
|
27
|
+
globals()["gui_bridge_status"] = gui_bridge_status
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def main() -> None:
|
|
31
|
+
host = os.environ.get("PARAVIEW_MCP_HOST", "127.0.0.1")
|
|
32
|
+
port = int(os.environ.get("PARAVIEW_MCP_PORT", "9876"))
|
|
33
|
+
status = start_gui_bridge(host=host, port=port)
|
|
34
|
+
state = "already running" if status["already_running"] else "started"
|
|
35
|
+
print(f"ParaView MCP GUI bridge {state} on {status['host']}:{status['port']}")
|
|
36
|
+
print("Verify from a terminal with:")
|
|
37
|
+
print(" python scripts/paraview_bridge_request.py scene.get_info")
|
|
38
|
+
print("Stop from the ParaView Python Shell with:")
|
|
39
|
+
print(" stop_gui_bridge()")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
main()
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Tests for the ParaView GUI bridge lifecycle helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from unittest.mock import MagicMock, patch
|
|
6
|
+
|
|
7
|
+
from bridge import gui_bridge
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def teardown_function(_function):
|
|
11
|
+
gui_bridge.stop_gui_bridge()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_start_gui_bridge_is_non_blocking_and_reports_status():
|
|
15
|
+
with patch("bridge.command_handler.CommandHandler", return_value=MagicMock()):
|
|
16
|
+
status = gui_bridge.start_gui_bridge(port=0)
|
|
17
|
+
|
|
18
|
+
assert status["running"] is True
|
|
19
|
+
assert status["already_running"] is False
|
|
20
|
+
assert status["host"] == "127.0.0.1"
|
|
21
|
+
assert status["port"] > 0
|
|
22
|
+
assert gui_bridge.gui_bridge_status() == {
|
|
23
|
+
"host": status["host"],
|
|
24
|
+
"port": status["port"],
|
|
25
|
+
"running": True,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_start_gui_bridge_is_idempotent():
|
|
30
|
+
with patch("bridge.command_handler.CommandHandler", return_value=MagicMock()):
|
|
31
|
+
first = gui_bridge.start_gui_bridge(port=0)
|
|
32
|
+
second = gui_bridge.start_gui_bridge(port=0)
|
|
33
|
+
|
|
34
|
+
assert first["running"] is True
|
|
35
|
+
assert second == {
|
|
36
|
+
"host": first["host"],
|
|
37
|
+
"port": first["port"],
|
|
38
|
+
"running": True,
|
|
39
|
+
"already_running": True,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_stop_gui_bridge_stops_running_server():
|
|
44
|
+
with patch("bridge.command_handler.CommandHandler", return_value=MagicMock()):
|
|
45
|
+
started = gui_bridge.start_gui_bridge(port=0)
|
|
46
|
+
|
|
47
|
+
stopped = gui_bridge.stop_gui_bridge()
|
|
48
|
+
|
|
49
|
+
assert stopped == {
|
|
50
|
+
"host": started["host"],
|
|
51
|
+
"port": started["port"],
|
|
52
|
+
"running": False,
|
|
53
|
+
"stopped": True,
|
|
54
|
+
}
|
|
55
|
+
assert gui_bridge.gui_bridge_status() == {"running": False}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|