Skip to main content
Glama

FERS — structural FEM

Server Details

Structural FEM for AI agents: frames, plates, buckling, seismic and Eurocode checks, solved locally.

Ownership verified
Status
Healthy
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL
Repository
Jeroen124/FERS_core
GitHub Stars
2

TDQS

Score is being calculated.

Available Tools

35 tools
add_imperfection_caseAdd a geometric imperfection
Read-only
Inspect

Add a geometric imperfection — a global sway (out-of-plumb lean, EN 1993-1-1 §5.3.2) and/or a member bow — bound to specific load combinations. The solver perturbs the geometry before solving those combinations, so it feeds both first-order and P-Delta results. Give the sway as a ratio denominator (200 means a 1/200 lean); it is stored in radians. IMPORTANT: the engine ignores an unknown combination id SILENTLY, so a typo would apply no imperfection at all — this tool rejects unknown ids instead. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelNoStringified FERS model JSON
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
sway_axis_xNoSway rotation axis X (default 0).
sway_axis_yNoSway rotation axis Y (default 0).
sway_axis_zNoSway rotation axis Z (default 1). The lean direction is axis x height_direction.
height_direction_xNoDirection height is measured along, X (default 0).
height_direction_yNoY (default 1 — these models are Y-up).
height_direction_zNoZ (default 0).
sway_magnitude_radNoSway angle directly in radians, if you would rather not use a ratio (0.005 = 1/200).
translation_axis_xNoBow direction X (default 1).
translation_axis_yNoBow direction Y (default 0).
translation_axis_zNoBow direction Z (default 0).
load_combination_idsYesJSON array of combination ids this imperfection applies to, e.g. [1,2]. Required — an imperfection only affects the combinations it names.
translation_magnitudeNoBow amplitude in model length units. Required when translation_memberset_ids is given.
sway_ratio_denominatorNoSway as 1/N: pass 200 for a 1/200 lean. Converted to radians for you.
translation_memberset_idsNoJSON array of member-set ids to give a bow imperfection, e.g. [1].
add_loadAdd a load
Read-only
Inspect

Add ONE load of any kind to an existing load case. Choose kind: "nodal_force" (force at a node), "nodal_moment" (moment at a node — direction is the moment AXIS, right-hand rule), "distributed" (line load along a member; covers uniform, TRAPEZOIDAL/TRIANGULAR via end_magnitude, and PARTIAL via start_frac/end_frac), "member_point_force" / "member_point_moment" (at a fractional position along a member, in global or local axes), "surface" (pressure over a convex planar polygon, distributed onto the coplanar members inside it), "plate_pressure" (pressure on a meshed plate surface). SIGN: direction_x/y/z is a GLOBAL vector — gravity is direction_y = -1. The direction is normalised for you and the whole load stays in magnitude (the raw engine multiplies component-wise, so an unnormalised [0,-2,0] would silently double the load). Distributed intensity is per unit of MEMBER length, not of horizontal projection. Units are the model's own (default N, m) EXCEPT plate_pressure, which must always be in SI pascals. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault
axesNomember_point_* only: "global" (default) or "local" (member frame, local x along the member).
kindYesnodal_force | nodal_moment | distributed | member_point_force | member_point_moment | surface | plate_pressure
nodeNoTarget node id — required for nodal_force / nodal_moment.
modelNoStringified FERS model JSON
memberNoTarget member id — required for distributed / member_point_force / member_point_moment.
polygonNosurface only. >= 3 vertices, planar and CONVEX, e.g. [[0,0,0],[6,0,0],[6,0,4],[0,0,4]]. Only members lying exactly in that plane receive load.
end_fracNodistributed only. Where it ends, 0..1 (default 1).
positionNoFraction along the member, 0 = start node, 1 = end node. Required for member_point_*. Clamped to [0,1] (the engine does not range-check it).
magnitudeNoLoad size, always positive — put the sense in direction_x/y/z. Force / force*length / force per length / force per area depending on kind.
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
projectedNoplate_pressure only. false (default) = pressure on the true area; true = on the projected area (snow-style).
start_fracNodistributed only. Where the line load starts, 0..1 (default 0). Use 0.25/0.75 for a partial UDL over the middle half.
surface_idNoplate_pressure only: id of a model.plate_surfaces[] entry. Prefer this.
direction_xNoX component of the direction (or moment axis). Default 0.
direction_yNoY component. Gravity is -1 in these Y-up models. Default 0.
direction_zNoZ component. Default 0. At least one component must be non-zero.
load_case_idNoid of the load case to append to (from add_load_case)
end_magnitudeNodistributed only. Intensity at end_frac. Omit for uniform; set it different from magnitude for a TRAPEZOID; magnitude 0 + end_magnitude w gives a TRIANGLE. There is no separate shape field — the shape IS these numbers.
distribution_dxNosurface only, optional: X of the span direction the load is carried in.
distribution_dyNosurface only, optional: Y of the span direction.
distribution_dzNosurface only, optional: Z of the span direction.
plate_element_idNoplate_pressure only: one generated element. Element ids change whenever the mesh changes — prefer surface_id.
add_load_caseAdd a load case
Read-only
Inspect

Add an empty load case — a named bucket of UNFACTORED loads of one origin (dead, snow, wind, imposed). Put loads in it with add_load, then combine cases with partial factors using add_load_combination. A load case on its own never reaches a code check: checks envelope over COMBINATIONS only. Returns the model plus the new load_case_id. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesName, e.g. "G - Permanent", "S - Snow", "W - Wind (+X)". results.loadcases is keyed by this, so it must be unique.
modelNoStringified FERS model JSON
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
add_load_combinationAdd a load combination
Read-only
Inspect

Add ONE factored load combination — a weighted sum of load cases at a given limit state. This is what the solver designs against: unity checks envelope over COMBINATIONS, never over raw load cases, so a load case no combination references is invisible to every check. ALWAYS set limit_state: it is the only field of a combination the solver reads, and leaving it null makes every SLS deflection check return an empty result that reads as a pass. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYese.g. "ULS 6.10 - leading Snow". results.loadcombinations is keyed by this.
checkNoReport metadata only. Defaults to "ALL".
modelNoStringified FERS model JSON
factorsYesLoad case ids to partial factors: {"1": 1.35, "2": 1.5} or [{"load_case_id":1,"factor":1.35}]. Negative factors are legal (uplift / favourable).
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
situationNoReport metadata only; the solver never reads it.
limit_stateNoULS | SLS | FLS | ALS (case-sensitive). Strongly recommended — see the tool description.
add_plate_grid_elementsAdd an explicit plate mesh
Read-only
Inspect

Author plate elements EXPLICITLY (model.plate_elements) as a regular quad grid over four corner points, instead of letting the solver mesh a PlateSurface. Creates the nodes, optionally supports the perimeter, and writes one 4-node PlateElement per cell. Verified to give bit-identical results to the equivalent structured surface mesh (16x16: max|dz| 4.31048e-3 m either way).

USE THIS WHEN YOU NEED PLATE UNITY CHECKS. In engine 0.2.52 a unity check targeting plates (AllPlates / PlateSurfaces / PlateElements with a PlateStress variable) returns an EMPTY per_entity for anything meshed from a PlateSurface — status "Green", max_utilization 0, no warning — because the mesh is generated on an internal working copy while the checks run against the original document. Explicit plate elements survive in that document and are checked normally (verified 256/256 entities).

ALSO USE IT when you need stable, known plate element ids: mesh-generated ids start at max(explicit id)+1 and are never echoed back, so an element-targeted pressure on a generated id is a silent no-op.

