Skip to main content
Glama
1622352030

ansys-agent-bridge

by 1622352030

ansys-agent-bridge

An MCP server that drives Ansys SpaceClaim headlessly, plus a DSH plugin bundle that installs it into a DeepSeek Harness profile in one command.

The point of this project is not to wrap every API. It is to report what SpaceClaim actually did, in a place where the honest answer matters: two operations on SpaceClaim 2024 R2 return success and change nothing, and an agent that believes the return value will confidently describe geometry that was never modified. This server measures the geometry before and after, and raises no_geometry_change instead of reporting a success it cannot see.

What it does

Fifteen MCP tools:

Tool

Read-only

What it does

ansys_bridge_doctor

yes

Reports detected Ansys releases, SpaceClaim.exe, Fluent root, Python, and package versions. Imports nothing heavyweight.

scdm_session_start

no

Starts a hidden SpaceClaim modeler (auto-detects the release; measured 30.6 s).

scdm_session_status

yes

Whether a session is live, and its backend type/version.

scdm_session_close

no

Releases the session and its licence.

scdm_open_file

no

Opens .scdoc/.scdocx/.dsco/.pmdb and reports bodies, named selections, face counts, volumes.

scdm_list_bodies

yes

Body names, face counts, volumes for the open design.

scdm_collisions

yes

Pairwise collision state (TOUCH/NONE/…), all pairs or a chosen list.

scdm_min_distance

yes

Minimum distance between two bodies in metres — the continuous counterpart to collisions.

scdm_insert_file

no

Merge another CAD file into the open design (open_file opens a document; this adds to one).

scdm_transform

no

rotate / scale / mirror, verified by a before/after spatial fingerprint.

scdm_inspect_geometry

yes

The eight official geometry checks: duplicate faces, short edges, small or missing faces, split and stitch faces, extra and inexact edges.

scdm_boolean

no

unite/subtract/intersect, guarded by a before/after geometry check.

scdm_share_topology

no

Share topology, guarded by the same check.

scdm_run_script

no

Runs a headless IronPython script against the live session.

scdm_export

no

Exports .scdocx, STEP, IGES, Parasolid text/binary, .pmdb.

The two silent failures, measured

On a stator + 27 windings + pipe + inlet assembly (31 bodies, 846 faces):

subtract fails, and the failure is easy to miss. Target stator: 382 faces and volume 0.003314505208 m³ before; 382 faces and the same volume after. The only thing that moved is the body count, 31 → 30, because keep_other=False deleted the tool.

That matters for how you guard it. The obvious check — "did anything change?" — answers yes here, so a guard built on it certifies the no-op. This server therefore judges a boolean by its target: if the named target keeps the same face count and volume, the call failed, whatever the body count says. The same symptom appears through raw IronPython Shape.Subtract, so it is a kernel/geometry problem with that model, not an API-path problem.

share_topology returns True and does nothing. Stator stays at 382 faces, winding 1 at 16, bodies at 31.

unite does work. Stator faces 382 → 390, volume 0.003314505208 → 0.003382973513 (delta 6.84683e-5, exactly winding 1's own volume), total faces 846 → 838, bodies 31 → 30. Both number sets match the raw IronPython result.

Full measured record, including the raw-IronPython traps (Body[](n) is a parse-time error that kills a script silently; Document.Load breaks every later SaveAs), is in spaceclaim/skills/ansys-spaceclaim/SKILL.md.

Related MCP server: Codex MCP Abaqus

Install

Requires Windows, an Ansys installation with SpaceClaim (2024 R2 tested), and uv.

DSH (one command)

dsh plugin --profile web add ansys-agent-bridge

That installs the package, which declares dsh.bundle, so the loader applies its cordis.patch.yml: one MCP client layer registering the ansys server. Restart the profile and call ansys_bridge_doctor.

Turning it off again is the same in reverse:

dsh plugin --profile web remove ansys-agent-bridge

The MCP row launches the server with uv tool run --from <this repo>, so no clone and no virtualenv is needed on the target machine — but the first call pays for resolving and building ansys-geometry-core. If you keep a local checkout and want a warm environment instead, point a --patch overlay at the same server name with args: [run, --directory, <clone>/python, ansys-bridge-mcp].

The patch contains no !!js and no absolute path, which is deliberate: the harness CLI (0.1.1-rc.1) evaluates !!js in a scope without createRequire and does not await the result, so an expression using either boots on the Desktop app (0.1.5-rc.2) and leaves the CLI with a profile that will not start. Both were tried and both broke it; command: uv needs neither. Override that one line if uv is not on the PATH the harness was launched with:

# a --patch overlay, applied after the bundle layer
- id: mcp-ansys
  name: '@deepseek-ai/dsh-mcp-client'
  config:
    serverName: ansys
    transport: stdio
    command: C:/Users/you/.local/bin/uv.exe
    args: [tool, run, --quiet, --from, <repo>, ansys-bridge-mcp]
    toolCallTimeoutMs: 900000

The bundled skill

The same !!js restriction is why spaceclaim/skills/ansys-spaceclaim/ is not wired up by the patch. Registering it needs a path resolved at load time, which needs one of the two constructs above. Add it explicitly instead, in your profile's own cordis.patch.yml (next to the bundle's) — this runs inside the host, where dshHomePath is always available and no module resolution is involved:

