The interface is localized. Skill descriptions and documents are machine-translated by AI into your language; code, commands, paths and technical terms stay in the original, and the author's document governs.
Explore skills
Development · SKILL.md

ansys-fluent-mcp

ansys-fluent-mcp

Drive an ANSYS Fluent solver session through the standalone `ansys-fluent-mcp` MCP server. USE WHEN the user asks to load a case/mesh, inspect physics, change settings, run iterations, or query results — and the chat client is connected directly to the MCP (VS Code Copilot, Cursor, Claude Desktop). EXPOSES a 22-tool surface: `session_status`, `connect`, `di…

Independent GitHub snapshot · Automated classification · Original documentation governs

Ccai-aa / cae-agent-hubApache-2.0

Skill documentation

GitHub

name: ansys-fluent-mcp description: | Drive an ANSYS Fluent solver session through the standalone ansys-fluent-mcp MCP server. USE WHEN the user asks to load a case/mesh, inspect physics, change settings, run iterations, or query results — and the chat client is connected directly to the MCP (VS Code Copilot, Cursor, Claude Desktop). EXPOSES a 22-tool surface: session_status, connect, disconnect, find_api, get_help, get_state, get_targeted_context, list_named_objects, find_named_object, select_named_objects, summarize_setup, simulation_report, solver_status, run_code, validate_code, screenshot, mesh_quality, list_fields, compare_files. This is a STATELESS leaf: there is no plan/journal/rollback and no propose_step / finalize planning machinery — run_code mutates the live solver immediately. DO NOT USE FOR generic Python / CFD-theory questions unrelated to Fluent.

ANSYS Fluent MCP (standalone) — Authoring Playbook

This skill targets the tool surface that ansys-fluent-mcp ships. The server gives you composable primitives — discovery, state read, schema discovery, validation, sandboxed execution — and you build everything else by chaining them. It is stateless: each call stands alone, there is no plan builder, journal, or undo.

Tool roster (this is what you actually have)

ToolOne-line purpose
session_statusAre we connected? Which backend?
connect(ip?, port?, ...)Launch a local Fluent session or attach to a running one.
disconnectTear down the session.
solver_statusIs the solver busy iterating?
find_api(query, limit?, kind?)Lexical (or, if configured, semantic) search over the Fluent settings tree. Returns ranked paths + signatures.
get_help(path)Per-node help text.
get_state(path, projection?)Read any settings path. path is a STRING.
get_targeted_context(...)Trimmed live-context snapshot for a specific intent.
list_named_objects(path)Enumerate the keys of a NamedObject collection.
find_named_object(path, name, fuzzy?)Exact or fuzzy name lookup.
select_named_objects(path, where=[...])Filter a NamedObject collection by predicates.
summarize_setup(scope?)Compact digest of models / BCs / materials / numerics / reference values.
simulation_reportStructured solution report on the loaded case.
run_code(code)Execute a sandboxed PyFluent Python snippet. This is your mutator.
validate_code(code)AST + signature check (no execution). Always run before run_code for untrusted code.
screenshot(filename?, width?, height?)Capture the active graphics window.
mesh_quality(include_check?)Live skewness / orthogonal-quality / aspect-ratio histograms (+ optional mesh.check()). Route every "show mesh quality" / "skewness" / "orthogonal quality" / "aspect ratio" / "check mesh" intent here.
list_fields(scope?)Enumerate scalar/vector fields available in the loaded case (pressure, velocity-magnitude, …).
compare_files(path_a, path_b)Diff two case/mesh files in two ephemeral PyFluent sessions; returns a markdown summary table per family. Live workspace session is not touched.

That is the complete surface. There is no propose_step, finalize, summarize_session, inspect_api, describe_command, get_allowed_values, query_reports, validate_setup, diagnose_divergence, or engineering-correlation helper (compute_htc, lookup_emissivity, …) on this server. Don't call them — they don't exist here.

The composition pattern

For nearly every intent, the loop is:

1. Discover    → find_api / get_help / list_named_objects / summarize_setup
2. Author      → your host or user supplies PyFluent settings-API Python
3. Validate    → validate_code (offline AST check)
4. Execute     → run_code (mutates the live solver)
5. Verify      → get_state / summarize_setup / simulation_report

Intent-to-code translation is not part of this leaf. If a host wants to translate user intent into Python, it should do so outside this server, then pass the resulting Python through validate_code before calling run_code.

Path roots (universal Fluent knowledge)

PyFluent has exactly five top-level path roots:

setup. | solution. | results. | file. | mesh.

setup.solution.* does not exist.

Recipes for common intents

"Show mesh quality / skewness / orthogonal quality / aspect ratio / check mesh"

Use the mesh_quality tool — it returns structured skewness / orthogonal-quality / aspect-ratio histograms and, when include_check=true, also embeds the output of Fluent's mesh.check():

mesh_quality(include_check=true)

Do NOT route these intents through run_code, simulation_report, or summarize_setup — the dedicated tool already wraps the raw PyFluent calls and normalises their output across versions.

"What fields are available?" / "list scalar fields"

list_fields(scope="any")     # any | cell | node | face

Returns the flat list usable in report defs, contours, vectors.

"Compare two case files"

compare_files(path_a="/abs/path/A.cas.h5", path_b="/abs/path/B.cas.h5")

Both files open in separate ephemeral PyFluent sessions with lightweight_setup=true — your live workspace session is NOT touched. Returns a markdown summary table in the summary field; echo that string verbatim to the user.

"Compute h for natural convection?" / "Porous resistance?" / "Emissivity / roughness of X?"

These engineering correlations and material lookups are not on this server. Ground the value yourself (textbook / handbook) and use it in host-authored Python rather than calling a non-existent tool.

"Show me the current setup"

summarize_setup(scope='models') or summarize_setup(scope='bcs') — don't dump the whole tree. Scoped output keeps client context small and the response on-topic.

"Enable energy" / "set BC outlet to pressure-outlet" / "switch turbulence to k-ω SST"

Author PyFluent settings-API Python, validate it with validate_code, then execute it with run_code.

Always show the generated code to the user before run_code — it mutates the solver immediately and there is no undo on this server.

"What's the path for ?"

find_api(query="velocity inlet thermal temperature", kind="path")

Pick the most-specific match and then:

get_help(path="setup.boundary_conditions.velocity_inlet.<zone>.thermal.t")

"List my zones / BCs / materials"

list_named_objects(path="setup.boundary_conditions.velocity_inlet")
list_named_objects(path="setup.cell_zone_conditions.fluid")
list_named_objects(path="setup.materials.fluid")

For predicate filtering, use select_named_objects with where=[...].

"Read a value"

get_state(path="setup.models.viscous.k_omega_model") — pass a string, not a list. The result is the live value.

"Iterate N steps"

run_code(code="solver.solution.run_calculation.iterate(iter_count=200)")

There's no streaming progress on this surface — you'll get the final residual snapshot. Use solver_status to confirm completion.

"Load a case / mesh"

run_code(code="solver.file.read_case(file_name=r'<path>')")
run_code(code="solver.file.read_data(file_name=r'<path>')")

Golden rules

  • NEVER emit .tui.* calls from run_code. Always solver.settings.* / solver.<root>.<path>... (the settings API is what's available in 27.1).
  • .list() / .list_properties() are void — they print only. Use list_named_objects instead for programmatic discovery.
  • run_code mutates the live solver. There is no journal / rollback on this surface. Show the user the code before you run it.
  • Named expressions REQUIRE units when dimensional: '288.15 [K]', '1.225 [kg/m^3]', '1 [m/s]'. Bare numbers silently break downstream report defs and BC values.
  • get_state(path=...) takes a string, not a list. Same for find_api(query=...).

Anti-patterns (do not do)

  • .tui.* calls of any kind, including via run_code.
  • Calling planning/governance tools (propose_step, finalize, summarize_session, inspect_api, validate_setup) — they are NOT part of this server.
  • Routing "mesh quality" / "skewness" / "orthogonal quality" / "aspect ratio" / "check mesh" through simulation_report, summarize_setup, or hand-written run_code — call the dedicated mesh_quality tool instead (it returns the structured histograms directly and optionally wraps Fluent's mesh.check()).
  • Calling run_code with intent strings (it expects Python, not executable code). Translate intent outside this leaf, validate the resulting Python, then execute it with run_code.
  • Skipping validate_code on host-authored Python for safety-critical operations (model toggles, BC writes, file.write_*).

Planning, retries, and recovery — host responsibility

This server is stateless. It deliberately ships no planner, no journal, no recipe registry, and no rollback. Multi-step plan construction, undo, retry policies, and "propose → confirm → apply" flows are the host's responsibility (VS Code Copilot, Cursor, Claude Desktop, or any custom agent that connects over MCP).

If the host has its own planner / agent loop, let it drive the discover → generate → validate → execute → verify cycle. This server will:

  • accept and run each step,
  • return rich error envelopes the host's planner can branch on,
  • never retry, queue, or sequence steps internally.

Intent-guard error codes (defense-in-depth at run_code)

run_code runs an offline, stateless intent guard before exec to catch a fixed set of Fluent-specific crash signatures. It is NOT a planner — it inspects only the snippet you submitted. Disable with FLUIDS_MCP_INTENT_GUARD=0 if your host wants full control.

When the guard fires, run_code returns one of these error codes:

error_codeMeaningCorrect response
risk_blockedSnippet matches a known crash signature (e.g. boundary rename to a name with whitespace; multiphase.number_of_phases = N int direct-assign; setup mutation while iterating).Read the suggestion in stderr, rewrite the snippet, then call run_code again. Do NOT retry the same snippet.
sequence_errorIntra-snippet use-before-create (e.g. gravity references expr_grav before the snippet creates setup.named_expressions["expr_grav"]).Reorder the statements (define first, then reference) and re-submit.
solver_disconnectedThe Fluent gRPC channel died during the call (or just before it).Call connect again, re-load the case/data file, then re-issue the work. The session is already marked disconnected — session_status will reflect that on the very next call.

The blocking signatures (return risk_blocked / sequence_error) are:

  1. bc.rename.whitespace — boundary rename whose new name contains whitespace. Use underscores instead ("oil_inlet", not "oil inlet").
  2. multiphase.number_of_phases.shape — direct integer assignment to multiphase.number_of_phases. Use multiphase.number_of_phases.number_of_eulerian_phases = N.
  3. seq.phase.material_before_rename — phase rename happens AFTER the material assignment in the same snippet. Rename first, then assign material to the new key.
  4. runtime.write_during_iter — setup.* mutation while the solver is iterating. Interrupt first (solver.solution.run_calculation.interrupt()), then write.
  5. seq.named_expr.use_before_create — a named expression is referenced before it is created in the same snippet. Reorder, or split into two run_code calls.
  6. reportdef.surface_field — a report definition is given a surfaces field (attribute, .locations.surfaces, or a create-dict key). Report definitions take surface_names=[...] (surfaces is the graphics-object field).

In addition, non-blocking advisories are returned in the successful result's warnings list (they do NOT stop execution):

  • named_expr.missing_units — a named expression is created with a bare number ({"definition": "9.81"}). Add a unit, e.g. "9.81 [m s^-2]"; a unit-less number is dimensionless and fails when consumed by a dimensioned slot.
  • tui.usage — the snippet uses .tui.*. Prefer the solver.settings.* tree, which the rest of this server validates against.

These exist purely to prevent today's most expensive failure modes from killing the gRPC channel (blocks) or silently mis-configuring the case (warnings); they do not constitute a planner and they do not cross-call each other.

Saved skills