COST: verbosity. An N x N grid emits (N+1)^2 nodes and N^2 elements inline, and the engine allocates a dense (7 x nodes)^2 block, so keep total model nodes under ~2000. Load the grid with ONE add_load kind:"surface" whose polygon covers it, rather than N^2 individual pressures. Same theory guidance as add_plate_surface: PlateTheory "Auto" resolves to Mindlin, which shear-locks (-55% at 8x8 on a span/thickness 80 slab), so prefer "kirchhoff" at span/thickness >= 20.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelNoStringified FERS model JSON
theoryNoauto | kirchhoff | mindlin | engine_auto.
behaviorNoshell | membrane.
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
thicknessNoPlate thickness in metres.
divisions_uNoCells along the first edge.
divisions_vNoCells along the other edge.
material_idNoExisting model.materials id.
plane_stateNoplane_stress | plane_strain.
edge_supportNonone | pinned | fixed on the perimeter.
corner_pointsYesJSON array of exactly 4 [x,y,z] corners, in order around the panel.
first_element_idNoStarting id for the generated elements.
local_x_directionNo[x,y,z] local axis direction.
add_plate_openingCut an opening in a plate
Read-only
Inspect

Cut a hole (stairwell, duct, riser) in an existing PlateSurface: creates the hole's boundary nodes and appends a PlateOpening to that surface's openings. The hole ring must be coplanar with, and lie strictly inside, the outer boundary; elements whose centroid falls in the hole are dropped, so the applied load drops with the removed area (verified: a 1x1 m hole in a 4x4 m slab under 10 kPa took the total reaction from 160000 N to exactly 150000 N).

HARD CONSTRAINT: openings only work with the Delaunay mesher. The structured mesher rejects them outright ("PlateSurface N Structured meshing does not support openings."), so this tool switches the surface to mesh method "Unstructured" with a target_size and tells you it did. That makes the surface's edge-node positions unpredictable, which is why the tool REFUSES to convert a surface whose structured edge grid is carrying a support: those pre-created edge nodes would be stranded off the new mesh and the plate would silently fall back to hanging on its corners (measured 6x too flexible, with the load still balancing exactly). If you need both an opening and a supported edge, author the surface as unstructured from the start and support it by other means.

TARGET SIZE IS A WHOLE-SURFACE SETTING, so a SMALL hole is the expensive case, not the cheap one: left to default (half the shortest hole edge) a 200 mm duct in a 6 m x 6 m slab asks for ~6100 mesh nodes and the engine aborts on that with a raw wasm trap. The default is therefore clamped to what the node budget allows — which means the hole is resolved coarsely and its stress concentration is NOT converged; model the region around the opening as its own smaller surface if you need it sharp. An explicit target_size that busts the budget is refused rather than clamped.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelNoStringified FERS model JSON
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
opening_idNoOverwrite this opening id.
surface_idNoid of the plate surface to cut the hole in.
target_sizeNoMesh size around the hole, metres. Openings force the Delaunay mesher.
corner_pointsNoJSON array of [x,y,z] points bounding the hole, inside the surface and in its plane.
boundary_node_idsNoExisting node ids bounding the hole instead.
add_plate_surfaceAdd a plate or slab
Read-only
Inspect

Add a meshed plate/shell surface (slab, wall, deck, panel) to a FERS model. You give the corner points; the tool creates the boundary nodes, optionally the full edge-node grid with a support, and appends the PlateSurface to model.plate_surfaces. The SOLVER meshes it at solve time — never author plate_elements for a surface yourself. Load it with add_load kind:"plate_pressure" (surface_id), not with distributed_loads.

MESHING DECIDES WHETHER YOUR MODEL IS CORRECT. The mesher only ever creates NODES and PLATE ELEMENTS: it never splits members and never adds supports, so a plate connects to the rest of the structure ONLY through nodes it shares by exact coordinate. (1) Leave the mesh unset and the surface becomes TWO TRIANGLES spanning the corners — it still solves and reactions still equal q x A, so nothing looks wrong; this tool rejects that instead. (2) A supported or member-connected EDGE only exists where a node sits at an exact mesh-grid coordinate: structured meshing has predictable positions so edge_support can pre-create them, unstructured/Delaunay does not, so edge_support with unstructured meshing is rejected. (3) If a beam runs along a plate edge, split that beam into segments ending on the grid, or the plate hangs off its two end nodes only (measured 4.2x too flexible, beam moment 2.5x too low) with no warning.

THEORY — THE ENGINE DEFAULT IS WRONG FOR THIN PLATES. PlateTheory "Auto" is resolved unconditionally to Mindlin (the OpenAPI text claiming otherwise is stale). Mindlin (DSG3) shear-locks: on a simply-supported square slab at span/thickness 80 the centre-deflection error was -86.1% / -55.2% / -8.1% / -0.4% at 4x4 / 8x8 / 16x16 / 32x32, where Kirchhoff (DKT, rewritten and patch-test-exact in 0.2.44) gave -5.5% / -1.4% / -0.3% / -0.03%. So: span/thickness >= 20 -> "kirchhoff"; span/thickness < 10 -> "mindlin" plus a fine mesh (it correctly adds the ~10% shear deflection Kirchhoff misses). theory:"auto" (the default) makes that choice from the SMALLER IN-PLANE DIMENSION of your boundary (not its shortest edge, which collapses the moment an edge carries intermediate nodes) and tells you which it picked and why.

BOUNDARY POINTS: give the ring OPEN. A closing point that repeats the first is dropped for you (and said so in the notes); any other repeated point is refused, because coincident points collapse onto one node and leave boundary_node_ids with a duplicate id — measured, that solves with no error, balances the load to exactly q x A, and is 513% wrong on deflection.

ALSO TRUE OF EVERY PLATE: plates carry NO self-weight (enable_self_weight loops over members only) — add density x thickness x g as a pressure. Plates contribute NO geometric stiffness, so alpha_cr from a model where plate stability governs is unconservative. behavior "membrane" does not remove bending stiffness, it scales it by 1e-6, so an out-of-plane load on a membrane plate returns absurd deflections rather than an error. Boundary point ORDER sets the element normal and therefore the sign of mx/my/mxy. Keep total model nodes under ~2000: the engine allocates a dense (7 x nodes)^2 block and aborts above that with a raw wasm trap, so both meshers are rejected here once the projected node count crosses it (Delaunay produces ~1.7 nodes per target_size^2 of area, measured, so target_size 0.1 on a 4 m x 4 m slab is already fatal).

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoLabel for the surface.
modelNoStringified FERS model JSON
offsetNoOffset of the plate mid-surface, metres.
theoryNoauto (default: picks from span/thickness) | kirchhoff (best for thin plates) | mindlin (shear-flexible but coarse-mesh stiff) | engine_auto.
behaviorNoshell (default) | membrane.
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
thicknessNoPlate thickness in metres. Required, > 0.
surface_idNoOverwrite this surface id instead of allocating a new one.
divisions_uNoStructured mesh divisions along the first edge. Use >= 8 for Kirchhoff, >= 16-32 for Mindlin.
divisions_vNoDivisions along the other edge. Omit one and it is inferred from the edge-length ratio.
material_idNoExisting model.materials id. Defaults to the first material.
mesh_methodNoauto | structured | unstructured (Delaunay — required for openings).
plane_stateNoplane_stress (default) | plane_strain.
target_sizeNoElement edge length for the unstructured mesher, in metres.
edge_supportNonone (default) | pinned | fixed — supports the generated perimeter nodes.
corner_pointsNoJSON array of [x,y,z] corner points forming an OPEN planar ring (do not repeat the first point). At least 3; exactly 4 for the structured mesher. Give this OR boundary_node_ids.
element_shapeNoauto | triangle | quad.
classificationNoFree-text group name.
edge_support_idNoReuse an existing nodal_supports id for the edge.
boundary_node_idsNoJSON array of EXISTING node ids to hang the plate off, e.g. [1,3,8,6].
local_x_directionNo[x,y,z] setting the plate's local axes, which fix the sign and meaning of mx/my/mxy. Defaults to the first edge.
stiffness_modifier_shearNoMultiplier on shear stiffness.
stiffness_modifier_bendingNoMultiplier on bending stiffness (0.5 doubles deflection).
stiffness_modifier_membraneNoMultiplier on membrane stiffness.
add_unity_checkAdd a code check
Read-only
Inspect