mkdir -p "$DSH_HOME/skills"                      # or %APPDATA%\dsh-desktop\harness\skills
cp -r <repo>/spaceclaim/skills/ansys-spaceclaim "$DSH_HOME/skills/"

$DSH_HOME/skills is one of the host's default skill roots, so nothing else is needed. Without it the MCP tools still work; what you lose is the measured operating notes and the trap list.

Any other MCP client

The server is a plain stdio MCP server, so it is not tied to DSH. Generate the block for your client:

uvx --from "git+https://github.com/1622352030/ansys-agent-bridge#subdirectory=spaceclaim/python" \
    ansys-bridge-doctor --config claude    # also: cursor, vscode, dsh

claude and cursor emit an mcpServers block, vscode emits a servers block with an explicit "type": "stdio", and dsh emits the insert patch entry for a profile's cordis.patch.yml. Paste the result into the client's configuration.

For a client whose schema you would rather write by hand, the command is:

{
  "mcpServers": {
    "ansys": {
      "command": "uv",
      "args": [
        "tool", "run", "--quiet",
        "--from", "git+https://github.com/1622352030/ansys-agent-bridge#subdirectory=spaceclaim/python",
        "ansys-bridge-mcp"
      ]
    }
  }
}

Use uv tool run, not uv run: measured against uv 0.11.29, uv run rejects --from with unexpected argument '--from' found, and the MCP client shows only Connection closed.

Check the environment first

uvx --from "git+https://github.com/1622352030/ansys-agent-bridge#subdirectory=spaceclaim/python" \
    ansys-bridge-doctor
ansys-agent-bridge 0.1.0
  python        3.13.4  C:\...\python.exe
  platform      Windows-11-10.0.26100-SP0

ANSYS releases detected (AWP_ROOT* and standard install roots):
  242          C:\Program Files\ANSYS Inc\v242
                 SpaceClaim.exe: C:\Program Files\ANSYS Inc\v242\scdm\SpaceClaim.exe

  Fluent root   C:\Program Files\ANSYS Inc\v242\fluent

Python packages:
  ansys.geometry.core      0.17.2
  ansys.fluent.core        0.42.1
  mcp                      1.28.1

Ready:
  server       yes
  spaceclaim   yes
  fluent       yes

Add --json for the machine-readable report.

Environment variables

Variable

Default

Effect

ANSYS_BRIDGE_UV

Not read by the patch (which has no !!js). Override the command: line with a --patch overlay if uv is not on PATH.

ANSYS_BRIDGE_PRELOAD

1

Import the Ansys clients at start-up. Set 0 for a fast start; the first SpaceClaim call then pays that import.

ANSYS_BRIDGE_TRANSPORT

stdio

stdio, sse, or streamable-http.

ANSYS_BRIDGE_LOG_LEVEL

WARNING

FastMCP request logging. INFO logs one line per request.

Why start-up preloads, and why tools are serialised

FastMCP runs a synchronous tool on the event loop thread (mcp/server/fastmcp/utilities/func_metadata.py: return fn(**args) — there is no to_thread). Lazy-importing ansys.geometry.core from inside a tool call was measured wedging the whole process inside numpy's C extension create_module, with no exception and no timeout — the client sees a tool call that simply never returns:

