Releases: UXARRAY/uxarray-mcp-server
Release list
uxarray-mcp 2026.9.0
🌎 uxarray-mcp 2026.9.0
An MCP server for UXarray. Point an AI
assistant at an unstructured climate mesh and it can subset it, compute on it,
plot it, and hand back an answer that carries its own checks.
Built against uxarray 2026.9. Python 3.11+.
🧭 What you can ask it to do
Describe a mesh. Topology, variables, what is face-centered and what is
not, whether the grid declares a radius, how much of the sphere it covers.
Compute on it. Area, zonal means and anomalies, gradient, curl,
divergence, azimuthal profiles, cross sections, temporal means, ensemble mean
and spread, bias, RMSE, pattern correlation.
Cut it down. Bounding box, polygon, and cross-section subsetting, each
reporting how many faces it started with and how many it kept.
Move between grids. Mesh-to-mesh and mesh-to-rectilinear remapping, with
nearest-neighbor, inverse-distance-weighted and bilinear on the UXarray
engine, and conservative, nnn, dnn and average through YAC.
Conservative is the one that preserves the field integral, and you ask for it
by that name.
Draw it. Wireframe mesh, geographic mesh over coastlines and borders,
choropleth of a variable, temporal mean, zonal profile.
Find your data. Walk a directory, classify what is a grid and what is
data, and say which operations each file supports.
Most of this goes through a single front door, run_analysis, which
dispatches by intent. 33 tools in the core surface.
🛡️ Answers that check themselves
A tool that returns a confident wrong number costs more than one that returns
nothing, because nothing downstream can tell the difference.
So every operation carries preconditions and postconditions. A call
that cannot be answered correctly comes back as a structured refusal that
names the repair, rather than a plausible-looking float.
- 📐 Ask for area on a grid that declares no radius and you are told to pass
sphere_radius, not handed steradians labeled as square metres. - 🗺️ Every area result reports what fraction of the sphere it summed over, so
a regional mesh and a global one do not read the same. - 🧮 Subsets, cross sections and zonal bands return coverage blocks with source
and selected face counts, and refuse a selection that is empty or entirely
non-finite. - 🔬 Remap coverage names the method it judged, so a non-conservative warning
tells you which non-conservative method ran. - 🚫
NaNandInfinitynever reach the wire. They are not JSON.
Refusals are multi-round-trip shaped, so a model can read the repair and try
again without a human in the loop.
🔌 Works with your client, and with other agents
Speaks the 2026-07-28 MCP specification, and negotiates the 2025-11-25
era cleanly for clients that ask for it. Result caching hints (ttlMs,
cacheScope) are sent when the negotiated era supports them and omitted when
it does not.
Figures and other large outputs are MCP resources. A plot too big to
inline comes back as a fetchable file:// link, reads are confined to the
artifact directory, and resources/list pages at 100.
🐍 It is not only an MCP server. One tool registry projects to three
surfaces, so the same checked operations are reachable from whatever you are
building:
uxarray-mcp serve # MCP, for Claude / any MCP client
uxarray-mcp openapi # REST + OpenAPI schema, for HTTP agents# or import the functions directly, no protocol involved
from uxarray_mcp.tools.frontdoor import run_analysis
result = run_analysis(
operation="calculate_area",
grid_path="mesh.nc",
sphere_radius=6371000.0,
)The preconditions, the coverage blocks and the refusals are in the functions,
not in the transport, so a Python agent framework gets the same guarantees as
an MCP client. Multi-agent setups can put the REST surface behind one agent
and the Python calls inside another.
🖥️ Runs where the data already is
Point it at an HPC endpoint and the work goes to the cluster over Globus
Compute. The mesh never moves. Only the result comes back.
File movement is its own tool set when you want it: transfer_ls,
transfer_put, transfer_get, transfer_status, backed by Globus Transfer.
They appear only when an endpoint declares a globus_transfer block, so an
install that moves no files never shows them to the model.
uxarray-mcp transfer setup # walks through auth and collections
uxarray-mcp doctor # says what is actually brokendoctor checks local auth, endpoint liveness, worker bootstrap, and whether
your write root is readable as well as writable.
⚡ Cheap to keep in context
The tool catalog is re-sent on every turn, so its size is paid for repeatedly.
The served catalog is 8,974 tokens for all 33 tools, and results are
budgeted per operation with tests that fail when one grows.
📖 See it on real data
CONUS precipitation case study →
Ten years of ne120np4 CONUS precipitation on NCAR Casper. 37 GB of source
data, a 777,602-face spectral element mesh, subset to 23,510 faces. One prompt
from a laptop, about eight minutes, and back comes a 178 KB PNG with the PBS
job ID attached. Nothing staged off the cluster.
Documented end to end, Casper setup included, so you can reproduce it.
📦 Install
pip install uxarray-mcp # core
pip install "uxarray-mcp[hpc]" # + Globus Compute
pip install "uxarray-mcp[hpc,transfer]" # + Globus Transfer
pip install "uxarray-mcp[openapi]" # + REST surfaceRegister it with your MCP client and open with:
"What can you tell me about this mesh?"
get_capabilities answers with the operations that particular grid supports,
so the model does not spend a call finding out the hard way.
README ·
HPC endpoints ·
CHANGELOG
🔢 On version numbers
Releases are CalVer, <year>.<month>.<patch>, tracking the uxarray release
they are built against. Running uxarray 2026.9 means you want uxarray-mcp
2026.9.x.
⚠️ PEP 440 orders2026.9.0above0.3.1, so a looseuxarray-mcp>=0.3
will move you onto the CalVer line. Pin~=2026.9.0to stay put.
🤝 Come break it
The most useful thing you can do is find where it gives you a bad answer.
- 🐛 Open an issue,
especially for a tool that returned something confidently wrong. That
outranks a crash here. - 🔧 PRs welcome. New operations, sharper preconditions, better refusal
messages, more client and agent integrations. - 🤖 Using it from an agent framework we have not tried? Tell us what the
interface got in your way. - 💬 Tell us the analysis you wanted to run and could not.
v0.3.1
Automated release 0.3.1.
Changes since v0.3.0: 10 commit(s).
v0.3.0
Automated release 0.3.0.
Changes since v0.2.2: 27 commit(s).
v0.2.2
Automated release 0.2.2.
Changes since v0.2.1: 4 commit(s).
v0.2.1
Automated release 0.2.1.
Changes since v0.2.0: 3 commit(s).
v0.2.0
Automated release 0.2.0.
Changes since v0.1.3: 5 commit(s).
v0.1.3
Automated release 0.1.3.
Changes since v0.1.2: 21 commit(s).
v0.1.2
Automated release 0.1.2.
Changes since v0.1.1: 18 commit(s).
v0.1.1
Automated release 0.1.1.
Changes since v0.1.0: 9 commit(s).
v0.1.0
Automated release 0.1.0.
Initial release.