Append a unity (code) check to a model's analysis.unity_checks. check is a UnityCheckDefinition JSON (see get_check_schema). Returns the updated model JSON to pass to run_unity_checks. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault
checkYesStringified UnityCheckDefinition JSON (get its schema + an example from get_check_schema)
modelNoStringified FERS model JSON
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
build_modelBuild a model from a node/member graph
Read-onlyIdempotent
Inspect

Build a complete, solver-ready FERS model from an arbitrary node/member graph: 3-D frames, trusses, pitched roofs, bracing, towers — anything create_beam/create_frame cannot express. Returns a full FERS JSON document ready for solve_model.

GEOMETRY (1-BASED). nodes is a JSON array of [X, Y, Z] triples in METRES, Y up (gravity is −Y). The index you use to refer to a node IS its solver node id: nodes[0] is node 1, so results (displacement_nodes, reaction_nodes) come back under exactly the numbers you wrote. Index 0 is rejected. members is a JSON array of [startNode, endNode] / [startNode, endNode, "SectionName"] / [startNode, endNode, "SectionName", {options}]; member ids are 1..N in the order given. Member options: rotation_angle (DEGREES, rolls the section about the member axis), type ("Truss" for a pin-jointed axial-only bar; also Tension/Compression/Cable/Rigid), hinge ("start"|"end"|"both" — releases both bending moments there; at a joint only ONE of the members may be released, because a node whose every member end is released has no rotational stiffness left and the solve then fails outright), classification (free-text group name; one member_set per distinct value, and unity checks can target it).

COLUMN ORIENTATION — READ THIS. FERS's strong bending axis is the LOCAL z axis (i_z > i_y for an I-section), and the member local frame is built from a global-Y reference vector. A HORIZONTAL member therefore bends strong-axis under gravity automatically, but a VERTICAL member gets local y = global Z and local z = global X, so it resists sway along global X with its WEAK axis i_y. Verified: a 6 m cantilever column pushed 20 kN in +X deflects 1.1357 m at rotation_angle 0 (= PL³/3E·i_y) and 0.0820 m at rotation_angle 90 (= PL³/3E·i_z) — a 13.8× difference the solver will never warn about. In plane:"XY" this tool sets rotation_angle 90 on vertical bending members for you (reported in info.auto_rotation), because sway there is along X; in "3D" it only warns, since which axis you want depends on the structure — set rotation_angle explicitly.

SUPPORTS. supports maps a 1-based node number to a preset or an explicit DOF object: "fixed" (all 6 DOFs), "pinned" (X,Y,Z fixed, rotations free), "roller_x"/"roller_y"/"roller_z" (free to slide along that global axis), "free". For anything else pass {"X":"fixed","Y":"fixed","Z":"free","RX":"free","RY":"free","RZ":2.5e6} — a NUMBER is a spring stiffness (N/m for X/Y/Z, N·m/rad for RX/RY/RZ), and that node then settles by exactly force/stiffness. Watch the sign when you read results: a SPRING reaction comes back with the OPPOSITE sign to a rigid support carrying the same force (measured: +30 kN at the pin and −30 kN at the spring of one beam), so do not add the two up. Any DOF you leave out of an explicit object is written as Free (never omitted: in the raw JSON an absent DOF means FIXED, which is the opposite of what everyone expects).

PLANE. plane is "3D" (default) or "XY". "XY" requires every node to have Z = 0 and pins Z, RX and RY at EVERY node, which is what makes a planar model well-posed — essential for a planar TRUSS, where the bars carry exactly zero out-of-plane stiffness. Note that analysis.options.dimensionality is cosmetic: the solver never reads it, so only supports can make a model planar. An under-restrained model whose loads reach the free direction is reported, not solved: that load case's errors_and_warnings carries singular_model and its converged flag is false. Read errors_and_warnings before using any number.

SECTIONS. Give a library name ("IPE300", "HEA200", "CHS 114.3x5", "RHS 100x50x5", "UB 457x191x67", …) in the member row and it is looked up and inserted with all EC3 moduli. For a rectangle or your own numbers, declare it in sections (same object shape as create_section) and reference it by name. A member naming no section gets the first declared section, else default_section (IPE300).

LOADS are in kN, kN/m and kNm and are converted to newtons internally. loads is a list of load cases: {"name":"G","udl":[[member, w]],"nodal_loads":[[node, Fx, Fy, Fz]],"nodal_moments":[[node, Mx, My, Mz]],"point_loads":[[member, position0to1, Fx, Fy, Fz]]}. A 2-entry udl row [member, w] is w kN/m acting DOWN (−Y); a 4-entry row [member, wx, wy, wz] is a full vector. Combine them with load_combinations: [{"name":"ULS","factors":{"G":1.35,"W":1.5}}], referencing load cases BY NAME; omit it for two automatic ones over every case: combination 1 "SLS characteristic (auto)" at factor 1.0 and combination 2 "ULS (auto)" at 1.35. A combination you name gets limit_state "ULS" unless you give one, because a null limit_state makes every later unity check silently evaluate nothing and report a pass.

LIMITS: 100 members on the Free tier (hard "LimitExceeded" above that), so keep element counts modest.

ParametersJSON Schema
NameRequiredDescriptionDefault
loadsNoJSON array of load cases in kN / kN·m: [{"name":"G","udl":[[member, w]],"nodal_loads":[[node,Fx,Fy,Fz]],"nodal_moments":[[node,Mx,My,Mz]],"point_loads":[[member,pos0to1,Fx,Fy,Fz]]}]. A 2-entry udl row is kN/m acting DOWN.
nodesYesJSON array of [X, Y, Z] node coordinates in metres, Y up. The 1-based array position IS the node id: the first triple is node 1, so results come back under the numbers you wrote. Minimum 2 nodes.
orderNo"LINEAR" (default) or "NONLINEAR" for second-order.
planeNo"3D" (default) or "XY". "XY" declares a planar model (every node at Z=0) and pins Z/RX/RY at EVERY node, which is what makes a planar model well-posed — an under-restrained one comes back as singular_model (converged:false), with no usable numbers.
membersYesJSON array of member rows: [start, end] / [start, end, "IPE300"] / [start, end, "IPE300", {options}]. Node numbers are 1-based; member ids are 1..N in this order. Options: rotation_angle (DEGREES — use 90 on the columns of an XY-plane frame or they resist sway with their WEAK axis), type (Truss/Tension/Compression/Cable/Rigid), hinge (start|end|both), classification.
materialNosteel_S355 (default), steel_S235, aluminium_6061 or concrete_C30.
sectionsNoJSON array of section definitions (same shape as create_section), referenced by name from the member rows.
supportsNoJSON object mapping a 1-based node number to "fixed" / "pinned" / "roller_x" / "roller_y" / "roller_z" / "free", or to an explicit DOF object {"X":"fixed","Y":"fixed","Z":"free","RX":"free","RY":"free","RZ":1.0e7} where a NUMBER means a spring stiffness. Required — a model with no supports is rejected.
self_weightNoAdd self-weight as its own load case and factor it into the combinations.
project_nameNoLabel for the model.
default_sectionNoSection for members that name none. Default IPE300.
load_combinationsNoJSON array referencing load cases by NAME: [{"name":"ULS","factors":{"G":1.35,"W":1.5},"limit_state":"ULS"}]. Omit for two automatic ones over every case: 1 "SLS characteristic (auto)" at 1.0 and 2 "ULS (auto)" at 1.35.
check_beamCheck a steel beam (EN 1993-1-1)
Read-only
Inspect

Check a steel beam to EN 1993-1-1 (Eurocode 3). Builds the beam + a ULS load combination + an EC3 member check over one member, solves it, and returns the governing utilization (<= 1.0 = OK) with the per-rule breakdown: bending, shear, combined N+M, and lateral-torsional buckling, plus a short advice string. Requires a named library section: European (IPE/HEA/HEB/HEM/UPE/RHS/SHS/CHS), UK (UB/UC/PFC) or US (W/HP/HSS/Pipe). Accepts common parameter aliases (span/length for span_m, load_kN_per_m/uniform_load for udl). Set restrained=true if the compression flange is continuously laterally restrained (skips the LTB check). On this hosted server the solve does NOT run here: the tool validates the model, parks it and returns an open_url that solves it in the user's browser, where the results are shown. Tell the user to open the link; for results inside the chat they can install the local FERS MCP server. Units: m, kN, kN/m.

