uxarray-mcp 0.3.0__tar.gz → 2026.9.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.
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/PKG-INFO +131 -29
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/README.md +125 -25
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/pyproject.toml +7 -4
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/pyproject.toml.orig +32 -4
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/__init__.py +1 -1
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/app.py +17 -9
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/cli.py +36 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/domain/__init__.py +20 -1
- uxarray_mcp-2026.9.0/src/uxarray_mcp/domain/anomaly_coverage.py +109 -0
- uxarray_mcp-2026.9.0/src/uxarray_mcp/domain/area.py +128 -0
- uxarray_mcp-2026.9.0/src/uxarray_mcp/domain/export_fidelity.py +157 -0
- uxarray_mcp-2026.9.0/src/uxarray_mcp/domain/mesh_coverage.py +242 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/domain/plotting.py +21 -1
- uxarray_mcp-2026.9.0/src/uxarray_mcp/domain/profile_coverage.py +90 -0
- uxarray_mcp-2026.9.0/src/uxarray_mcp/domain/remap_backend.py +110 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/domain/remap_coverage.py +46 -3
- uxarray_mcp-2026.9.0/src/uxarray_mcp/domain/subset_coverage.py +158 -0
- uxarray_mcp-2026.9.0/src/uxarray_mcp/domain/temporal_coverage.py +156 -0
- uxarray_mcp-2026.9.0/src/uxarray_mcp/domain/variable.py +130 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/domain/vector_calc.py +61 -1
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/domain/zonal.py +7 -0
- uxarray_mcp-2026.9.0/src/uxarray_mcp/json_safe.py +107 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/postconditions.py +67 -71
- uxarray_mcp-2026.9.0/src/uxarray_mcp/preconditions.py +784 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/provenance.py +20 -7
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/registry.py +191 -4
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/remote/agent.py +175 -4
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/remote/compute_functions.py +1021 -23
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/remote/config.py +86 -0
- uxarray_mcp-2026.9.0/src/uxarray_mcp/remote/gcp.py +194 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/remote/health.py +11 -4
- uxarray_mcp-2026.9.0/src/uxarray_mcp/remote/transfer.py +637 -0
- uxarray_mcp-2026.9.0/src/uxarray_mcp/resources.py +300 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/response_contract.py +104 -4
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/state.py +191 -22
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/__init__.py +10 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/advanced.py +624 -84
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/catalog.py +128 -15
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/execution_control.py +135 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/frontdoor.py +365 -38
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/inspection.py +20 -3
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/orchestration.py +71 -27
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/plotting.py +77 -76
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/remote_tools.py +319 -28
- uxarray_mcp-2026.9.0/src/uxarray_mcp/tools/transfer_tools.py +305 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/vector_calc.py +12 -0
- uxarray_mcp-2026.9.0/src/uxarray_mcp/transfer_setup.py +545 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/typed_results.py +162 -28
- uxarray_mcp-0.3.0/src/uxarray_mcp/domain/area.py +0 -37
- uxarray_mcp-0.3.0/src/uxarray_mcp/domain/variable.py +0 -77
- uxarray_mcp-0.3.0/src/uxarray_mcp/preconditions.py +0 -330
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/LICENSE +0 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/__main__.py +0 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/content_blocks.py +0 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/domain/dims.py +0 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/domain/mesh.py +0 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/next_steps.py +0 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/py.typed +0 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/remote/__init__.py +0 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/capabilities.py +0 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/contracts.py +0 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/scientific_agent.py +0 -0
- {uxarray_mcp-0.3.0 → uxarray_mcp-2026.9.0}/src/uxarray_mcp/tools/stateful.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: uxarray-mcp
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2026.9.0
|
|
4
4
|
Summary: MCP server for analyzing unstructured meshes with UXarray
|
|
5
5
|
Keywords: uxarray,mcp,unstructured grids,scientific computing,globus compute
|
|
6
6
|
Author: Rajeev Jain, Dayan Abdulla
|
|
@@ -218,17 +218,18 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
218
218
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
219
219
|
Requires-Dist: toolregistry-server[mcp]>=0.5.0
|
|
220
220
|
Requires-Dist: toolregistry>=0.16.0
|
|
221
|
-
Requires-Dist: mcp>=1.
|
|
221
|
+
Requires-Dist: mcp>=1.27,<3
|
|
222
222
|
Requires-Dist: holoviews>=1.19.0
|
|
223
223
|
Requires-Dist: matplotlib>=3.9.0
|
|
224
|
-
Requires-Dist: pyyaml>=6.0
|
|
225
|
-
Requires-Dist: uxarray>=2026.
|
|
224
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
225
|
+
Requires-Dist: uxarray>=2026.9.0,<2026.10
|
|
226
226
|
Requires-Dist: sphinx>=7.0 ; extra == 'docs'
|
|
227
227
|
Requires-Dist: sphinx-book-theme>=1.1.0 ; extra == 'docs'
|
|
228
228
|
Requires-Dist: myst-parser>=3.0 ; extra == 'docs'
|
|
229
229
|
Requires-Dist: academy-py>=0.3.1 ; extra == 'hpc'
|
|
230
230
|
Requires-Dist: globus-compute-sdk>=4.5.0 ; extra == 'hpc'
|
|
231
231
|
Requires-Dist: toolregistry-server[openapi]>=0.5.0 ; extra == 'openapi'
|
|
232
|
+
Requires-Dist: globus-cli>=3.30 ; extra == 'transfer'
|
|
232
233
|
Requires-Python: >=3.11
|
|
233
234
|
Project-URL: Documentation, https://uxarray-mcp-server.readthedocs.io
|
|
234
235
|
Project-URL: Source, https://github.com/UXARRAY/uxarray-mcp-server
|
|
@@ -236,12 +237,13 @@ Project-URL: Tracker, https://github.com/UXARRAY/uxarray-mcp-server/issues
|
|
|
236
237
|
Provides-Extra: docs
|
|
237
238
|
Provides-Extra: hpc
|
|
238
239
|
Provides-Extra: openapi
|
|
240
|
+
Provides-Extra: transfer
|
|
239
241
|
Description-Content-Type: text/markdown
|
|
240
242
|
|
|
241
243
|
# UXarray MCP Server
|
|
242
244
|
|
|
243
|
-
An MCP server that lets an AI assistant (Claude Code, Claude Desktop,
|
|
244
|
-
or any MCP client) analyze unstructured climate meshes with
|
|
245
|
+
An MCP server that lets an AI assistant (Claude Code, Claude Desktop, Codex,
|
|
246
|
+
opencode, Cursor, or any MCP client) analyze unstructured climate meshes with
|
|
245
247
|
[UXarray](https://uxarray.readthedocs.io/) — locally on your machine, or
|
|
246
248
|
remotely on an HPC system you have access to.
|
|
247
249
|
|
|
@@ -288,6 +290,15 @@ You are most likely one of:
|
|
|
288
290
|
5. **Just trying it out, or running an agent harness** — you don't want to
|
|
289
291
|
install a scientific Python stack at all. → [Docker](#docker).
|
|
290
292
|
|
|
293
|
+
**Want to see what this is for before installing anything?** Read the worked
|
|
294
|
+
case study: [**a 10-year CONUS precipitation map from 37 GB that never
|
|
295
|
+
moved**](case-studies/conus-precipitation-gdex/README.md). One paragraph of
|
|
296
|
+
plain English on a laptop, ten years of 6-hourly CESM output on the NCAR
|
|
297
|
+
filesystem, all the compute on a Casper worker, and a 178 KB PNG plus an
|
|
298
|
+
auditable provenance record coming back. It covers what MCP is, what actually
|
|
299
|
+
ran where, why it took 7.7 minutes, what it cost in tokens, and how to set the
|
|
300
|
+
same thing up yourself.
|
|
301
|
+
|
|
291
302
|
---
|
|
292
303
|
|
|
293
304
|
## Docker
|
|
@@ -374,16 +385,22 @@ uv tool install --python 3.12 uxarray-mcp
|
|
|
374
385
|
|
|
375
386
|
# Or from a fresh clone (developer path)
|
|
376
387
|
git clone https://github.com/UXARRAY/uxarray-mcp-server.git
|
|
377
|
-
cd uxarray-mcp-server && uv sync --python 3.12
|
|
378
|
-
# or: bash SETUP.sh (
|
|
388
|
+
cd uxarray-mcp-server && uv sync --python 3.12 --extra hpc --extra transfer
|
|
389
|
+
# or: bash SETUP.sh (local-only sync + runs the local test suite in one step)
|
|
379
390
|
```
|
|
380
391
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
392
|
+
The `hpc` and `transfer` extras hold the Globus Compute and Globus Transfer
|
|
393
|
+
SDKs. Leave them off for a laptop-only install. Note that `uv sync` installs
|
|
394
|
+
*exactly* the requested set: running a plain `uv sync` later removes the
|
|
395
|
+
extras again, and `hpc/endpoint_status` will then report `unreachable` with
|
|
396
|
+
`No module named 'globus_compute_sdk'`.
|
|
397
|
+
|
|
398
|
+
> **Why `--python 3.12`?** Only the HPC path needs it. Globus Compute's
|
|
399
|
+
> serializer is fragile across Python minor versions — a 3.13 submitter
|
|
400
|
+
> against a 3.12 endpoint worker raises `WorkerLost` on non-trivial payloads,
|
|
401
|
+
> and HPC sites broadly ship 3.12 conda stacks today. Local-only use works on
|
|
402
|
+
> 3.11–3.13. Tracking removal of this constraint at
|
|
403
|
+
> [globus/globus-compute#2139](https://github.com/globus/globus-compute/issues/2139).
|
|
387
404
|
> `uv` downloads 3.12 automatically if your system doesn't have it.
|
|
388
405
|
|
|
389
406
|
### Step 2 — Write a starter config
|
|
@@ -395,16 +412,32 @@ uxarray-mcp setup
|
|
|
395
412
|
Creates `~/.config/uxarray-mcp/config.yaml` with sensible defaults. Local mode
|
|
396
413
|
needs nothing more.
|
|
397
414
|
|
|
415
|
+
Three environment variables adjust where the server looks and writes:
|
|
416
|
+
`UXARRAY_MCP_CONFIG` (path to a config file, checked before
|
|
417
|
+
`~/.config/uxarray-mcp/config.yaml`), `UXARRAY_MCP_STATE_DIR` (sessions,
|
|
418
|
+
result handles and rendered plots; default `~/.uxarray_mcp_server`), and
|
|
419
|
+
`UXARRAY_MCP_VERDICT_POLICY` (`full`, `reference_only` or `off` for the
|
|
420
|
+
postcondition block on every result).
|
|
421
|
+
|
|
398
422
|
### Step 3 — Connect your AI client
|
|
399
423
|
|
|
400
424
|
**Claude Desktop**
|
|
401
425
|
|
|
402
426
|
```bash
|
|
403
|
-
|
|
427
|
+
# merges the mcpServers block into the config file you name
|
|
428
|
+
uxarray-mcp install-claude --config-path ~/Library/Application\ Support/Claude/claude_desktop_config.json
|
|
404
429
|
# or
|
|
405
430
|
uxarray-mcp install-claude --print-only # prints the JSON to paste manually
|
|
406
431
|
```
|
|
407
432
|
|
|
433
|
+
Without `--config-path` the command only prints the block; it never guesses
|
|
434
|
+
where your Claude Desktop config lives.
|
|
435
|
+
|
|
436
|
+
If you installed from a clone rather than `uv tool install`, the `uxarray-mcp`
|
|
437
|
+
binary lives in the project `.venv`. In every client config below, use
|
|
438
|
+
`uv --directory /path/to/uxarray-mcp-server run uxarray-mcp serve` as the
|
|
439
|
+
command instead of a bare `uxarray-mcp serve`.
|
|
440
|
+
|
|
408
441
|
Restart Claude Desktop. The `uxarray` server should appear in Settings →
|
|
409
442
|
Developer.
|
|
410
443
|
|
|
@@ -416,10 +449,63 @@ claude mcp add uxarray --transport stdio -- uxarray-mcp serve
|
|
|
416
449
|
|
|
417
450
|
Then `/mcp` in Claude Code; pick `uxarray`.
|
|
418
451
|
|
|
419
|
-
**
|
|
452
|
+
**Codex CLI**
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
codex mcp add uxarray -- uxarray-mcp serve
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
Or write `~/.codex/config.toml` directly:
|
|
459
|
+
|
|
460
|
+
```toml
|
|
461
|
+
[mcp_servers.uxarray]
|
|
462
|
+
command = "uxarray-mcp"
|
|
463
|
+
args = ["serve"]
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
Then `/mcp` in a Codex session.
|
|
420
467
|
|
|
421
|
-
|
|
422
|
-
|
|
468
|
+
**opencode**
|
|
469
|
+
|
|
470
|
+
Add to `~/.config/opencode/opencode.json`:
|
|
471
|
+
|
|
472
|
+
```json
|
|
473
|
+
{
|
|
474
|
+
"mcp": {
|
|
475
|
+
"uxarray": {
|
|
476
|
+
"type": "local",
|
|
477
|
+
"command": ["uxarray-mcp", "serve"],
|
|
478
|
+
"enabled": true
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
The server registers 33 tools, which is a large tool schema to carry on every
|
|
485
|
+
request. `"enabled": false` turns it off for sessions that are not doing mesh
|
|
486
|
+
analysis.
|
|
487
|
+
|
|
488
|
+
**Cursor**
|
|
489
|
+
|
|
490
|
+
Add to `~/.cursor/mcp.json` (or a project-local `.cursor/mcp.json`):
|
|
491
|
+
|
|
492
|
+
```json
|
|
493
|
+
{
|
|
494
|
+
"mcpServers": {
|
|
495
|
+
"uxarray": {
|
|
496
|
+
"command": "uxarray-mcp",
|
|
497
|
+
"args": ["serve"]
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
**Any other MCP client**
|
|
504
|
+
|
|
505
|
+
The server speaks stdio, so every client wants the same two facts — the
|
|
506
|
+
command `uxarray-mcp` and the argument `serve`. `uxarray-mcp install-claude
|
|
507
|
+
--print-only` prints the `mcpServers` JSON block that most clients accept
|
|
508
|
+
verbatim.
|
|
423
509
|
|
|
424
510
|
### Step 4 — Sanity check
|
|
425
511
|
|
|
@@ -476,16 +562,27 @@ Intent-shaped tools, not raw UXarray bindings — all local by default:
|
|
|
476
562
|
- `get_capabilities` — what can I do with this mesh?
|
|
477
563
|
- `analyze_dataset` — deterministic first-look: inspect, validate, area, zonal mean, plots.
|
|
478
564
|
- `run_analysis` — one operation at a time (gradient, curl, subset, remap, …).
|
|
479
|
-
|
|
565
|
+
Remaps take `method`: `nearest_neighbor`, `inverse_distance_weighted` or
|
|
566
|
+
`bilinear` on UXarray's own engine, or `conservative`, `nnn`, `dnn`,
|
|
567
|
+
`average` on [YAC](https://dkrz-sw.gitlab-pages.dkrz.de/yac/) (equivalently
|
|
568
|
+
`backend="yac"` with `yac_method`). Only `conservative` preserves the field
|
|
569
|
+
integral, and it needs YAC importable where the remap runs — build it with
|
|
570
|
+
`scripts/build_yac_local.sh` on a laptop or `scripts/hpc_build_yac.py` on a
|
|
571
|
+
worker, and put its `site-packages` on `PYTHONPATH`.
|
|
572
|
+
- `plot_dataset` — `plot_type` of `mesh`, `mesh_geo`, `variable`, or `zonal_mean`.
|
|
480
573
|
- `run_workflow`, `resume_workflow`, `get_status`, `get_result`, `manage_session` —
|
|
481
574
|
persisted sessions and multi-step workflows.
|
|
482
575
|
|
|
483
|
-
|
|
576
|
+
Helper namespaces also appear in `tools/list`: `session/*`, `hpc/*`,
|
|
577
|
+
`io/list_datasets`, `contract/*` and `prompt/*`.
|
|
578
|
+
|
|
579
|
+
Full schema and every `run_analysis` parameter: [docs/tools.md](docs/tools.md).
|
|
484
580
|
|
|
485
581
|
**Protocol version.** We do not implement MCP directly; servers are built
|
|
486
582
|
through `toolregistry-server`, which depends on the `mcp` Python SDK. As of
|
|
487
583
|
`toolregistry-server` 0.5.0 and `toolregistry` 0.16.0 the SDK cap is lifted, so
|
|
488
|
-
we resolve `mcp` 2.1.1 and negotiate spec
|
|
584
|
+
we resolve `mcp` 1.27 or 2.x (2.1.1 at the last lock) and negotiate spec
|
|
585
|
+
**`2026-07-28`** (stateless core,
|
|
489
586
|
cacheable list results, MRTR). 0.16.0 also widens the recognized content-block
|
|
490
587
|
set to audio, `resource_link`, and embedded resources.
|
|
491
588
|
|
|
@@ -508,10 +605,13 @@ auditable and the server actively flags common scientific pitfalls:
|
|
|
508
605
|
the tool that ran, timestamp, input arguments, `execution_venue`
|
|
509
606
|
(`local` or `hpc:<endpoint>`), and the UXarray/Python versions used.
|
|
510
607
|
- **Derivative unit convention is never hidden.** `gradient`, `curl`, and
|
|
511
|
-
`divergence` echo `scale_by_radius`
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
`
|
|
608
|
+
`divergence` echo `scale_by_radius` and a `radius_basis` block (the radius
|
|
609
|
+
used and whether it came from the grid or the caller), so a unit-sphere
|
|
610
|
+
result can never be mistaken for a physical (per-metre) one. Most grid files
|
|
611
|
+
declare no `sphere_radius`; pass `sphere_radius=6371000` (metres) to attach
|
|
612
|
+
Earth's. Without it, or with `scale_by_radius=False`, the call is refused
|
|
613
|
+
with `outcome="input_required"` until you pass `acknowledge`. The same
|
|
614
|
+
`sphere_radius` argument turns `calculate_area` from steradians into m².
|
|
515
615
|
- **Vector-calculus sanity guard.** `curl`/`divergence` warn (without blocking)
|
|
516
616
|
when the two inputs are the same field, or when neither carries a
|
|
517
617
|
velocity/flux-like `units` attribute — the classic "vorticity from two random
|
|
@@ -533,12 +633,14 @@ auditable and the server actively flags common scientific pitfalls:
|
|
|
533
633
|
|
|
534
634
|
| Command | Purpose |
|
|
535
635
|
|---|---|
|
|
536
|
-
| `uxarray-mcp serve` | Run the MCP server (used by your AI client) |
|
|
636
|
+
| `uxarray-mcp serve` | Run the MCP server (used by your AI client); `--profile core\|deferred-full`, `--transport stdio\|sse\|http` — see [docs/serving.md](docs/serving.md) |
|
|
637
|
+
| `uxarray-mcp openapi` | Print the OpenAPI document for the HTTP transport |
|
|
537
638
|
| `uxarray-mcp setup` | Write a starter config |
|
|
538
639
|
| `uxarray-mcp endpoints add NAME UUID` | Register a Globus Compute endpoint |
|
|
539
|
-
| `uxarray-mcp endpoints list` | Show configured endpoints |
|
|
640
|
+
| `uxarray-mcp endpoints list` / `remove NAME` | Show or drop configured endpoints |
|
|
641
|
+
| `uxarray-mcp transfer setup` | Check and fix everything a Globus Transfer needs, including the browser login an MCP server cannot open |
|
|
540
642
|
| `uxarray-mcp doctor` | Validate local + (optionally) remote setup |
|
|
541
|
-
| `uxarray-mcp install-claude` | Merge or print the Claude Desktop config block |
|
|
643
|
+
| `uxarray-mcp install-claude --config-path FILE` | Merge (or `--print-only`) the Claude Desktop config block |
|
|
542
644
|
|
|
543
645
|
---
|
|
544
646
|
|
|
@@ -579,7 +681,7 @@ see **[SECURITY.md](SECURITY.md)**.
|
|
|
579
681
|
## Development
|
|
580
682
|
|
|
581
683
|
```bash
|
|
582
|
-
uv sync --extra hpc --extra
|
|
684
|
+
uv sync --extra hpc --extra transfer --extra docs
|
|
583
685
|
uv run pre-commit run --all-files
|
|
584
686
|
uv run pytest tests/ --ignore=tests/test_remote_agent.py
|
|
585
687
|
uv run sphinx-build -b html docs docs/_build/html
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# UXarray MCP Server
|
|
2
2
|
|
|
3
|
-
An MCP server that lets an AI assistant (Claude Code, Claude Desktop,
|
|
4
|
-
or any MCP client) analyze unstructured climate meshes with
|
|
3
|
+
An MCP server that lets an AI assistant (Claude Code, Claude Desktop, Codex,
|
|
4
|
+
opencode, Cursor, or any MCP client) analyze unstructured climate meshes with
|
|
5
5
|
[UXarray](https://uxarray.readthedocs.io/) — locally on your machine, or
|
|
6
6
|
remotely on an HPC system you have access to.
|
|
7
7
|
|
|
@@ -48,6 +48,15 @@ You are most likely one of:
|
|
|
48
48
|
5. **Just trying it out, or running an agent harness** — you don't want to
|
|
49
49
|
install a scientific Python stack at all. → [Docker](#docker).
|
|
50
50
|
|
|
51
|
+
**Want to see what this is for before installing anything?** Read the worked
|
|
52
|
+
case study: [**a 10-year CONUS precipitation map from 37 GB that never
|
|
53
|
+
moved**](case-studies/conus-precipitation-gdex/README.md). One paragraph of
|
|
54
|
+
plain English on a laptop, ten years of 6-hourly CESM output on the NCAR
|
|
55
|
+
filesystem, all the compute on a Casper worker, and a 178 KB PNG plus an
|
|
56
|
+
auditable provenance record coming back. It covers what MCP is, what actually
|
|
57
|
+
ran where, why it took 7.7 minutes, what it cost in tokens, and how to set the
|
|
58
|
+
same thing up yourself.
|
|
59
|
+
|
|
51
60
|
---
|
|
52
61
|
|
|
53
62
|
## Docker
|
|
@@ -134,16 +143,22 @@ uv tool install --python 3.12 uxarray-mcp
|
|
|
134
143
|
|
|
135
144
|
# Or from a fresh clone (developer path)
|
|
136
145
|
git clone https://github.com/UXARRAY/uxarray-mcp-server.git
|
|
137
|
-
cd uxarray-mcp-server && uv sync --python 3.12
|
|
138
|
-
# or: bash SETUP.sh (
|
|
146
|
+
cd uxarray-mcp-server && uv sync --python 3.12 --extra hpc --extra transfer
|
|
147
|
+
# or: bash SETUP.sh (local-only sync + runs the local test suite in one step)
|
|
139
148
|
```
|
|
140
149
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
150
|
+
The `hpc` and `transfer` extras hold the Globus Compute and Globus Transfer
|
|
151
|
+
SDKs. Leave them off for a laptop-only install. Note that `uv sync` installs
|
|
152
|
+
*exactly* the requested set: running a plain `uv sync` later removes the
|
|
153
|
+
extras again, and `hpc/endpoint_status` will then report `unreachable` with
|
|
154
|
+
`No module named 'globus_compute_sdk'`.
|
|
155
|
+
|
|
156
|
+
> **Why `--python 3.12`?** Only the HPC path needs it. Globus Compute's
|
|
157
|
+
> serializer is fragile across Python minor versions — a 3.13 submitter
|
|
158
|
+
> against a 3.12 endpoint worker raises `WorkerLost` on non-trivial payloads,
|
|
159
|
+
> and HPC sites broadly ship 3.12 conda stacks today. Local-only use works on
|
|
160
|
+
> 3.11–3.13. Tracking removal of this constraint at
|
|
161
|
+
> [globus/globus-compute#2139](https://github.com/globus/globus-compute/issues/2139).
|
|
147
162
|
> `uv` downloads 3.12 automatically if your system doesn't have it.
|
|
148
163
|
|
|
149
164
|
### Step 2 — Write a starter config
|
|
@@ -155,16 +170,32 @@ uxarray-mcp setup
|
|
|
155
170
|
Creates `~/.config/uxarray-mcp/config.yaml` with sensible defaults. Local mode
|
|
156
171
|
needs nothing more.
|
|
157
172
|
|
|
173
|
+
Three environment variables adjust where the server looks and writes:
|
|
174
|
+
`UXARRAY_MCP_CONFIG` (path to a config file, checked before
|
|
175
|
+
`~/.config/uxarray-mcp/config.yaml`), `UXARRAY_MCP_STATE_DIR` (sessions,
|
|
176
|
+
result handles and rendered plots; default `~/.uxarray_mcp_server`), and
|
|
177
|
+
`UXARRAY_MCP_VERDICT_POLICY` (`full`, `reference_only` or `off` for the
|
|
178
|
+
postcondition block on every result).
|
|
179
|
+
|
|
158
180
|
### Step 3 — Connect your AI client
|
|
159
181
|
|
|
160
182
|
**Claude Desktop**
|
|
161
183
|
|
|
162
184
|
```bash
|
|
163
|
-
|
|
185
|
+
# merges the mcpServers block into the config file you name
|
|
186
|
+
uxarray-mcp install-claude --config-path ~/Library/Application\ Support/Claude/claude_desktop_config.json
|
|
164
187
|
# or
|
|
165
188
|
uxarray-mcp install-claude --print-only # prints the JSON to paste manually
|
|
166
189
|
```
|
|
167
190
|
|
|
191
|
+
Without `--config-path` the command only prints the block; it never guesses
|
|
192
|
+
where your Claude Desktop config lives.
|
|
193
|
+
|
|
194
|
+
If you installed from a clone rather than `uv tool install`, the `uxarray-mcp`
|
|
195
|
+
binary lives in the project `.venv`. In every client config below, use
|
|
196
|
+
`uv --directory /path/to/uxarray-mcp-server run uxarray-mcp serve` as the
|
|
197
|
+
command instead of a bare `uxarray-mcp serve`.
|
|
198
|
+
|
|
168
199
|
Restart Claude Desktop. The `uxarray` server should appear in Settings →
|
|
169
200
|
Developer.
|
|
170
201
|
|
|
@@ -176,10 +207,63 @@ claude mcp add uxarray --transport stdio -- uxarray-mcp serve
|
|
|
176
207
|
|
|
177
208
|
Then `/mcp` in Claude Code; pick `uxarray`.
|
|
178
209
|
|
|
179
|
-
**
|
|
210
|
+
**Codex CLI**
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
codex mcp add uxarray -- uxarray-mcp serve
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Or write `~/.codex/config.toml` directly:
|
|
217
|
+
|
|
218
|
+
```toml
|
|
219
|
+
[mcp_servers.uxarray]
|
|
220
|
+
command = "uxarray-mcp"
|
|
221
|
+
args = ["serve"]
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Then `/mcp` in a Codex session.
|
|
180
225
|
|
|
181
|
-
|
|
182
|
-
|
|
226
|
+
**opencode**
|
|
227
|
+
|
|
228
|
+
Add to `~/.config/opencode/opencode.json`:
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"mcp": {
|
|
233
|
+
"uxarray": {
|
|
234
|
+
"type": "local",
|
|
235
|
+
"command": ["uxarray-mcp", "serve"],
|
|
236
|
+
"enabled": true
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The server registers 33 tools, which is a large tool schema to carry on every
|
|
243
|
+
request. `"enabled": false` turns it off for sessions that are not doing mesh
|
|
244
|
+
analysis.
|
|
245
|
+
|
|
246
|
+
**Cursor**
|
|
247
|
+
|
|
248
|
+
Add to `~/.cursor/mcp.json` (or a project-local `.cursor/mcp.json`):
|
|
249
|
+
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"mcpServers": {
|
|
253
|
+
"uxarray": {
|
|
254
|
+
"command": "uxarray-mcp",
|
|
255
|
+
"args": ["serve"]
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Any other MCP client**
|
|
262
|
+
|
|
263
|
+
The server speaks stdio, so every client wants the same two facts — the
|
|
264
|
+
command `uxarray-mcp` and the argument `serve`. `uxarray-mcp install-claude
|
|
265
|
+
--print-only` prints the `mcpServers` JSON block that most clients accept
|
|
266
|
+
verbatim.
|
|
183
267
|
|
|
184
268
|
### Step 4 — Sanity check
|
|
185
269
|
|
|
@@ -236,16 +320,27 @@ Intent-shaped tools, not raw UXarray bindings — all local by default:
|
|
|
236
320
|
- `get_capabilities` — what can I do with this mesh?
|
|
237
321
|
- `analyze_dataset` — deterministic first-look: inspect, validate, area, zonal mean, plots.
|
|
238
322
|
- `run_analysis` — one operation at a time (gradient, curl, subset, remap, …).
|
|
239
|
-
|
|
323
|
+
Remaps take `method`: `nearest_neighbor`, `inverse_distance_weighted` or
|
|
324
|
+
`bilinear` on UXarray's own engine, or `conservative`, `nnn`, `dnn`,
|
|
325
|
+
`average` on [YAC](https://dkrz-sw.gitlab-pages.dkrz.de/yac/) (equivalently
|
|
326
|
+
`backend="yac"` with `yac_method`). Only `conservative` preserves the field
|
|
327
|
+
integral, and it needs YAC importable where the remap runs — build it with
|
|
328
|
+
`scripts/build_yac_local.sh` on a laptop or `scripts/hpc_build_yac.py` on a
|
|
329
|
+
worker, and put its `site-packages` on `PYTHONPATH`.
|
|
330
|
+
- `plot_dataset` — `plot_type` of `mesh`, `mesh_geo`, `variable`, or `zonal_mean`.
|
|
240
331
|
- `run_workflow`, `resume_workflow`, `get_status`, `get_result`, `manage_session` —
|
|
241
332
|
persisted sessions and multi-step workflows.
|
|
242
333
|
|
|
243
|
-
|
|
334
|
+
Helper namespaces also appear in `tools/list`: `session/*`, `hpc/*`,
|
|
335
|
+
`io/list_datasets`, `contract/*` and `prompt/*`.
|
|
336
|
+
|
|
337
|
+
Full schema and every `run_analysis` parameter: [docs/tools.md](docs/tools.md).
|
|
244
338
|
|
|
245
339
|
**Protocol version.** We do not implement MCP directly; servers are built
|
|
246
340
|
through `toolregistry-server`, which depends on the `mcp` Python SDK. As of
|
|
247
341
|
`toolregistry-server` 0.5.0 and `toolregistry` 0.16.0 the SDK cap is lifted, so
|
|
248
|
-
we resolve `mcp` 2.1.1 and negotiate spec
|
|
342
|
+
we resolve `mcp` 1.27 or 2.x (2.1.1 at the last lock) and negotiate spec
|
|
343
|
+
**`2026-07-28`** (stateless core,
|
|
249
344
|
cacheable list results, MRTR). 0.16.0 also widens the recognized content-block
|
|
250
345
|
set to audio, `resource_link`, and embedded resources.
|
|
251
346
|
|
|
@@ -268,10 +363,13 @@ auditable and the server actively flags common scientific pitfalls:
|
|
|
268
363
|
the tool that ran, timestamp, input arguments, `execution_venue`
|
|
269
364
|
(`local` or `hpc:<endpoint>`), and the UXarray/Python versions used.
|
|
270
365
|
- **Derivative unit convention is never hidden.** `gradient`, `curl`, and
|
|
271
|
-
`divergence` echo `scale_by_radius`
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
`
|
|
366
|
+
`divergence` echo `scale_by_radius` and a `radius_basis` block (the radius
|
|
367
|
+
used and whether it came from the grid or the caller), so a unit-sphere
|
|
368
|
+
result can never be mistaken for a physical (per-metre) one. Most grid files
|
|
369
|
+
declare no `sphere_radius`; pass `sphere_radius=6371000` (metres) to attach
|
|
370
|
+
Earth's. Without it, or with `scale_by_radius=False`, the call is refused
|
|
371
|
+
with `outcome="input_required"` until you pass `acknowledge`. The same
|
|
372
|
+
`sphere_radius` argument turns `calculate_area` from steradians into m².
|
|
275
373
|
- **Vector-calculus sanity guard.** `curl`/`divergence` warn (without blocking)
|
|
276
374
|
when the two inputs are the same field, or when neither carries a
|
|
277
375
|
velocity/flux-like `units` attribute — the classic "vorticity from two random
|
|
@@ -293,12 +391,14 @@ auditable and the server actively flags common scientific pitfalls:
|
|
|
293
391
|
|
|
294
392
|
| Command | Purpose |
|
|
295
393
|
|---|---|
|
|
296
|
-
| `uxarray-mcp serve` | Run the MCP server (used by your AI client) |
|
|
394
|
+
| `uxarray-mcp serve` | Run the MCP server (used by your AI client); `--profile core\|deferred-full`, `--transport stdio\|sse\|http` — see [docs/serving.md](docs/serving.md) |
|
|
395
|
+
| `uxarray-mcp openapi` | Print the OpenAPI document for the HTTP transport |
|
|
297
396
|
| `uxarray-mcp setup` | Write a starter config |
|
|
298
397
|
| `uxarray-mcp endpoints add NAME UUID` | Register a Globus Compute endpoint |
|
|
299
|
-
| `uxarray-mcp endpoints list` | Show configured endpoints |
|
|
398
|
+
| `uxarray-mcp endpoints list` / `remove NAME` | Show or drop configured endpoints |
|
|
399
|
+
| `uxarray-mcp transfer setup` | Check and fix everything a Globus Transfer needs, including the browser login an MCP server cannot open |
|
|
300
400
|
| `uxarray-mcp doctor` | Validate local + (optionally) remote setup |
|
|
301
|
-
| `uxarray-mcp install-claude` | Merge or print the Claude Desktop config block |
|
|
401
|
+
| `uxarray-mcp install-claude --config-path FILE` | Merge (or `--print-only`) the Claude Desktop config block |
|
|
302
402
|
|
|
303
403
|
---
|
|
304
404
|
|
|
@@ -339,7 +439,7 @@ see **[SECURITY.md](SECURITY.md)**.
|
|
|
339
439
|
## Development
|
|
340
440
|
|
|
341
441
|
```bash
|
|
342
|
-
uv sync --extra hpc --extra
|
|
442
|
+
uv sync --extra hpc --extra transfer --extra docs
|
|
343
443
|
uv run pre-commit run --all-files
|
|
344
444
|
uv run pytest tests/ --ignore=tests/test_remote_agent.py
|
|
345
445
|
uv run sphinx-build -b html docs docs/_build/html
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "uxarray-mcp"
|
|
3
|
-
version = "
|
|
3
|
+
version = "2026.9.0"
|
|
4
4
|
description = "MCP server for analyzing unstructured meshes with UXarray"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
keywords = [
|
|
@@ -25,11 +25,11 @@ requires-python = ">=3.11"
|
|
|
25
25
|
dependencies = [
|
|
26
26
|
"toolregistry-server[mcp]>=0.5.0",
|
|
27
27
|
"toolregistry>=0.16.0",
|
|
28
|
-
"mcp>=1.
|
|
28
|
+
"mcp>=1.27,<3",
|
|
29
29
|
"holoviews>=1.19.0",
|
|
30
30
|
"matplotlib>=3.9.0",
|
|
31
|
-
"pyyaml>=6.0",
|
|
32
|
-
"uxarray>=2026.
|
|
31
|
+
"pyyaml>=6.0.1",
|
|
32
|
+
"uxarray>=2026.9.0,<2026.10",
|
|
33
33
|
]
|
|
34
34
|
|
|
35
35
|
[[project.authors]]
|
|
@@ -49,6 +49,7 @@ hpc = [
|
|
|
49
49
|
"academy-py>=0.3.1",
|
|
50
50
|
"globus-compute-sdk>=4.5.0",
|
|
51
51
|
]
|
|
52
|
+
transfer = ["globus-cli>=3.30"]
|
|
52
53
|
docs = [
|
|
53
54
|
"sphinx>=7.0",
|
|
54
55
|
"sphinx-book-theme>=1.1.0",
|
|
@@ -65,7 +66,9 @@ Tracker = "https://github.com/UXARRAY/uxarray-mcp-server/issues"
|
|
|
65
66
|
|
|
66
67
|
[dependency-groups]
|
|
67
68
|
dev = [
|
|
69
|
+
"jsonschema>=4.20.0",
|
|
68
70
|
"mypy>=1.10.0",
|
|
71
|
+
"packaging>=23.0",
|
|
69
72
|
"pre-commit>=4.3.0",
|
|
70
73
|
"pytest>=9.0.2",
|
|
71
74
|
"pytest-asyncio>=1.0.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "uxarray-mcp"
|
|
3
|
-
version = "
|
|
3
|
+
version = "2026.9.0"
|
|
4
4
|
description = "MCP server for analyzing unstructured meshes with UXarray"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
keywords = ["uxarray", "mcp", "unstructured grids", "scientific computing", "globus compute"]
|
|
@@ -45,11 +45,22 @@ dependencies = [
|
|
|
45
45
|
# is_content_block_list about audio/resource_link/resource; on 0.15.0 those
|
|
46
46
|
# blocks are silently stringified into one TextContent instead of failing.
|
|
47
47
|
"toolregistry>=0.16.0",
|
|
48
|
-
|
|
48
|
+
# Both SDK generations are in range and register handlers differently:
|
|
49
|
+
# 1.27.2 has the per-method decorators and no `add_request_handler`, 2.1.1
|
|
50
|
+
# has `add_request_handler` and no decorators. `resources.py` registers
|
|
51
|
+
# through whichever is present, and `tests/test_artifact_resources.py`
|
|
52
|
+
# passes on both.
|
|
53
|
+
"mcp>=1.27,<3",
|
|
49
54
|
"holoviews>=1.19.0",
|
|
50
55
|
"matplotlib>=3.9.0",
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
# 6.0.1, not 6.0: PyYAML 6.0 ships no wheel for CPython 3.12 and its sdist
|
|
57
|
+
# cannot build against a modern Cython, failing with `'build_ext' object has
|
|
58
|
+
# no attribute 'cython_sources'`. Nothing hit it in normal CI because that
|
|
59
|
+
# resolves to the newest PyYAML; the weekly `lowest-direct` job installs the
|
|
60
|
+
# floor we actually declare, and had failed on it every run since
|
|
61
|
+
# 2026-08-10.
|
|
62
|
+
"pyyaml>=6.0.1",
|
|
63
|
+
"uxarray>=2026.9.0,<2026.10",
|
|
53
64
|
]
|
|
54
65
|
|
|
55
66
|
[project.optional-dependencies]
|
|
@@ -60,6 +71,14 @@ hpc = [
|
|
|
60
71
|
"academy-py>=0.3.1",
|
|
61
72
|
"globus-compute-sdk>=4.5.0",
|
|
62
73
|
]
|
|
74
|
+
# Moving files is separate from running code on them, and is done by running
|
|
75
|
+
# the `globus` command-line client rather than by linking a second SDK. The CLI
|
|
76
|
+
# owns the tokens, the consents and the session, so this package holds no auth
|
|
77
|
+
# code at all -- which is the only reason a two-person project can offer data
|
|
78
|
+
# movement without also signing up to track Globus's scope rules.
|
|
79
|
+
transfer = [
|
|
80
|
+
"globus-cli>=3.30",
|
|
81
|
+
]
|
|
63
82
|
docs = [
|
|
64
83
|
"sphinx>=7.0",
|
|
65
84
|
"sphinx-book-theme>=1.1.0",
|
|
@@ -76,7 +95,16 @@ Tracker = "https://github.com/UXARRAY/uxarray-mcp-server/issues"
|
|
|
76
95
|
|
|
77
96
|
[dependency-groups]
|
|
78
97
|
dev = [
|
|
98
|
+
# Declared so the outputSchema conformance tests cannot silently skip.
|
|
99
|
+
# jsonschema arrives transitively today, which means a resolver change
|
|
100
|
+
# would turn the checks that hold every result to its published envelope
|
|
101
|
+
# into a green no-op.
|
|
102
|
+
"jsonschema>=4.20.0",
|
|
79
103
|
"mypy>=1.10.0",
|
|
104
|
+
# Same reason as jsonschema: the suite-integrity check reads the declared
|
|
105
|
+
# uxarray floor out of the packaging metadata so it cannot drift from this
|
|
106
|
+
# file, and it needs a specifier parser to do that.
|
|
107
|
+
"packaging>=23.0",
|
|
80
108
|
"pre-commit>=4.3.0",
|
|
81
109
|
"pytest>=9.0.2",
|
|
82
110
|
"pytest-asyncio>=1.0.0",
|
|
@@ -23,6 +23,7 @@ from toolregistry_server.app import App
|
|
|
23
23
|
|
|
24
24
|
from . import __version__
|
|
25
25
|
from .registry import Profile
|
|
26
|
+
from .resources import attach_artifact_resources
|
|
26
27
|
|
|
27
28
|
if TYPE_CHECKING:
|
|
28
29
|
from toolregistry import ToolRegistry
|
|
@@ -101,12 +102,16 @@ class UXarrayApp(App):
|
|
|
101
102
|
name = kwargs.pop("name", identity.name)
|
|
102
103
|
kwargs.pop("profile", None)
|
|
103
104
|
|
|
104
|
-
MCPAdapter(
|
|
105
|
+
adapter = MCPAdapter(
|
|
105
106
|
route_table,
|
|
106
107
|
name=name,
|
|
107
108
|
list_tools_ttl_ms=LIST_TOOLS_TTL_MS,
|
|
108
109
|
list_tools_cache_scope=LIST_TOOLS_CACHE_SCOPE,
|
|
109
|
-
)
|
|
110
|
+
)
|
|
111
|
+
# Large figures go back as ``resource_link``, which is only honest if
|
|
112
|
+
# something answers ``resources/read`` for the URI (#14).
|
|
113
|
+
attach_artifact_resources(adapter.server)
|
|
114
|
+
adapter.run(**kwargs)
|
|
110
115
|
|
|
111
116
|
|
|
112
117
|
# ---------------------------------------------------------------------------
|
|
@@ -122,16 +127,19 @@ def make_registry(*, profile: Profile = "core") -> ToolRegistry:
|
|
|
122
127
|
def make_mcp_server(*, profile: Profile = "core"):
|
|
123
128
|
"""Build a configured MCP server ready for any transport.
|
|
124
129
|
|
|
125
|
-
Carries the same ``tools/list`` cache hints
|
|
126
|
-
so tests and scripts
|
|
130
|
+
Carries the same ``tools/list`` cache hints and the same artifact
|
|
131
|
+
resource handlers as :meth:`UXarrayApp.serve_mcp`, so tests and scripts
|
|
132
|
+
exercise the surface the CLI actually serves.
|
|
127
133
|
"""
|
|
128
134
|
from toolregistry_server.adapters.mcp import route_table_to_mcp_server
|
|
129
135
|
from toolregistry_server.route_table import RouteTable
|
|
130
136
|
|
|
131
137
|
registry = make_registry(profile=profile)
|
|
132
|
-
return
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
return attach_artifact_resources(
|
|
139
|
+
route_table_to_mcp_server(
|
|
140
|
+
RouteTable(registry),
|
|
141
|
+
"UXarray MCP",
|
|
142
|
+
list_tools_ttl_ms=LIST_TOOLS_TTL_MS,
|
|
143
|
+
list_tools_cache_scope=LIST_TOOLS_CACHE_SCOPE,
|
|
144
|
+
)
|
|
137
145
|
)
|