_call_with_frames_removed (<frozen importlib._bootstrap>:488)
create_module (<frozen importlib._bootstrap_external>:1321)
<module> (numpy\_core\multiarray.py:11)
...
start (ansys_bridge_mcp\scdm.py)
scdm_session_start (ansys_bridge_mcp\server.py)
_handle_message (mcp\server\lowlevel\server.py)

The identical import finishes in 0.9 s at process start, so main() imports numpy and both Ansys clients before accepting a request. Stacks were captured with py-spy dump.

The same fact means long tools block the server: a 30-second SpaceClaim start holds the event loop, so a concurrent call queues behind it. That is acceptable here — SpaceClaim mutates one design, and serialising is what you want — but it is why toolCallTimeoutMs in the DSH patch is 900 s rather than the 60 s default.

Safety

  • Never open a file a SpaceClaim GUI has open, and never write to a source model. Open, operate, export to a new path.

  • A session holds a licence; call scdm_session_close.

  • Package inspection is metadata-only. An earlier version imported ansys.fluent.core inside a tool call to read its version; that library prints during import, which corrupted the stdio JSON-RPC stream and killed the session mid-call. package_version() now reads metadata without importing.

Layout

The repository is split by product domain, strictly. SpaceClaim material and Fluent material never share a directory, down to the test scripts:

package.json            DSH bundle manifest (`dsh.bundle.patch`) + npm entry
cordis.patch.yml        the bundle's patch layer
screenshots.json
tools/verify-patch.mjs             offline check of cordis.patch.yml

spaceclaim/
  python/               the MCP server (uv/pip-installable, src layout)
  skills/ansys-spaceclaim/SKILL.md measured operating notes and traps
  docs/feature-coverage.md         implementation vs. the official API
  docs/verification.md             what was verified, and the bugs found
  dev/tests|logs|evidence|models|scratch

fluent/
  docs/mcp-audit.md                audit of the official ansys-fluent-mcp
  dev/tests|logs|evidence|scratch
  (no code yet -- the Fluent side currently uses the official package)

dev/ holds development-time material and stays inside the repository on purpose, so nothing is ever written into a user's model directory. Transcripts, export dumps and the copied test models are gitignored; the test scripts and the API inventories are kept.

The root keeps only what must be at the root: npm reads package.json there, and dsh.bundle.patch resolves ./cordis.patch.yml relative to it.

What is and is not implemented

spaceclaim/docs/feature-coverage.md is the item-by-item comparison against the official API: every capability domain, whether it is implemented, and — for the gaps — why. It is not a list of what the server does; it is the list a reader needs to find what it does not do.

The headline is that the official client declares far more than this release can run. Of 286 public methods carrying a @min_backend_version gate, only 15 are callable on 24R2; the other 271 need 25.1 through 27.1. That includes all 44 GeometryCommands modelling methods. The comparison therefore filters by version first, which is what separates a real gap from a method that would only raise GeometryRuntimeError.

Two consequences worth knowing before you plan work:

  • Geometric inspection is now the headline feature. Eight RepairTools.find_* methods carry no version gate at all, so they work on 24R2, and all eight are behind scdm_inspect_geometry. On the assembly whose meshing failed, that tool names the cause: two pairs of coincident faces, one on stator and one on pip in each pair, with identical areas. Replacing "the mesh failed" with "these two faces are stacked" is the whole point.

  • An external flow enclosure cannot be built through this API. The three create_*_enclosure methods need 26.1.0. For external-flow CFD, build the domain in the SpaceClaim UI or use Fluent Meshing's enclosure instead.

Development

node tools/verify-patch.mjs        # no profile needed
uv run --directory python pytest -q

verify-patch.mjs evaluates any !!js expression in the patch inside a bare with (ctx) { eval(expr) } scope — exactly what the CLI builds — and refuses a promise result, so a patch that would only boot on the newer harness fails here instead of on a user's machine. It also checks that the console script the patch launches is the one pyproject.toml declares.

Licence

MIT. See LICENSE.

Related MCP Connectors

Related MCP Servers