Skip to content

kitlord/Simulation-MCP

Repository files navigation

Simulation MCP

Simulation MCP is an engineering-tool workspace with two independent Model Context Protocol (MCP) servers:

  • A Python stdio server for validated OpenFOAM case management and CFD operations.
  • A TypeScript NitroStack server for FreeCAD, Avogadro/Open Babel, and three interactive result-preview widgets.

They can run independently. An MCP host can use both servers in one workflow, but the TypeScript server does not start or proxy the Python OpenFOAM server automatically.

Architecture

MCP host
  |-- stdio --> Python Simulation MCP
  |              |-- FastMCP tool adapters
  |              |-- OpenFOAMService
  |              |-- OpenFOAMExecutor --> bash -lc --> OpenFOAM CLI
  |              `-- SIMULATION_ROOT/<case>/
  |
  `-- stdio / NitroStack transport --> NitroStack MCP server
                   |-- FreeCAD module --> XML-RPC --> FreeCAD MCP addon
                   |-- Avogadro module --> Open Babel CLI / local bridge
                   `-- widget tools --> Next.js widgets

Optional cloud path
  NitroStack deployment --> authenticated HTTPS tunnel --> loopback local bridge
                                                     |-- /freecad --> FreeCAD XML-RPC
                                                     `-- /avogadro --> local Open Babel
Path Responsibility
simulation_mcp/server.py Python FastMCP composition root and stdio entry point.
simulation_mcp/openfoam/ OpenFOAM input models, tool adapters, case service, executor, parsers, and safe domain errors.
src/app.module.ts NitroStack composition root for the dashboard, FreeCAD, Avogadro, and health modules.
src/modules/freecad/ Typed FreeCAD tools, sequential XML-RPC client, service layer, and workflow prompt.
src/modules/avogadro/ Zod schemas and local or bridged Open Babel operations.
src/modules/simulation/ display_simulation_results widget bridge.
src/local-bridge.ts Loopback-only HTTP bridge for a tunnelled local FreeCAD and Avogadro installation.
src/widgets/ Next.js implementations of the simulation dashboard and 3D previews.
examples/mcp_client.py Minimal Python stdio MCP client.
tests/ Python service tests.

Prerequisites

Install only the components required for the capabilities you plan to use.

Capability Requirements
OpenFOAM Python 3.12+, an Ubuntu OpenFOAM installation, and its etc/bashrc.
NitroStack A supported Node.js runtime and npm.
FreeCAD FreeCAD with its MCP addon installed and its XML-RPC server started. The addon is an external dependency and is not included in this repository.
Avogadro Open Babel CLI (obabel and obprop), its force-field data directory, and optionally Avogadro or the Open Babel GUI for opening files.
Cloud access to local engineering apps An authenticated HTTPS tunnel such as ngrok, plus a locally running bridge.

Quick Start

OpenFOAM Server

python3.12 -m venv .venv
source .venv/bin/activate
pip install -e '.[test]'
cp .env.example .env
# Set OPENFOAM_BASHRC in .env if discovery cannot find the installation.
simulation-mcp

The Python server communicates through stdio. Do not write ordinary output to its stdout; MCP protocol messages use that stream. Use python -m simulation_mcp as an equivalent entry point.

By default, cases are stored in ./simulation-data. Set SIMULATION_ROOT to use a different root, for example SIMULATION_ROOT=/data/simulation-cases.

NitroStack Server

npm install
cp .env.example .env
npm run dev

npm run build compiles the TypeScript application and bundles the widgets. npm start builds and starts the production server; npm run start:prod starts an existing production build. The NitroStack CLI installs widget dependencies while bundling, and npm run widget runs the widget-package command in src/widgets.

Start the FreeCAD addon RPC server before calling FreeCAD tools. Configure executable paths and data roots before calling Avogadro tools, then use avogadro_status to verify the installation.

Configuration

Copy .env.example to .env. Python reads its OpenFOAM settings with Pydantic settings; NitroStack and the bridge load the same file with dotenv.

OpenFOAM