ParametersJSON Schema
NameRequiredDescriptionDefault
udlNoUniformly distributed load in kN/m, downward
spanNoAlias for span_m (beam span in metres)
lengthNoAlias for span_m (beam span in metres)
span_mNoBeam span in metres (required — or use alias `span`/`length`)
sectionYesLibrary section name, e.g. 'IPE300', 'HEA200', 'UB 457x191x67', 'W10X22' (required). Carries the EC3 moduli.
supportNo'simply_supported' (default), 'cantilever', or 'fixed' (fixed–fixed)
materialNosteel_S235 (default), steel_S275, steel_S355 or steel_S460 (shorthand S235/S275/S355/S460 ok)
point_loadNoPoint load in kN, downward
restrainedNotrue if the compression flange is continuously laterally restrained (e.g. by decking or a slab) — the LTB (§6.3.2) check is then skipped. Default false.
uls_factorNoULS load factor applied to the load (default 1.35)
uniform_loadNoAlias for udl (uniformly distributed load in kN/m)
load_kN_per_mNoAlias for udl (uniformly distributed load in kN/m)
point_positionNoPoint-load position along the span, 0..1 (default mid-span; tip for a cantilever)
laterally_restrainedNoAlias for restrained
create_beamBuild a beam model
Read-onlyIdempotent
Inspect

Generate a solver-ready FERS model JSON for one beam. Use a named library section (IPE300, HEA200, 'RHS 100x50x5', 'UB 457x191x67', 'W10X22', …) or a solid rectangle. Returns model JSON to pass to solve_model. Accepts common parameter aliases (span/length for span_m, load/udl/uniform_load for load_kn; point_load implies load_type 'point'). Units: metres, kN, kN/m. The model carries two load combinations: 1 'SLS characteristic (auto)' at factor 1.0 and 2 'ULS (auto)' at 1.35, so ULS unity checks evaluate factored loads. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault
udlNoAlias for load_kn as a UDL in kN/m
loadNoAlias for load_kn (kN/m as a UDL, kN as a point load)
spanNoAlias for span_m (beam span in metres)
lengthNoAlias for span_m (beam span in metres)
span_mNoBeam span in metres (required — or use alias `span`/`length`)
load_knNoUDL in kN/m or point load in kN, downward (default 10)
sectionNoLibrary section name, e.g. 'IPE300', 'HEA200', 'RHS 100x50x5', 'UB 457x191x67', 'W10X22'. Overrides height_mm/width_mm.
supportNo'simply_supported' (default) or 'cantilever'
materialNosteel_S235 (default), steel_S275, steel_S355, steel_S460, aluminium_6061 or concrete_C30 (shorthand S235/S275/S355/S460 ok)
width_mmNoSection width b in mm (default 100)
height_mmNoRectangular section depth h in mm (default 200; ignored if `section` is set)
load_typeNo'udl' (default) or 'point'
point_loadNoPoint load in kN, downward (implies load_type 'point')
uniform_loadNoAlias for load_kn as a UDL in kN/m
load_positionNoAlias for load_position_frac (0..1 along the span)
point_positionNoAlias for load_position_frac (0..1 along the span)
load_position_fracNoPoint-load position along the span, 0..1 (default 0.5; 1.0 for cantilever)
create_frameBuild a portal frame
Read-onlyIdempotent
Inspect

Generate a solver-ready FERS model JSON for a 2-D rectangular portal frame (columns + beams). Returns model JSON to pass to solve_model. Units: metres, kN, kN/m. Columns are turned 90° so their depth (column_height_mm) resists sway in the frame plane. Load combinations as create_beam: 1 'SLS characteristic (auto)' at 1.0, 2 'ULS (auto)' at 1.35. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault
baseNo'fixed' (default) or 'pinned' column bases
baysNoNumber of bays (default 1)
storeysNoNumber of storeys (default 1)
materialNosteel_S355 (default), steel_S235, steel_S275, steel_S460, aluminium_6061 or concrete_C30
lateral_knNoHorizontal point load at the top-left corner, kN (default 0)
bay_width_mNoBay width in metres (default 5)
beam_width_mmNoBeam section width in mm (default 120)
beam_height_mmNoBeam section depth in mm (default 240)
column_width_mmNoColumn section width in mm (default 200)
storey_height_mNoStorey height in metres (default 3)
column_height_mmNoColumn section depth in mm (default 200)
roof_udl_kn_per_mNoGravity UDL on the top-storey beams, kN/m (default 10)
create_sectionAdd a cross-section
Read-only
Inspect

Add or replace a cross-section on an existing FERS model and optionally assign it to members. Takes the model JSON, mutates model.sections (and model.materials when a new preset is introduced), returns the model.

THREE WAYS TO DEFINE IT:

  1. LIBRARY — shape:"library" with library_name (or just name) set to a library profile — European IPE/HEA/HEB/HEM/UPE/RHS/SHS/CHS/L or UK UB/UC/PFC, e.g. "IPE300", "HEB240", "CHS 114.3x5", "RHS 100x50x5", "UB 457x191x67". This is the ONLY way to get exact rolled-profile properties (root fillets included) and it carries every EC3 modulus. Prefer it whenever a standard profile fits.

  2. PARAMETRIC — shape:"rect" (h_mm, b_mm), "circle" (d_mm), "chs" (d_mm, t_mm), "rhs"/"shs"/"box" (h_mm, b_mm, t_mm) or "i" (h_mm, b_mm, tf_mm, tw_mm), dimensions in MILLIMETRES. rect/circle/chs are exact and rhs area+inertias are exact (its Bredt torsion J is ~2% low), but the "i" generator assumes SHARP fillets: against a real rolled IPE300 it is 3.6% low on area, 4.3% low on i_z and 22% low on J. Use "i" for WELDED plate girders, not for rolled profiles.

  3. CUSTOM — shape:"custom" with your own SI numbers. area, i_y, i_z and j are all MANDATORY and strictly positive; a missing one is a hard parse error and a MISTYPED one is silently ignored (Section has no deny_unknown_fields), giving a wrong answer that still solves.

AXIS CONVENTION: local z is the STRONG axis. For depth h and width b, i_z = b·h³/12 (strong, resists gravity on a horizontal member) and i_y = h·b³/12 (weak). Getting these the wrong way round is the most common authoring error and the solver cannot detect it.

EC3 CHECKS NEED MORE THAN STIFFNESS. An Ec3Steel check on a section lacking wel_y/wpl_y/i_w does not fail — it returns utilization 0.0, status Green and an explanatory message, which reads as a clean pass. So also give wel_y, wel_z, wpl_y, wpl_z and i_w (warping constant, m⁶); the parametric shapes compute these for you. Optionally add ec3 {"section_class":1,"buckling_curve_y":"B","buckling_curve_z":"C","buckling_curve_lt":"B"} — curves A0/A/B/C/D (alpha 0.13/0.21/0.34/0.49/0.76); omitting the block silently uses curve b. Unlike the rest of the section, the ec3 block DOES reject unknown keys, so a typo there is a hard solve-time error.

ASSIGNMENT: apply_to "all" reassigns every member, a JSON array of member ids reassigns those, a classification string reassigns every member in that group. A section whose name already exists is overwritten IN PLACE, keeping its id and all existing member references.

