MIDAS NX MCP Connector
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MIDAS NX MCP ConnectorRun the analysis and show me the reaction forces at supports"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MIDAS NX MCP Connector
Zero-dependency (stdlib only) MCP server for MIDAS Gen / Civil NX. Exposes the MIDAS NX Open API to an LLM host through six tools, backed by an offline-generated Endpoint Registry and safety guards that encode the hard-won live-testing pitfalls.
LLM host <--JSON-RPC/stdio--> midas-mcp <--HTTP + MAPI-Key--> MIDAS Gen/Civil NXRequirements
Python 3.9+ (tested on 3.14). No third-party packages.
A running MIDAS Gen NX / Civil NX with the Open API enabled and a MAPI-Key.
Related MCP server: midas-bridge-mcp
Quick start
Credentials live in a JSON config file, grouped into per-product profiles, so MIDAS Gen NX, Civil NX and a cloud endpoint each keep their own URL + key:
# 1) create config.json next to the project (it is gitignored)
cp config.example.json config.json # then fill in the keys{
"active_profile": "MIDAS GEN NX",
"profiles": {
"MIDAS GEN NX": { "base_url": "http://localhost:3030/gen", "mapi_key": "<key>" },
"MIDAS CIVIL NX": { "base_url": "http://localhost:3030/civil", "mapi_key": "<key>" }
}
}python -m midas_mcp # stdio, active profile
python -m midas_mcp --profile "MIDAS CIVIL NX" # switch product
python -m midas_mcp --list-profiles # what is configured
python -m midas_mcp --show-config # resolved settings (key redacted)
python -m midas_mcp --transport http --port 8100 # Streamable HTTP on 127.0.0.1config.json is discovered automatically (cwd, then project root, then the
user config dir); --config <path> or MIDAS_MCP_CONFIG overrides it.
Environment variables still win over the file, so a one-off or CI run needs no
edits: MIDAS_MAPI_KEY="ci key" python -m midas_mcp --profile "MIDAS CIVIL NX".
The key is never accepted on the command line.
One-shot run
A steel portal frame end to end — build, analyse, self-verify against load equilibrium, print the report — is one command or one tool call:
python -m midas_mcp.frame --spec specs/portal-frame.json # the report
python -m midas_mcp.frame --spec specs/portal-frame.json --json # + the verdictBoth commands need midas_mcp importable in that shell: either pip install -e .
once, or prefix the command with PYTHONPATH=src (set PYTHONPATH=src in
PowerShell). midas_frame_run exports the child's PYTHONPATH itself, so the
tool path works without an install.
The MCP tool is midas_frame_run, e.g. {"spec_path": "specs/portal-frame.json"}.
Both paths run the same driver, so they cannot drift apart.
Varying the frame needs no second spec file — pass the keys to override inline, and the report describes the frame that was actually built:
{"spec_path": "specs/portal-frame.json",
"spec": {"span": 24.0, "eave": 7.0, "ridge": 9.5,
"sections": {"COLUMN": {"id": 1, "name": "COLUMN_H450X200X9X14",
"vsize": [0.45, 0.2, 0.009, 0.014, 0, 0, 0, 0]}}},
"clear": true}Verified live: that call answers ok: true, 18/18 steps, 13/13 criteria, 4/4
balance checks, and a report whose model table reads 24 m / 7 m / 9.5 m with the
new section names — none of the 20 m frame's numbers survive into it.
specs/portal-frame.json is the validated 20 m span / 6 m eave / 8 m ridge
frame. Every key is optional — an omitted key keeps the validated value — and
an unknown key is refused by name, never silently ignored. A run refuses to
build on a non-empty MIDAS document unless --clear is passed, so a report
never mixes two models.
The verdict is one JSON line: {ok, analysis, criteria, verifications, steps, failed, note, report}. ok is deliberately hard to earn — it needs
analysis == "SUCCESS", a non-empty criterion list, no failed criterion, and
self-consistency checks that actually ran and passed; exit code 0 means the same
thing. Everything the report says about the run — the tool list, the artifact
directory — is read back from the run itself rather than hardcoded, and a
refused run hands back no report at all.
The tool wraps that verdict rather than returning it bare:
{ok, endpoint, method, status, category, message, report, data}, where data
is the verdict above and report is the rendered report. A refusal answers
category: "MODEL_NOT_EMPTY" with an empty report, so a caller that reads only
the top level still cannot mistake it for a run.
Verified live on Gen NX 2027: 18/18 steps, 13/13 criteria, 4/4 self-consistency
checks, ANALYSIS = SUCCESS, exit 0, about five minutes.
Long runs: progress, and not waiting for them
The run above answers only when it is finished, which is three to six minutes. Two ways out, and they compose:
Progress. Pass
params._meta.progressTokenon a blockingtools/calland the server emits onenotifications/progressper driver step as it is printed18 for a complete run. Verified live: 18 notifications,
progress1..18, the right token, all before the response. A background call gets none: MCP progress belongs to a request that is still in flight, and that one is answered at once. Over--transport httpthere is no progress channel at all, and the server's own instructions say so rather than advertising it.
Polling.
{"background": true}returns{job_id, running, status: 202}straight away;midas_frame_status {"job_id": ...}then reports the steps the driver has printed so far, and the poll that findsrunning: falsereturns the same envelope as the blocking call, report included. One frame run at a time: a second run, or any other write, is refused while one is in flight, because the driver builds in the live document. Reads stay allowed.
Verified live: the job id came back in 0.0 s; the polls showed steps_done
0 → 5 → 7 → 11 → 12 while the run was in flight; the finished poll carried the
9541-character report, 13/13 criteria and 4/4 self-checks with
ANALYSIS = SUCCESS; and the blocking call's 18 progress notifications arrived
before its response. A job does not survive a server restart, and
midas_frame_status says so rather than pretending the id was never valid.
The six tools
Tool | Purpose | Maps to |
| project control + analysis |
|
| read data; search endpoints; schema introspection |
|
| create/update data; run POST actions |
|
| delete specific ids |
|
| one-shot steel portal frame: spec → model → analysis → verified report |
|
| progress of a | the run's own stdout, kept in the server |
Every MIDAS endpoint is addressed by a registry key (DB:NODE,
POST:TABLE:REACTIONG, DESIGN:RC:KDS-41-20-2022:DCO), never by a raw URL the
model supplies. The registry carries {uri, methods, wrapper, selector, notes}
per endpoint (see registry/registry.json, ~590 endpoints).
Guard rails (validated on live Gen NX)
Crash guard. Boundary/load records keyed on node/element ids (
CONS,CNLD,BMLD,NSPR,SSPS,ELNK,RIGD, …) are refused locally unless the referenced id exists. Assigning a missing id crashes MIDAS (everything after it returns 502); we never let that happen.Delete safety. An empty
target_idsis rejected — it never means "delete all". Bulk delete requiresdelete_all=trueandMIDAS_MCP_ALLOW_BULK_DELETE=1.Payload corrections.
EIGV.TYPEis forced toLANCZOS;MATL PARAM.P_TYPEis forced to2(P_TYPE 1 silently zeroes POISN/THERMAL/DEN/MASS); file paths are converted to Windows backslashes (EXPORT_PATH, which fails on forward slashes).Retry policy. Only idempotent
GETretries transient statuses (502/503/504).ANAL, DELETE, IMPORT/EXPORT and design actions are never auto-retried.Success by body, not status. MIDAS returns
Wrong Fielderror bodies with an HTTP 2xx; the connector classifies success from the body.No wrapper injection.
Assign/Argumentare chosen server-side from the registry; the model cannot twist the request shape.
MIDAS knowledge surfaced as resources
midas://knowledge/pitfalls— the validated pitfall tablemidas://knowledge/routing— tool/ordering rules (also inlined intoinitialize.instructions)midas://registry/index— full endpoint key list by namespacemidas://recipes/one-shot— read this first for a steel portal frame; thenmidas://recipes/modal-rs,midas://recipes/steel-frame,midas://recipes/load-balance,midas://recipes/rc-section— end-to-end worked sequences.load-balanceis the equilibrium proof to run before quoting any extreme value.
Development
# offline unit + protocol conformance tests (no network)
python -m unittest discover -s tests -p 'test_*.py'
# live tests against a running MIDAS (reads config.json; see Configuration below)
MIDAS_MCP_LIVE=1 python -m unittest tests.test_live_gen -v
# regenerate the registry from the vendored docs (docs/manual, pinned commit)
python build/build_registry.py
# probe every GET endpoint in the registry against the live MIDAS
python build/verify_live.py # config.json is auto-discovered
python build/verify_live.py --profile "MIDAS CIVIL NX"The registry is generated from two sources: the v2 dev pack
(api_chapters/*.md, uniform Endpoint Registry tables) and the vendored
upstream manual (docs/manual/*.md, 505 endpoint sections across nine
formats). Upstream wins on URI/methods; local wins on key naming/wrapper.
build/build_registry.py --check fails if the documented chapter counts drift.
Live probe results are folded back into each endpoint's notes so callers know
what this Gen build actually serves (e.g. /db/RCHK, /db/DCON design reads
are unavailable).
Registering with a host
With config.json in place the host command needs no secrets in it at all.
Claude Code:
claude mcp add midas -- python -c "import sys; sys.path.insert(0,'src'); from midas_mcp.__main__ import main; main()"
# a different product:
claude mcp add midas-civil -- python -c "import sys; sys.path.insert(0,'src'); from midas_mcp.__main__ import main; main()" -- --profile "MIDAS CIVIL NX"Claude Desktop claude_desktop_config.json — one server entry per profile:
{
"mcpServers": {
"midas-gen": {
"command": "python",
"args": ["-m", "midas_mcp", "--profile", "MIDAS GEN NX"],
"env": { "PYTHONPATH": "G:/StructAI MCP/src" }
},
"midas-civil": {
"command": "python",
"args": ["-m", "midas_mcp", "--profile", "MIDAS CIVIL NX"],
"env": { "PYTHONPATH": "G:/StructAI MCP/src" }
}
}
}(Adjust PYTHONPATH/working dir so midas_mcp is importable. Set
MIDAS_MCP_CONFIG in env only if the file is not in the auto-discovered
locations.)
Configuration reference
Precedence
Highest wins:
Environment variables (
MIDAS_MAPI_KEY,MIDAS_BASE_URL,MIDAS_MCP_*)The selected profile block in the config file
The config file's top level (shared settings)
Built-in defaults
Profile selection: --profile > MIDAS_MCP_PROFILE > active_profile in the
file > the only profile when exactly one is defined. Config file lookup:
--config > MIDAS_MCP_CONFIG > ./config.json > <project root>/config.json
%APPDATA%\midas-mcp\config.json(or~/.config/midas-mcp/config.json).
Config file
{
"active_profile": "MIDAS GEN NX",
"profiles": {
"MIDAS GEN NX": { "base_url": "http://localhost:3030/gen", "mapi_key": "<key>" },
"MIDAS CIVIL NX": { "base_url": "http://localhost:3030/civil", "mapi_key": "<key>",
"timeouts": { "analysis": 3600 } }
},
"timeouts": { "query": 30, "assign": 60, "analysis": 1800, "table": 180 },
"allow_bulk_delete": false,
"log_level": "warning",
"max_workers": 8
}A profile may override base_url, mapi_key, timeouts, registry_dir,
allow_bulk_delete, log_level and max_workers. A flat file with just
top-level base_url + mapi_key still works. config.json is gitignored —
never commit it.
Environment variables
Env var | Meaning | Default |
| API key override (beats the config file) | profile value |
| base URL override | profile value |
| profile to use |
|
| config file path | auto-discovered |
| per-class timeouts (s) | 30/60/1800/180 |
| allow |
|
| python logging level |
|
| tool-call thread pool |
|
API verification (live, 2026-09-21)
docs/API_VERIFICATION_2026-09-21.md records a full cross-check of the
registry against a running Gen NX build. Headline results:
0 method mismatches across 379 endpoints once two doc under-reports were corrected (
DB:REBCandDESIGN:SRC:AIK-SRC2K:DSRCboth serve GET, which the manual omits).0 schema field mismatches across the 24 DB endpoints whose schema the server exposes at
GET /info/db/<NAME>.38 endpoints are not served by the Gen build. They are kept and marked (
variant:Hyper-S-only/other-product/JP-only) rather than removed, since Civil NX, Civil Designer or the Hyper-S solver do expose them. Runbuild/verify_api.pyto refresh the evidence.An end-to-end cantilever built from an empty document reproduces the closed form to 0.02% (δ = PL³/3EI, M = P·L, V = P), pinned by
tests/live_workflow.py.
Variant-aware registration (v3 audit)
Per the official-source audit (MIDAS_MCP_Connector_Development_Pack_v3_official_source),
every endpoint is registered with a product and variant marker so callers
never assume an endpoint is universal across Civil/Gen:
-M1endpoints are annotatedHyper-S-only.DB:GALDisJP-only(Civil NX Japan edition).DB:HHND(Heat of Hydration Result Graph) andDB:GALDare injected from the audit (they were absent from the vendored manuals) and live-probed.Storey properties are
/ope/STORYPROP(STORY+PROP), not the oldSTORPROPspelling. It is POST-only; "no valid story information" is the expected empty answer until storeys exist./db/STORis a no-op stub on the tested Gen build.
Limitations on the tested Gen NX build
/db/RCHK(rebar layout) and the/post/TABLEdesign-force endpoints (STEELMEMBERDESIGNFORCES,COLUMNDESIGNFORCES,BEAMDESIGNFORCES) are not served — see the endpoint notes in the registry.Hyper-S (
-M1) endpoints are Gen-version-specific.accepts_analysisresults invalidate on any model change; run/doc/ANALagain before reading result tables.
License
Proprietary and confidential - internal use only. See LICENSE. No licence is granted for redistribution or third-party use.
Note that this repository also carries MIDAS GEN NX / MIDAS CIVIL NX API
documentation (api_chapters/, docs/manual/, docs/reference/, mcp/).
That material belongs to MIDAS IT and is not covered by the notice above.
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP facade over the Nebelus Construction API. ~48 tools give full agent build parity: create/update/probe agents, edit graphs, attach knowledge and vector stores, wire connectors, set governance policies and locked guardrails, enable grounding-trace, and read deployment wiring. Purpose-built for regulated industries: data residency is enforced per region (EU / GCC-KSA), with PII controls and an audit trail. Agents are created as drafts — no deploy tool is exposed over MCP by design; publishing happens in the Nebelus console.
Gateway between LLM agents and world data through eight tools and a bundled endpoint catalog.
Bounded tools for rendering, extraction, RAG, enrichment, local discovery and review analysis.
A registry of AI agent tools — MCP servers, APIs, CLIs, SDKs — kept current by automated ingestion.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables AI clients to interact with Autodesk Revit for building design, editing, analysis, clash detection, MEP, interop, documentation, and model persistence via 48 tools.MIT
- AlicenseNot gradedqualityCmaintenanceEnables Claude to directly control Midas Civil NX for bridge structural analysis, allowing users to model, apply loads, and perform analysis through natural language descriptions.2MIT
- AlicenseAqualityBmaintenanceEnables AI agents to interact with Bentley STAAD.Pro models for tasks like load case definition, data extraction, and property setting through natural language.546MIT
- AlicenseBqualityAmaintenanceEnables AI assistants to interact with bridge structural analysis software for modeling, construction stages, and code checking.132Apache 2.0