Variable Default Purpose
SIMULATION_ROOT ./simulation-data Root directory containing server-owned cases.
OPENFOAM_BASHRC auto-discovered Explicit path to the OpenFOAM etc/bashrc.
OPENFOAM_COMMAND_TIMEOUT_SECONDS 3600 Per-command timeout, from 1 to 86,400 seconds.
LOG_LEVEL INFO Python log level.

When OPENFOAM_BASHRC is absent, the executor checks /opt/openfoam/etc/bashrc, then recent openfoam*/etc/bashrc installations under /opt and /usr/lib/openfoam.

FreeCAD

Variable Default Purpose
FREECAD_RPC_HOST / FREECAD_RPC_PORT 127.0.0.1 / 9875 Local FreeCAD addon XML-RPC endpoint.
FREECAD_RPC_URL unset Complete HTTP(S) RPC endpoint. Use a /freecad tunnel route when applicable.
FREECAD_RPC_TIMEOUT_MS 150000 XML-RPC timeout, from 1,000 to 3,600,000 ms.
FREECAD_FEM_MAX_TIMEOUT_SECONDS 1800 Maximum accepted FEM tool timeout.
FREECAD_ALLOW_REMOTE_RPC false Required before a non-loopback RPC endpoint is accepted.
FREECAD_ALLOW_CODE_EXECUTION false Enables the arbitrary Python execution tools. Use only for trusted clients.
FREECAD_RPC_BASIC_AUTH_USERNAME / FREECAD_RPC_BASIC_AUTH_PASSWORD unset Paired basic-auth credentials for a remote RPC endpoint.

FreeCAD operations are serialized in the NitroStack service so requests do not concurrently mutate the FreeCAD process. Inputs use 1-based FreeCAD subelement IDs: for example, face_id: 1 refers to Face1.

Avogadro And Open Babel

Variable Default Purpose
AVOGADRO_EXECUTABLE Windows Avogadro2 path Avogadro application used by avogadro_open_file.
OPENBABEL_GUI_EXECUTABLE Windows Open Babel GUI path GUI application used by avogadro_open_file.
OPENBABEL_EXECUTABLE / OPENBABEL_OBPROP_EXECUTABLE Derived from GUI path Open Babel CLI executables.
OPENBABEL_DATA_DIRECTORY Avogadro data directory Force-field data, passed as BABEL_DATADIR.
AVOGADRO_DATA_ROOT ./avogadro-data Root for molecule inputs and outputs.
OPENBABEL_COMMAND_TIMEOUT_MS 120000 Open Babel command and bridge-request timeout.
AVOGADRO_BRIDGE_URL unset Local or remote /avogadro bridge endpoint.
AVOGADRO_ALLOW_REMOTE_BRIDGE false Required before a non-loopback bridge URL is accepted.
AVOGADRO_BRIDGE_BASIC_AUTH_USERNAME / AVOGADRO_BRIDGE_BASIC_AUTH_PASSWORD unset Paired basic-auth credentials for the bridge.

Supported molecule formats are cjson, cml, mol, mol2, pdb, sdf, smi, and xyz.

Local Bridge

Variable Default Purpose
LOCAL_BRIDGE_PORT 9876 Loopback HTTP port used by the local bridge.
FREECAD_RPC_LOCAL_PORT 9875 Local FreeCAD RPC port to proxy from /freecad.

OpenFOAM Tools

All Python tools return a JSON envelope:

{"ok": true, "message": "Case created.", "data": {}}

Expected failures return ok: false with an error_code in data. The adapters return safe validation, case, installation, and command errors rather than Python tracebacks.

Tool Purpose
list_available_solvers Report availability of the supported solver catalog.
create_case, list_cases, clean_case, delete_case Create, inspect, clean, and permanently delete isolated cases.
import_geometry Copy an existing .stl into constant/triSurface.
generate_mesh, check_mesh Run blockMesh and checkMesh -allTopology -allGeometry.
set_boundary_conditions Write initial conditions for U, p, k, omega, epsilon, or nut.
set_simulation_parameters Update supported controlDict values.
run_solver, monitor_simulation Run an allowlisted solver synchronously or retain an in-process background status record.
calculate_forces, extract_results, export_vtk Run force post-processing, inspect result times and fields, and run foamToVTK.