ParametersJSON Schema
NameRequiredDescriptionDefault
jNoTorsion constant, m⁴.
ec3NoEN 1993-1-1 design parameters: {"section_class":1,"buckling_curve_y":"a","buckling_curve_z":"b","buckling_curve_lt":"c"}. Unlike the rest of Section, a typo here IS a hard error.
i_wNoWarping constant, m⁶.
i_yNoSecond moment about local y, m⁴.
i_zNoSecond moment about local z (STRONG axis), m⁴.
a_syNoShear area along local y, m².
a_szNoShear area along local z, m².
areaNoArea in m² (required for shape 'custom').
b_mmNoWidth in MILLIMETRES.
d_mmNoDiameter in MILLIMETRES (circle/chs).
h_mmNoDepth in MILLIMETRES.
nameYesName for the section in this model.
t_mmNoWall thickness in MILLIMETRES.
modelNoStringified FERS model JSON
shapeNolibrary (default when library_name is given) | rect | circle | chs | rhs | shs | box | i | custom. Prefer "library" for a standard profile: the parametric "i" generator has sharp fillets and is ~4% low on area and ~22% low on J versus a real rolled IPE300.
tf_mmNoFlange thickness in MILLIMETRES.
tw_mmNoWeb thickness in MILLIMETRES.
wel_yNoElastic modulus about y, m³.
wel_zNoElastic modulus about z, m³.
wpl_yNoPlastic modulus about y, m³.
wpl_zNoPlastic modulus about z, m³.
apply_toNo"all", a JSON array of member ids, or a classification string — assigns the section to those members.
materialNoMaterial preset for this section (see list_materials).
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
library_nameNoLibrary section name, e.g. IPE300 (see list_sections).
generate_load_combinations_ec0Generate EN 1990 combinations
Read-only
Inspect

Generate a complete EN 1990 (Eurocode 0) combination set from the model's load cases in one call, instead of adding them one at a time. Classify each load case as an action type — G permanent, Q imposed, S snow, W wind — and this emits ULS expression 6.10 (each variable action taken as leading in turn, with psi_0 on the accompanying ones) and the SLS characteristic combinations, including the favourable-permanent (gamma_G = 1.0) variants that govern wind uplift. Every generated combination carries a limit_state, so unity checks actually evaluate against them. Any load case you do not classify is guessed from its name. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelNoStringified FERS model JSON
actionsYesAction type per load case: {"1":"G","2":"S","3":"W"} or [{"load_case_id":1,"action":"G"}]. G = permanent, Q = imposed, S = snow, W = wind. Unclassified cases are guessed from their name.
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
include_slsNoEmit SLS characteristic combinations (default true).
include_ulsNoEmit ULS 6.10 combinations (default true).
replace_existingNoReplace analysis.load_combinations entirely instead of appending (default false).
include_favorableNoEmit the gamma_G = 1.0 favourable-permanent ULS variants, which govern uplift (default true).
get_check_schemaCode-check schema
Read-onlyIdempotent
Inspect

Get the canonical schema for authoring unity (code) checks: the UnityCheckDefinition schema and everything it references, read straight from the solver's OpenAPI, plus a worked EN 1993 example. Call this before add_unity_check. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

get_schemaLook up the model schema
Read-onlyIdempotent
Inspect

Look up the FERS model input contract — the authoritative JSON Schema the solver itself is generated from. Call with NO arguments to get an index of the useful roots (geometry, loads, analysis, checks) with a one-line description of each; then call again with a root to get that schema plus everything it references. Use this instead of guessing field names: the engine silently ignores unknown keys under analysis.*, so a typo becomes a wrong answer rather than an error. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault
rootNoSchema to expand, e.g. 'BucklingAnalysisSettings', 'MemberHinge', 'LoadCase', 'NodalSupport', 'Model'. Omit for the index.
get_sectionSection properties
Read-onlyIdempotent
Inspect

Get a named section's full properties in SI units (m, m², m⁴): area, second moments i_y/i_z, torsion constant j, warping constant i_w, shear areas, and the elastic/plastic moduli wel_y/wel_z/wpl_y/wpl_z that an EN 1993-1-1 check needs. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesSection name, e.g. 'IPE300', 'HEA 200', 'RHS 100x50x5'
get_templateGet a starter model
Read-onlyIdempotent
Inspect

Retrieve the full JSON of a template structural model by name. Use list_templates first to see available names.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesTemplate name (e.g. 'simple_shed', 'solar_rail')
get_usageCheck usage
Read-onlyIdempotent
Inspect

Check your FERS tier and how solves run on this server: member limits, licence state and where results come from. With sandbox_token: true, a Pro account also gets a solve token for 15 minutes, for a code sandbox that cannot reach ferscloud.com: set it as FERS_SOLVE_TOKEN there (or run_analysis(solve_token=...), FERS 0.2.0+) to solve beyond 100 members. It sits in the transcript, so ask only when a model needs it.

ParametersJSON Schema
NameRequiredDescriptionDefault
sandbox_tokenNotrue: also return a 15-minute Pro solve token for a code sandbox
list_materialsList materials
Read-onlyIdempotent
Inspect

List the named material presets the model builders accept, with their E, G, density and yield stress in SI units. The solver itself accepts ANY isotropic material — see get_schema('Material') to author one inline. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

list_modelsList saved models
Read-onlyIdempotent
Inspect

List your saved models (id, name, description, last-updated time).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

list_sectionsList steel sections
Read-onlyIdempotent
Inspect

List the named steel sections FERS knows: European (IPE, HEA, HEB, HEM, UPE, RHS, SHS, CHS, L), UK (UB, UC, PFC) and US (W, HP, HSS, Pipe). check_beam and create_beam require one of these names, so call this rather than guessing. Returns names only — use get_section for a section's properties. Free.

ParametersJSON Schema
NameRequiredDescriptionDefault
familyNoFilter by family/prefix, e.g. 'IPE', 'HEA', 'RHS'. Case-insensitive. Omit for all families.
list_templatesList starter models
Read-onlyIdempotent
Inspect

List all available template structural models. Returns name and description for each template.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

load_modelLoad a saved model
Read-onlyIdempotent
Inspect

Load one of your saved models' full JSON by id (owner only).

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesSaved model id
run_unity_checksRun code checks
Read-only
Inspect

Solve a model and return its code-check (unity-check) results: per-entity utilizations, status, and the calculation trace behind each rule. The model's analysis.unity_checks must already be defined (see add_unity_check). On this hosted server the solve does NOT run here: the tool validates the model, parks it and returns an open_url that solves it in the user's browser, where the results are shown. Tell the user to open the link; for results inside the chat they can install the local FERS MCP server. Set include_report=true to also get the rendered HTML hand-calc report.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelNoStringified FERS model JSON that includes analysis.unity_checks
detailNoHow much result data to return. 'summary' (peak forces, displacements and reactions with where they occur — smallest, usually enough), 'standard' (default: envelopes + node displacements + reactions), or 'full' (adds section forces and the complete internal-force series; can be hundreds of thousands of tokens on a real model).
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
result_filterNoAdvanced: emit only these result blocks, overriding `detail`. Any of: local_envelopes, global_envelopes, local_end_forces, global_end_forces, section_forces, internal_force_series, local_displacements, node_displacements, reactions. An empty list is a maximal strip. Unity checks, summaries and diagnostics are never filtered.
include_reportNoEmbed the rendered HTML hand-calc report in the response. Default false — it is large. Use the free render_report tool on a saved result instead.
idempotency_keyNoOptional. Reuse when retrying so the retry is recognised as the same request.
save_modelSave a model to your accountInspect

Save a model to your FersCloud account (requires a Pro subscription; free accounts use local JSON export/import instead). Solver results are never stored. Returns the model id.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesA name for the saved model
modelNoStringified FERS model JSON
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
descriptionNoOptional description
set_analysisConfigure the analysis
Read-onlyIdempotent
Inspect

Configure HOW a model is solved, and switch on the analyses the engine supports beyond plain statics. Writes analysis.options (first- vs second-order, P-Delta, self-weight, gravity, tolerances) and the three optional blocks: analysis.modal (natural frequencies), analysis.buckling (linear eigenvalue alpha_cr) and analysis.seismic (EN 1998-1 response spectrum / lateral force). Pass only what you want to change — each sub-object is merged into the existing block, so load cases, combinations and unity checks are preserved. Returns the updated model for solve_model. KEY FACTS: models from create_beam, create_frame and build_model are LINEAR (the engine itself has no default and requires order; the Python SDK defaults to NONLINEAR), so set order:"NONLINEAR" for second-order/P-Delta. Buckling needs exactly one reference form (reference / references / all_combinations) and reports alpha_cr as results.buckling.modes[].critical_load_factor. Seismic directions are GLOBAL AXES and these models are Y-up, so the two horizontal directions are usually X and Z. Unknown field names are REJECTED here on purpose: the solver would accept them, ignore them, and silently give you a default. Call get_schema("BucklingAnalysisSettings") etc. for the exact fields.

