MCP Server
The extension ships a standalone MCP server (dist/mcpServer.js) that exposes its mesh and simulation-setup engine to any MCP client (Claude Code, Claude Desktop, …) — no VS Code needed. Anything the sidebar and palette can do to a mesh by path is reachable here; UI-only surfaces (preview layout, Inspect, What's New) are not.
Build it once with npm run compile, then register it, e.g. with Claude Code:
bash
claude mcp add kratos-mdpa -- node /abs/path/to/VSCode-MDPA-Preview/dist/mcpServer.jsor in a generic client config:
json
{ "mcpServers": { "kratos-mdpa": { "command": "node", "args": ["/abs/path/to/dist/mcpServer.js"] } } }| Tool | What it does |
|---|---|
mesh_info | Parse any supported mesh (.mdpa, VTK family, .stl/.obj/.ply, and the extended meshio++ formats) and summarize nodes, blocks, SubModelParts, fields, diagnostics. Named groups from formats that carry them (gmsh physical groups, Abaqus sets, Exodus blocks/node sets/side sets) appear as SubModelParts. inputFormat forces a reader no extension defaults to (ansys, freefem, ansysinp). timeStep selects a step of a multi-step mesh (Exodus, MED since meshio++ 9.9.0, GiD postprocess, CGNS/Tecplot since 11.3.0, XDMF, VTKHDF, ParaView .pvd, OpenFOAM time directories); the response then includes timeStep/timeValues (Exodus, GiD, MED, CGNS, Tecplot, XDMF and OpenFOAM list theirs). metadataOnly skips parsing and reports the file header (counts, block shapes, data-array names, regions, bbox) for the formats whose reader stays header-only (.xdmf/.xmf, .msh, .med, .cgns, .dat/.tec, the GiD .post.* set) — anything else is refused rather than served at header price. An OpenFOAM case is opened through its .foam marker, like any other path. piece reads one piece of a .pvtu/.pvtp and dropGhosts (default true for those two) drops cells duplicated at partition seams; region reads one region of a multi-region OpenFOAM case instead of merging them all. summary is the universal counterpart: it reports the file shape for every supported format, including .mdpa and the natively-parsed VTK/STL/OBJ/PLY, and never refuses for ineligibility — it reports cost instead (header a bounded read, scan a whole-file stream that builds nothing, buffered/read the meshio++ paths that hold or parse the file), with bytesRead saying what it actually took and unknown naming what the format cannot report so a blank is not read as a zero. A mesh with one-node (sphere/particle) elements also reports a spheres section — how many, whether they carry a RADIUS, and a suggested radius if not. An .mdpa that declares Begin Properties also reports a properties section with the parsed values, one that declares Begin Constraints a constraints section (per block: name, variables, row count and id range, plus undefinedIds — constraint ids a SubModelPart lists that no block defines), and a mesh with line cells a beams section (how many carry a CROSS_AREA, and how many of those are Elements rather than boundary conditions) |
mesh_quality | Geometric quality metrics (edge ratio, angles, gradation) with Kratos thresholds and worst-element ids, plus a watertight section: how many boundary edges (holes), non-manifold edges, inconsistently wound face pairs and zero-area faces — the counts rather than a bare flag, since three boundary edges is a pinhole and three thousand is a surface that was never closed |
mesh_size | Nodal size (NODAL_H, a port of Kratos FindNodalHProcess) + element size (mean edge length), with box-whisker statistics and the IQR-outlier smallest/largest element ids |
mesh_field_integrate | Cell-measure-weighted total and mean of the cell fields — a density field's total mass, a flux field's total power, an occupied volume — for the whole mesh and per named region, which here means one row per entity block and one per SubModelPart. Regions overlap rather than partition, so their totals need not sum to the domain total |
mesh_curvature | Discrete mean / Gaussian / principal curvature statistics of a surface mesh, the Gauss–Bonnet check (angle-defect sum vs 2πχ), boundary / isolated / degenerate node counts and orientation warnings — read-only; mesh_transform's curvature op writes the fields |
mesh_compare | Compare two meshes and their fields by entity id: a verdict (identical / equal within tolerance / different), moved nodes with the worst id, entities only in one mesh or with changed connectivity or type per kind, block-name and SubModelPart-membership differences, and per-field max / mean / RMS / relative error with coverage gaps counted (never compared as 0). With variable it also compares one field — by id, or by spatial point sampling of the other mesh's nodal field — and with outputPath writes the difference mesh (<name>_DIFF, _ABS, _REL) |
mesh_derive | Write a new mesh derived from the opened one (nothing is written back to the input): a slice through a plane, the isosurface of a nodal field, a threshold region where a field lies in an absolute or normalized window, a decimated copy of a triangle surface, or a regular sampling of it — grid (a lattice from nothing, no input mesh needed), voxelize (occupancy) and sdfVolume (signed distance, dense or octree), sized by cellSize or resolution with a memory estimate and a 20-million-cell refusal before anything runs; a complete lattice can be written as .vti (survivors keep their ids and cell-field values). Slices and isosurfaces carry the interpolated fields and tag every cell with the cell it was cut from (SOURCE_ENTITY_ID / SOURCE_ENTITY_KIND); a threshold region keeps original ids, groups, fields, Properties and the conditions still on it, or returns its boundary surface. Normalized windows need an explicit fixed reference range — rescaling per frame is opt-in |
mesh_probe | Sample a nodal field along a polyline — distance-versus-value rows with a gap (null) wherever the path leaves the mesh or crosses a region the field was never written, never a fabricated 0 — optionally across every step of a time series, with CSV output |
mesh_split | Split one mesh into several files that keep the source's ids, kinds, Properties, SubModelParts and fields: partition writes N per-part meshes with optional ghost layers (every cell owned by exactly one part, ghosts flagged, weights by an elemental field, interface nodes and imbalance in the manifest — space-filling curve only, the WebAssembly build has no KaHIP), or component / type / field split into connected bodies, element types or field values |
mesh_transform | Apply a sequence of mesh operations (scale/translate/rotate, merge nodes, remove orphans, linear→quadratic, delete/rename SubModelPart, reorganize the SubModelPart tree (create / move / merge / add / remove entities), write mesh-size fields, set/scale the sphere-element RADIUS, MMG remesh & level-set split, smooth, reorder, partition, refine, simplexify, linear→linear-only (quadratic→linear), crop, field calculator + nodal/elemental averaging, field gradient/divergence/curl, field Hessian, Zienkiewicz-Zhu error estimate, signed distance to an imported surface, mass-preserving field transfer from another mesh, merge another mesh file) inline or from a saved Edit-sidebar recipe |
mesh_convert | Convert between formats — ours (.mdpa, .vtk, .vtu, .vtp, .stl, .obj, .ply) plus ~35 written by meshio++ (.msh, .inp, .bdf, .unv, .mesh, .vol, .su2, .xdmf, .off, .poly (Triangle), the HDF5 containers .cgns/.h5m/.hmf/.med, plus the field-only .dex/.ip/.mff and write-only .svg/.tikz figures, …); plus .e/.exo/.ex2 (Exodus, lossy — see the format table). inputFormat/outputFormat override the extension defaults; timeStep selects a step of a multi-step input (Exodus, MED, GiD postprocess, CGNS/Tecplot, XDMF, OpenFOAM time directories). piece, dropGhosts and region select the input as for mesh_info. Writing .xdmf also emits a companion <stem>.h5 |
mesh_extract_submodelpart | Slice one SubModelPart (+ subtree) into a standalone file |
mesh_extract_skin | Extract the boundary skin of a mesh's volume cells (+ any pre-existing surface cells) as a standalone surface mesh — a native boundary-face walk, so SubModelParts survive (narrowed to node membership) |
mesh_field_series | One entity's value for one variable across every step of a time series — the headless mirror of the viewer's Plot over time, and the only tool that reads a value across steps. Steps are discovered from a single path exactly as the preview does (a sibling <prefix>_<rank>_<step> series (VTK, STL/OBJ/PLY and meshio formats without an in-file timeline), an in-file series such as Exodus/GiD/XDMF/OpenFOAM, or a lone file), and source reports which was found. A gap is null, never 0, with missingField and missingId counted apart; topologyChangedAt warns that the mesh changed size mid-series. Writes a .csv when outputPath is given |
mesh_export_table | Tabulate every node/element/condition/geometry as rows of plain values — id, coordinates or block+connectivity, optional SubModelPart membership, and every field defined there. The only tool that reports field values (mesh_info reports field metadata; mesh_find_entity answers for one id). With outputPath it writes the whole table as .csv/.xlsx; without one it returns limit rows from offset as JSON (default 100, max 10 000). submodelpart restricts rows to one part and its subtree |
mesh_pack_series | Packs a solver run's per-step mesh files into ONE transient XDMF time series. path is the vtk_output directory or any one step file; steps are found the same way the preview finds them (<prefix>_<rank>_<step>), and the step label becomes the time, so the axis carries the Kratos step numbers rather than 0..N-1. Not mesh_convert with outputFormat: xdmf — that writes ONE mesh, this writes every step. Only .xdmf/.xmf are accepted (the one format that carries a mesh time series) and the sibling .h5 is part of the output, not an extra. Refuses a lone file, a format that already carries its own steps, and a series whose mesh changes between steps (an XDMF series has one grid for all steps). Streams one step at a time, and the result re-opens in the preview as a timeline. |
mesh_find_entity | Locate a node/element/condition/geometry by id (coordinates, connectivity, owning SubModelParts) |
mesh_capabilities | meshio++ capability inventory: the installed WASM build's readers/writers, per-reader options-awareness, backend and cgnslib — next to the extension's routing (read candidates, write targets, in-file vs filename timelines, header-only metadata set, unrouted keys with reasons) and a fidelity section (the carry/adopt adapter's carrier keys, SubModelPart region prefix, and which model slots it retains). Takes no arguments |
problemtype_list / problemtype_describe | Enumerate built-in + workspace problemtypes; get the full form/condition/material spec plus a default case skeleton |
case_run | Start a Kratos solve (generating the case files first unless told not to). The solver is always spawned detached, with its output appended to <stem>.kratosrun.log, so it outlives the MCP server — which cannot own a run, since its stdout is the protocol channel. waitSeconds (default 10, 0 = don't wait) blocks for the exit; expiry is not an error but a handoff, returning running with the pid and log path, since the only applicable timeout belongs to the client and the server cannot observe it. Refuses to start over a run that may still be active unless forced. python / installPath / extraEnv are arguments, defaulting to a pip-installed Kratos |
case_stop | Stop the latest run by the pid in its sidecar, escalating SIGINT → SIGTERM → SIGKILL (Windows: immediate terminate — signals are not real there) and reporting which rung worked — SIGINT is what lets python close its last result file rather than truncate it. Records the stop before signalling so it reads cancelled, not failed. A run that already ended is never signalled, since pids get reused |
case_status | The latest Kratos run for a mesh: status, exit code, command, pid and a vtk_output/ summary. Reads the <stem>.kratosrun.json sidecar, so either side can see what the other started — and reconciles it against the OS rather than repeating it, so a stale record whose process is gone reads orphaned and one whose pid is alive reads detached, never running |
case_validate / case_write_state | Check a case setup against mesh + problemtype; write <stem>.kratoscase.json (picked up by the sidebar) |
case_generate | Write ProjectParameters.json, the materials JSON and MainKratos.py next to the mesh — same output as the sidebar's Generate button, including solver mesh-name adaptation (a non-.mdpa mesh is always converted to <stem>_case.mdpa first) |
problem_pack / problem_unpack | Bundle the whole problem (mesh + edit recipe + case state + generated case files) into one zip, or extract such an archive — the same format as the File menu's Save problem… / Load problem… |
MMG operations run in-process and block the server while they run; progress is streamed as MCP log messages.