Supported solver names are simpleFoam, pisoFoam, icoFoam, potentialFoam, rhoSimpleFoam, and buoyantSimpleFoam. list_available_solvers determines which of those are installed.

create_case creates a basic incompressible-flow skeleton with editable OpenFOAM dictionaries and a rectangular blockMeshDict. import_geometry owns an STL within the case but does not make the initial blockMesh conform to that geometry. For geometry-conformal production meshes, edit the generated dictionaries and add an appropriate meshing workflow such as snappyHexMesh.

Background solver state is held in memory. After the Python server restarts, provide no run_id to inspect the most recently modified case log instead.

Example Workflow

The MCP host supplies the input object expected by the Python tool signatures:

{"tool":"create_case","arguments":{"input":{"case_name":"naca2412"}}}
{"tool":"import_geometry","arguments":{"input":{"case_name":"naca2412","stl_path":"/data/naca2412.stl"}}}
{"tool":"generate_mesh","arguments":{"input":{"case_name":"naca2412"}}}
{"tool":"check_mesh","arguments":{"input":{"case_name":"naca2412"}}}
{"tool":"set_boundary_conditions","arguments":{"input":{"case_name":"naca2412","conditions":[{"patch":"inlet","field":"U","condition_type":"fixedValue","value":[30,0,0]}]}}}
{"tool":"run_solver","arguments":{"input":{"case_name":"naca2412","solver":"simpleFoam"}}}
{"tool":"calculate_forces","arguments":{"input":{"case_name":"naca2412","patches":["walls"]}}}
{"tool":"extract_results","arguments":{"input":{"case_name":"naca2412","fields":["U","p"]}}}
{"tool":"export_vtk","arguments":{"input":{"case_name":"naca2412","latest_time_only":true}}}

Run python examples/mcp_client.py after installing the Python package for a minimal official MCP-client example.

Python MCP Host Configuration

Configure a stdio-capable MCP host with the installed entry point:

{
  "mcpServers": {
    "simulation-mcp": {
      "command": "/absolute/path/to/.venv/bin/simulation-mcp",
      "args": [],
      "env": {
        "SIMULATION_ROOT": "/absolute/path/to/simulation-data",
        "OPENFOAM_BASHRC": "/opt/openfoam12/etc/bashrc"
      }
    }
  }
}

NitroStack Capabilities

FreeCAD Tools And Prompt

The freecad_ tools control the external FreeCAD MCP addon over XML-RPC.

Area Tools
Connectivity and documents freecad_status, freecad_create_document, freecad_list_documents, freecad_reload_document
Object operations freecad_create_object, freecad_edit_object, freecad_delete_object, freecad_get_objects, freecad_get_object, freecad_list_features
Measurement and queries freecad_get_face_normal, freecad_get_edge_direction, freecad_measure_distance, freecad_measure_angle, freecad_bounding_box, freecad_center_of_mass, freecad_intersects, freecad_closest_face, freecad_raycast, freecad_validate_constraints
Placement freecad_align_face_to_face, freecad_align_axis, freecad_rotate_about_edge, freecad_look_at, freecad_snap_to_vertex, freecad_snap_to_edge, freecad_snap_to_face
Mates freecad_mate_coincident, freecad_mate_parallel, freecad_mate_perpendicular, freecad_mate_tangent
Visualization freecad_get_view, freecad_preview_model
Parts library freecad_get_parts_list, freecad_list_parts_library_categories, freecad_search_parts_library, freecad_insert_part_from_library
Advanced operations freecad_execute_code, freecad_execute_code_async, freecad_run_fem_analysis

freecad_asset_creation_strategy is an MCP prompt that directs clients to inspect current documents, search the installed parts library before creating geometry, verify changes, and validate FEM setup before solving. The code-execution tools remain disabled unless explicitly enabled.

Avogadro Tools