ParametersJSON Schema
NameRequiredDescriptionDefault
clearNoOptional JSON array of blocks to delete first, e.g. ["modal","buckling"].
modalNoModalAnalysisSettings, e.g. {"num_modes":6,"mass_formulation":"CONSISTENT"}. Pass "null" to remove the block.
modelNoStringified FERS model JSON to update
optionsNoAnalysisOptions fields to merge, as a JSON object. e.g. {"order":"NONLINEAR","nonlinear_method":"P_DELTA","enable_self_weight":true}. See get_schema("AnalysisOptions").
seismicNoSeismicAnalysisSettings, e.g. {"method":"MODAL_RESPONSE_SPECTRUM","num_modes":30,"directions":["X","Z"],"spectrum_x":{"EurocodeParametric":{"ag":2.45,"ground_type":"C","spectrum_type":"TYPE1","q":3.0,"beta":0.2}},"mass_sources":[{"load_case_id":1,"psi":1.0}]}. Pass "null" to remove.
bucklingNoBucklingAnalysisSettings, e.g. {"num_modes":3,"reference":{"LoadCombination":1},"member_effective_lengths":true}. Needs exactly one of reference / references / all_combinations. Pass "null" to remove.
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
set_memberSet member behaviour
Read-only
Inspect

Set structural behaviour on one or more existing members: element type, end releases (hinges), rigid end offsets, cross-section rotation/mirroring and cable parameters. Mutates model.members (and model.member_hinges when a release is authored) and returns the model.

member_type: Normal (full 6-DOF beam), Truss (axial only — carries exactly zero moment), Tension (tie that drops out in compression), Compression (strut that drops out in tension), Rigid (near-rigid link; produces NO entry in results.member_results at all) or Cable (analytic elastic catenary; forces the whole solve onto the nonlinear path and only sags when analysis.options.enable_self_weight is true). Tension/Compression drop-out is governed by analysis.options.axial_slack in FORCE units — a member switches off when its axial force passes 0.5*axial_slack on the wrong side — so this tool lowers axial_slack to 1e-3 when it writes one (set keep_axial_slack to skip). With a coarse axial_slack the member never drops out and quietly behaves like a plain Truss. To build a truss use member_type Truss: two double-hinged Normal members meeting at a free node give a singular stiffness matrix.

END RELEASES ARE A TRISTATE and that is the whole point: for each release DOF, null (or simply not naming it) = RIGID, 0.0 = FULLY RELEASED, and a positive number = a spring of that stiffness (force/length for vx/vy/vz, force*length/rad for mx/my/mz/warp). Release DOFs are in the MEMBER LOCAL frame. Verified on an encastre beam under UDL: mz null gives support moment wL^2/12 and midspan wL^2/24; mz 0.0 gives 0 and wL^2/8, i.e. exactly simply supported. Each release object fully defines that end's hinge — DOFs you do not name are written as rigid — and passing "rigid" clears the release. A rotational release is rejected when it would leave a node with NO rotational stiffness at all, because that is a hard "Stiffness matrix is singular or near-singular": either a dead-end node (no other member frames in and the support does not restrain it) or a node where every member meeting there releases the same DOF. Note the asymmetry the check has to respect — an absent RX/RY/RZ on a support is read as FIXED, but an absent warping_condition really is free, so a plain pinned support does NOT hold a warp release. Releasing the same vx, vy, vz or mx at BOTH ends of one member is refused outright: that one is fatal at the element level whatever the model looks like ("apply_end_releases_to_local_beam_k: interface block is singular"), while my/mz/warp at both ends is just an ordinary pin-pin beam.

A release object may also carry rotation_axes: "Global" or {"User":{"x":[...],"y":[...]}} takes mx/my/mz, their curves and their moment-rotation diagrams about those axes instead of the member's own — a beam at an angle in plan, pinned about the axis of the girder it hangs from, needs {"mx":0.0,"rotation_axes":"Global"}. A user frame's first axis runs along x and its second along y made square to it. Translations stay member-local, member results stay in member axes, and the axes stay fixed in space on the corotational path. A model whose hinges release in other axes is written with schema_version 3 (engine 0.2.68), so an older engine refuses it instead of solving the release about the member's axes.

MemberHinge also carries seven capacity fields (max_tension_*, max_moment_*, max_bimoment_warp). They are accepted by the schema and carried through the model but are NEVER ENFORCED by the solver: nothing limits a hinge force by them and they trigger no nonlinearity. Do not author "yielding" hinges with them — this tool does not write them.

Offsets (start_offset/end_offset) are rigid arms between the node and the member work point in the GLOBAL frame, in model length units. rotation_angle_deg rolls the cross-section about the member axis in DEGREES, not radians: on a vertical column FERS builds the local frame from global Z, so sway along global X is resisted by the WEAK axis i_y unless you rotate 90 degrees (verified 13.8x difference on a cantilever column, with no warning from the solver). pretension is valid ONLY on Cable/Tension/Compression (a hard validation error elsewhere) and pins a tie permanently active; unstretched_length only does anything on a Cable and is silently ignored everywhere else. Sign convention for reading results back: local_start_forces.fx is COMPRESSION-POSITIVE.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelNoStringified FERS model JSON
mirrorNoMirror the cross-section.
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
end_offsetNoSame, at the end.
member_idsYesJSON array of member ids, e.g. [1,2,3], or the string "all".
pretensionNoCable / Tension / Compression members only.
end_releaseNoSame, at the END node.
member_typeNoNormal | Truss (pin-jointed, axial only) | Tension (drops out in compression) | Compression | Rigid | Cable.
start_offsetNoRigid arm at the start, GLOBAL frame, model length units: {"X":0,"Y":0.2,"Z":0}. null removes it.
start_releaseNoEnd release at the START node, in the MEMBER LOCAL frame: {"mz":0.0} releases the major-axis moment. CAREFUL: an unnamed DOF or null means RIGID, 0.0 means FULLY RELEASED, and a positive number is a rotational spring (N·m/rad). Add "rotation_axes":"Global" (or {"User":{"x":[...],"y":[...]}}) to take mx/my/mz about other axes. Use "rigid" to clear.
keep_axial_slackNoLeave analysis.options.axial_slack untouched.
rotation_angle_degNoRoll the cross-section about the member axis, in DEGREES. Use 90 on the columns of an XY-plane frame.
unstretched_lengthNoCable members only.
set_member_designSet buckling / design data
Read-only
Inspect

Set the design (code-check) data that lives on a MemberSet — buckling restraints, buckling lengths, LTB length, effective-length factors — plus the per-member chi override.

THESE FIELDS CHANGE NOTHING IN THE STATICS. Displacements, reactions and member forces come back bit-identical; the values only feed the EN 1993-1-1 unity-check evaluator. If the model has no Ec3Steel unity check and a matching load combination you will see no effect at all anywhere in the results, so add one with add_unity_check first.

A MemberSet is one physical beam: the ordered chain of collinear FE members that make it up. Design lengths resolve per axis with this precedence: explicit buckling_length_* > effective_length_factor_* > buckling_restraints spacing > member length. WATCH THE TWO BASELINES — an explicit length and a restraint spacing are measured along the WHOLE chain, but effective_length_factor_y/z multiplies the length of the INDIVIDUAL FE member. Verified on a 6 m column split into 4 x 1.5 m members: buckling_length = 6.0 reproduces the default exactly, buckling_length = 12.0 quarters N_cr, but effective_length_factor = 2.0 gives L_cr = 3.0 m (2 x 1.5 m), not 12 m.

buckling_restraints are named by the member LOCAL axis they hold (restrains_local_y / restrains_local_z / restrains_torsion), not strong/weak — which one is strong depends on the section orientation and rotation_angle. A restraint's node_id must actually lie on one of the set's own members or the whole model fails validation.

chi is a per-MEMBER override of the EN 1993-1-1 flexural-buckling reduction factor. It replaces the section-curve chi for BOTH flexural axes (the slenderness stays physical) and is written onto every member of the targeted sets; pass "clear" to remove it.

ParametersJSON Schema
NameRequiredDescriptionDefault
chiNoEN 1993-1-1 reduction factor override in (0,1], written onto every member of the set.
modelNoStringified FERS model JSON
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
ltb_lengthNoLateral-torsional buckling length.
classificationNoAlternative selector: exact match on the set's classification.
member_set_idsYesJSON array of member-set ids, or "all". Give this or `classification`.
buckling_length_tNoTorsional buckling length.
buckling_length_yNoL_cr about local y, in model length units, measured along the whole member chain.
buckling_length_zNoL_cr about local z.
set_classificationNoRename the set's classification.
buckling_restraintsNo[{"node_id":3,"restrains_local_y":true,"restrains_local_z":true,"restrains_torsion":true}]. Replaces the set's list; nodes must lie on the set's own members. [] clears them.
effective_length_factor_yNoK about y — multiplies the INDIVIDUAL element's length, not the chain's.
effective_length_factor_zNoK about z, same caveat.
set_scissor_hingeLet a continuous beam turn on what it crosses
Read-only
Inspect

Let a continuous beam turn or slide on the members it crosses (a scissor hinge, engine 0.2.68), with no link member or extra node: a rail resting on beams, a bracing pair crossing at a bolt. Name the beam by member_ids (or an existing member_set_id) and give the releases. Returns the model.

releases is an object over tx, ty, tz (translations) and rx, ry, rz (rotations): 0.0 FREES that axis, a positive number is a spring between the beam and the node (force/length for t*, forcelength/rad for r), and an axis you do not name is HELD — the same tristate as a member hinge. {"rz":0.0} lets a beam in the XY plane turn on what it crosses; {"tx":0.0} lets it slide along X.

The hinge goes on a MEMBER SET and applies wherever one of the set's members meets a member OUTSIDE the set (or a plate). Inside the set the members stay joined to each other, so the beam stays continuous. A set holding every member meets nothing and the solver refuses it, so when no set holds exactly these members they leave their sets for a new one; info lists the sets they were taken from. at_nodes limits the hinge to those nodes of the beam (a rail that slides over its first post only); omit it for every crossing.

axes: "Global" (the default) or {"User":{"x":[...],"y":[...]}} for a rack turned in plan — the first axis runs along x, the second along y made square to it. "Local" is refused: the set's members need not share one.

Supports and nodal loads at a released node act on the members outside the set, and a node's reported displacement is theirs; the beam's own motion there is in its members' local end displacements. The solver refuses a member point load or moment exactly at a released end of the beam. In second order, a model with scissor hinges takes the corotational correction only when analysis.options.nonlinear_method is COROTATIONAL. The model is written with schema_version 3, so an engine older than 0.2.68 refuses it instead of solving every crossing rigid. scissor_hinge_id reuses (and with releases or axes, rewrites) one definition for several beams; clear:true takes the hinge off the beam's set.

ParametersJSON Schema
NameRequiredDescriptionDefault
axesNo"Global" (default) or {"User":{"x":[1,0,0],"y":[0,1,0]}} for a frame turned in plan. "Local" is refused.
clearNoTake the scissor hinge off the beam's member set.
modelNoStringified FERS model JSON
at_nodesNoJSON array of the beam's node ids where the hinge applies; omit for every node where the beam meets another member.
releasesNoAxes to release: {"rz":0.0} frees rotation about global Z, {"tx":0.0} lets the beam slide along X, a positive number is a spring (force/length for tx/ty/tz, force*length/rad for rx/ry/rz). An axis not named is HELD.
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
member_idsNoJSON array of the continuous beam's member ids, e.g. [4,5,6]. They get a member set of their own unless one already holds exactly them.
member_set_idNoInstead of member_ids: put the hinge on this existing member set.
scissor_hinge_idNoReuse this existing scissor hinge definition (and rewrite it when releases or axes are given).
set_supportSet a support condition
Read-only
Inspect

Write a nodal support (boundary condition) and point one or more nodes at it: creates or overwrites an entry in model.nodal_supports and sets node.nodal_support on every node you name. Returns the updated model — feed it to solve_model.

All 7 DOFs are set independently, in the GLOBAL frame: X/Y/Z (translations), RX/RY/RZ (rotations about the global axes) and warping (the 7th DOF, only live when analysis.options.include_warping is true and the section has i_w). Condition types are case-sensitive: Fixed (rigid), Free (no restraint), Spring (needs the matching _stiffness > 0 — N/m for translations, N*m/rad for rotations), PositiveOnly (one-way: may only push in the +global direction, i.e. lift-off) and NegativeOnly (the mirror image). A one-way condition may also carry a _stiffness, which from engine 0.2.65 is the bedding stiffness it acts through while in contact — a base plate on a slab is not infinitely stiff. Released, it is free regardless. On 0.2.64 and earlier that number was accepted, range-checked and then silently discarded, so the model solved as rigid contact.

THERE IS NO "FREE BY OMISSION". Once a node references a support, any DOF you leave out is treated by the solver as FULLY FIXED — a support of literally {"id":1} is an encastre, and the OpenAPI text claiming an absent field means free is wrong. This tool therefore always writes all six translation/rotation conditions explicitly, and anything you do not name is written as Free. Use preset to fill them in one go: fixed (encastre), pinned (X/Y/Z fixed, rotations free), free, roller_x/roller_y/roller_z (ONLY that translation fixed, everything else free), ground_contact_y (X/Z fixed, Y PositiveOnly, rotations free — a base plate that can lift off). Per-DOF fields are applied on top of the preset. Warping is the one exception: leaving it out really does mean free.

ONE-WAY SUPPORTS have a prerequisite this tool checks for you: analysis.options.rigid_strategy must be RigidMember (LinearMpc is a hard validation error). Tension/Compression members are fine alongside them from engine 0.2.65 -- before that the combination was refused at validation, so if you are reading advice written against an older engine, that restriction is gone. There is also a SILENT prerequisite — the release tolerance is 0.5*axial_slack in force units, so a coarse axial_slack leaves the DOF engaged while still reporting its reaction as 0, and the printed reactions stop summing to the applied load. This tool lowers axial_slack to 1e-3 when it writes a one-way condition (set keep_axial_slack to skip that). Beware that a support which lifts off can leave the structure unrestrained, and that a one-way support can break an eigen solve if the model also has a modal or buckling block.

Reactions use ONE SIGN CONVENTION for every support type from engine 0.2.60: each row is the force the support applies to the structure, so reactions can be summed against the applied load without checking which kind of support produced each one. (Up to 0.2.59 a Spring DOF reported the spring force k*u, the negative of what a Fixed DOF reported for the same physical situation. If you are reading results solved on an older engine, that flip is still in them.) A stiffness curve (stiffness_curves) makes the spring load-dependent, forces the DOF to Spring and requires a NONLINEAR analysis order — and note its driver is the EXTERNAL nodal load at that node, not the reaction, so a base-plate curve with no direct nodal load degenerates to the first point's stiffness.

ParametersJSON Schema
NameRequiredDescriptionDefault
XNoFixed | Free | Spring | PositiveOnly | NegativeOnly (global X translation).
YNoSame, global Y (vertical in these models).
ZNoSame, global Z.
RXNoSame, rotation about global X.
RYNoSame, rotation about global Y.
RZNoSame, rotation about global Z.
modelNoStringified FERS model JSON
presetNofixed | pinned | free | roller_x | roller_y | roller_z | ground_contact_y. Applied first; the per-DOF fields below then override it.
warpingNoWarping DOF condition.
node_idsYesJSON array of node ids to support, e.g. [1,2], or the string "all". They all share one support definition.
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
support_idNoOverwrite this existing nodal_supports entry; omit to allocate a new one.
X_stiffnessNoN/m — required when X is Spring.
Y_stiffnessNoN/m — required when Y is Spring.
Z_stiffnessNoN/m — required when Z is Spring.
RX_stiffnessNoN·m/rad — required when RX is Spring.
RY_stiffnessNoN·m/rad — required when RY is Spring.
RZ_stiffnessNoN·m/rad — required when RZ is Spring.
classificationNoFree-text label.
keep_axial_slackNoLeave analysis.options.axial_slack untouched when writing a one-way support.
stiffness_curvesNoNonlinear support springs: {"Y":{"depends_on":"Fy","points":[[0,1e5],[10000,1e6]]}}. Forces that DOF to Spring and the analysis to NONLINEAR.
warping_stiffnessNoRequired when warping is Spring.
solve_modelSolve a structural model
Read-only
Inspect

Run the FERS FEM solver on a structural model. Input is the full model JSON (as a string). Returns displacements, internal forces and reactions. On this hosted server the solve does NOT run here: the tool validates the model, parks it and returns an open_url that solves it in the user's browser, where the results are shown. Tell the user to open the link; for results inside the chat they can install the local FERS MCP server. Results are returned at detail: standard by default — ask for 'summary' when you only need peak values, and 'full' only when you genuinely need every sample point.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelNoStringified JSON of the FERS structural model
detailNoHow much result data to return. 'summary' (peak forces, displacements and reactions with where they occur — smallest, usually enough), 'standard' (default: envelopes + node displacements + reactions), or 'full' (adds section forces and the complete internal-force series; can be hundreds of thousands of tokens on a real model).
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.
result_filterNoAdvanced: emit only these result blocks, overriding `detail`. Any of: local_envelopes, global_envelopes, local_end_forces, global_end_forces, section_forces, internal_force_series, local_displacements, node_displacements, reactions. An empty list is a maximal strip. Unity checks, summaries and diagnostics are never filtered.
include_reportNoEmbed the rendered HTML hand-calc report in the response. Default false — it is large. Use the free render_report tool on a saved result instead.
idempotency_keyNoOptional. Reuse the same value when retrying a solve so the retry is recognised as the same request.
stash_modelPark a model, get a handleInspect

Park a model and get back a short handle (model_ref). Every authoring tool, and solve_model, accepts model_ref instead of model — so a multi-step build stops shipping the whole document through your context on every call, which on a real model is thousands of tokens per step. Tools called with a handle return the same handle, so the chain stays cheap. Handles are private to you and expire after 24 hours; they are NOT saved models and never appear in list_models (use save_model for that). Free.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoOptional label, purely to help you keep several drafts apart.
modelYesStringified FERS model JSON to park
summarize_plate_resultsSummarize plate results
Read-onlyIdempotent
Inspect

Reduce a solved FERS document to the plate numbers an engineer actually reads, and derive extreme-fibre stresses. READ-ONLY: it returns a summary, not a model.

You need this because plate results cannot be read back through the model. The mesh is generated on an internal working copy, so the returned document has model.plate_elements = [] and plate_surfaces[].generated_plate_element_ids = [], and the mesh node ids in displacement_nodes have no coordinates anywhere in model.nodes. The only georeferenced plate output is results.<case|combination>.plate_results, keyed by element id, carrying centroid {X,Y,Z}, centroid_displacement_global/local and the stress resultants.

UNITS AND CONVENTION, from the engine's own denormalisation: nx, ny, nxy, qx, qy are membrane forces and transverse shears per unit width, in force/length (N/m); mx, my, mxy are moments per unit width, in force (N.m/m, numerically N). mx is the moment PRODUCING sigma_x (conjugate to curvature about local y), not "the moment about x" — on a rectangular slab spanning the short way with local_x along the long side, the large resultant is my. The sign of mx/my/mxy follows the element normal, which follows the boundary/connectivity ordering, so reversing it flips all three; von Mises and |principal| are immune. qx and qy are identically ZERO for Kirchhoff/DKT plates by construction, so non-zero transverse shear is itself proof the Mindlin element was used. results..summary.total_plate_forces is a COUNT of plate results, not a force.

Give thickness and the tool derives the extreme-fibre stresses exactly as the engine's own plate unity check does: sigma_x = nx/t +/- 6mx/t^2, sigma_y = ny/t +/- 6my/t^2, tau_xy = nxy/t +/- 6mxy/t^2, evaluated at both fibres with the governing (larger von Mises) one reported, then vonMises = sqrt(sx^2 - sx.sy + sy^2 + 3txy^2) and the in-plane principals. Add yield_stress for a utilisation.

ParametersJSON Schema
NameRequiredDescriptionDefault
top_nNoHow many governing elements to list per quantity (default 5).
resultsYesA solved FERS document (or just its `results` block) from solve_model.
thicknessNoPlate thickness in metres — needed to turn moments and forces into extreme-fibre stresses.
quantitiesNoJSON array from: deflection, nx, ny, nxy, mx, my, mxy, qx, qy, von_mises, sigma_x, sigma_y, tau_xy, principal_max, principal_min.
yield_stressNoYield stress in Pa — adds a von Mises utilization if given.
case_or_combinationNoName of one load case or combination. Omit for all of them.
validate_modelValidate a model
Read-onlyIdempotent
Inspect

Check a FERS model against the solver's own schema WITHOUT solving it — free. Reports field-level errors (missing or wrong-typed fields, invalid enum values), broken id references (a member pointing at a node that does not exist, a load on a deleted member, duplicate ids), and warns about unknown fields under analysis.* — which matter because the engine silently ignores those and gives you a default instead of an error. Always run this before solve_model on a hand-authored model.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelNoStringified JSON of the FERS structural model to validate
model_refNoHandle from stash_model, used INSTEAD of `model`. Avoids sending the whole document on every step; the tool returns the same handle back.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 35 tool updates
    • First observedadd_imperfection_case
    • First observedadd_load
    • First observedadd_load_case
    • First observedadd_load_combination
    • First observedadd_plate_grid_elements
    • First observedadd_plate_opening
    • First observedadd_plate_surface
    • First observedadd_unity_check
    • First observedbuild_model
    • First observedcheck_beam
    • First observedcreate_beam
    • First observedcreate_frame
    • First observedcreate_section
    • First observedgenerate_load_combinations_ec0
    • First observedget_check_schema
    • First observedget_schema
    • First observedget_section
    • First observedget_template
    • First observedget_usage
    • First observedlist_materials
    • First observedlist_models
    • First observedlist_sections
    • First observedlist_templates
    • First observedload_model
    • First observedrun_unity_checks
    • First observedsave_model
    • First observedset_analysis
    • First observedset_member
    • First observedset_member_design
    • First observedset_scissor_hinge
    • First observedset_support
    • First observedsolve_model
    • First observedstash_model
    • First observedsummarize_plate_results
    • First observedvalidate_model

Publisher details

Operator
FERS Cloud · Publisher source
Operator website
https://ferscloud.com
Vendor relationship
First-party
Trust center
Not available
Restrictions
Free tier: non-commercial use only, models up to 100 members. Commercial use needs a paid FERS Cloud plan (Pro, up to 10,000 members). The hosted server returns solves as a browser link; for results inside the chat use the local server (npx -y @ferscloud/fers-mcp). · Publisher source

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    A
    maintenance
    An agentic MCP server for CSI ETABS v22+ that enables AI agents to model, load, analyze, design, and inspect building structures through 60 curated engineering tools and live .NET reflection of the full 1,293-method OAPI. Includes offscreen 3D rendering of deformed shapes and D/C ratios, interactive database table editing, and background analysis execution.
    71
    20
    Apache 2.0
  • A
    license
    A
    quality
    D
    maintenance
    Enables AI agents to interact with Bentley STAAD.Pro models for tasks like load case definition, data extraction, and property setting, running locally with multi-instance support and no cloud dependency.
    5
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    The official MCP interface for AgentFEM, giving AI agents seven typed tools to create, validate, run, inspect, and verify finite-element simulations while preserving scientific evidence.
    7
    39 PyPI
    Apache 2.0
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to perform structural engineering analysis using the Pynite finite element library, including model creation, element definition, analysis execution, and result visualization through natural language.
    -
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.