Tool Purpose
avogadro_status Verify the configured applications, CLI tools, data directory, and molecule root.
avogadro_create_molecule Create a 2D or 3D structure from SMILES, optionally optimizing it.
avogadro_convert_molecule Convert formats and preserve, add, or remove hydrogens.
avogadro_optimize_molecule Optimize geometry with MMFF94, MMFF94s, UFF, GAFF, or Ghemical.
avogadro_get_properties Obtain Open Babel molecular properties.
avogadro_preview_molecule Render a bounded interactive ball-and-stick preview.
avogadro_list_files List supported files under AVOGADRO_DATA_ROOT.
avogadro_open_file Launch a stored molecule in Avogadro or the Open Babel GUI.

Molecule file paths must be relative to AVOGADRO_DATA_ROOT; absolute paths and traversal outside that root are rejected. Preview source files are limited to 25 MB and output is limited to 999 atoms and 999 bonds.

Widgets

Tool Widget Behavior
display_simulation_results simulation-dashboard Displays mapped OpenFOAM status, mesh data, residuals, forces, and VTK artifact names.
freecad_preview_model freecad-model-preview Converts bounded FreeCAD tessellation buffers to an in-browser GLB preview.
avogadro_preview_molecule avogadro-molecule-preview Builds an in-browser ball-and-stick GLB preview from Open Babel geometry.

The dashboard does not load VTK files. It identifies exported artifacts for use in a compatible viewer such as ParaView. VTK rendering in a browser would require a separately hosted file endpoint and a WebGL viewer.

Local Bridge And Remote Deployments

For a cloud-hosted NitroStack server to access local FreeCAD and Open Babel, run the loopback bridge and expose only its port through an authenticated HTTPS tunnel:

npm run bridge
ngrok http 9876 --basic-auth="engineering:YOUR_LONG_RANDOM_PASSWORD"

The bridge binds to 127.0.0.1, provides GET /health, proxies all /freecad traffic to local XML-RPC, and accepts validated POST /avogadro actions. Its JSON request body limit is 1 MiB. Authentication is supplied by the HTTPS tunnel or another reverse proxy; the bridge itself does not implement authentication.

Configure the NitroStack deployment with the tunnel's HTTPS URL and matching credentials:

FREECAD_RPC_URL=https://your-tunnel.ngrok-free.app/freecad
FREECAD_RPC_BASIC_AUTH_USERNAME=engineering
FREECAD_RPC_BASIC_AUTH_PASSWORD=YOUR_LONG_RANDOM_PASSWORD
FREECAD_ALLOW_REMOTE_RPC=true
FREECAD_ALLOW_CODE_EXECUTION=false

AVOGADRO_BRIDGE_URL=https://your-tunnel.ngrok-free.app/avogadro
AVOGADRO_BRIDGE_BASIC_AUTH_USERNAME=engineering
AVOGADRO_BRIDGE_BASIC_AUTH_PASSWORD=YOUR_LONG_RANDOM_PASSWORD
AVOGADRO_ALLOW_REMOTE_BRIDGE=true

Keep the FreeCAD addon, bridge, and tunnel running. A new ephemeral tunnel URL must be applied to both remote endpoint variables after a tunnel restart.

Security And Operational Notes

  • OpenFOAM case paths are confined to SIMULATION_ROOT; case names are allowlisted and STL imports require an existing .stl file.
  • The Python executor uses asyncio.create_subprocess_exec. It invokes bash -lc only to source the OpenFOAM environment, then runs commands assembled from validated values.
  • Avogadro operations use direct execFile arguments and confine molecule paths to AVOGADRO_DATA_ROOT.
  • FreeCAD rejects non-loopback endpoints unless FREECAD_ALLOW_REMOTE_RPC=true; Avogadro applies the same opt-in rule to bridge URLs.
  • freecad_execute_code and freecad_execute_code_async execute arbitrary Python in FreeCAD. Keep them disabled for untrusted clients and remote deployments.
  • The NitroStack system health check runs every 30 seconds and reports degraded when Node.js heap use reaches 90%.

Development And Verification

# Python tests
pip install -e '.[test]'
pytest

# TypeScript application and widgets
npm install
npm run build

The Python test suite covers case creation/listing, case-name traversal rejection, and STL import validation. The repository currently has no TypeScript test suite; npm run build is the TypeScript and widget verification command.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors