
IFClite MCP
MCPIFClite's built-in MCP server: lets agents query and modify IFC models, run clash detection, IDS validation, version and quantity diffs, export CSV, GLB and more, and color or isolate elements in a browser 3D view. Just Node.js and an IFC file; read-only mode available.
@ifc-lite/mcp
Model Context Protocol (MCP) server for ifc-lite — agent-native BIM via JSON-RPC.
Make ifc-lite the first BIM platform that any LLM agent (Claude Desktop, Cursor, ChatGPT, Goose, Windsurf, Zed, custom) can drive directly against real models.
Quick start
# Run against a local IFC file over stdio (the default for Claude Desktop / Cursor)
npx @ifc-lite/mcp ./model.ifc
# Federate multiple files
npx @ifc-lite/mcp ./arch.ifc ./struct.ifc ./mep.ifc --federate
# Read-only (no mutation tools advertised)
npx @ifc-lite/mcp ./model.ifc --read-only
# HTTP / Streamable HTTP for remote agents
npx @ifc-lite/mcp ./model.ifc --transport http --port 8765 --token $API_TOKEN
# Auto-open the WebGL viewer at startup. Add --open to also pop the URL in
# the system browser.
npx @ifc-lite/mcp ./model.ifc --viewer
npx @ifc-lite/mcp ./model.ifc --open
Embedded loaded-model authoring
For embedded HTTP servers, HttpTransport accepts maxSessions (default
1000, including pending factory builds) and sessionIdleMs (default 30
minutes). At capacity it admits a new session only if a slot is free or an
idle session can be reclaimed without unpublished drafts, active requests,
or open event streams. Otherwise initialization returns 503 session-capacity; an unknown session returns 404 unknown-session and must
initialize again. See the embedding guide
for the idle-window and response contract.
loadIfcModel returns a model whose bim.store supports the existing
addElementType, assignType, addMaterial, addMaterialLayerSet,
addMaterialLayerSetUsage and assignMaterial SDK methods. They delegate to
shared schema-aware builders, convert metre dimensions to native units, and
record each call as one complete public mutation_undo operation. Late schema
refusals leave no partial helpers. These embedded methods are distinct from
the JSON-RPC tool names; see the programmatic embedding guide.
addStair, addRailing and removeStair use the same canonical SDK factory.
removeStair removes a uniquely owned parent/flight pair atomically, retaining
shared shape/style leaves and refusing ambiguous ownership or foreign product
references. Public run_flow routes element.stair / element.railing through
model.addElement; each successful graph creation has one mutation_undo.
Tracking is fresh per RPC call, so cross-call update/remove needs a persistent
caller-owned tracking store. No separate creation or Redo RPC is added.
3D viewer integration
The server bundles the same WebGL viewer used by ifc-lite view. Once it is
open, every viewer-touching tool (viewer_colorize, viewer_isolate,
viewer_fly_to, …) drives the live scene, and any element the user clicks
in the browser flows back to MCP.
From a chat (the typical flow)
The agent should follow this etiquette by default:
- Call
viewer_askwith areason. The tool returns suggested wording so the agent can ask the user for permission. - After the user agrees, call
viewer_open. The result includes the URL to share with the user. - Drive the visualization (
viewer_colorize,viewer_color_by_property,viewer_isolate,viewer_fly_to,viewer_set_section). - Subscribe to
ifc-lite://viewer/selection(viaresources/subscribe) to be notified whenever the user picks an element.viewer_get_selectionreads the latest pick directly;viewer_wait_for_selectionblocks until the next click. viewer_closewhen done.
Pre-baked prompts
visual_audit— opens the viewer, runsmodel_audit, paints issues by severity, frames the worst offender.interactive_property_inspect— opens the viewer, waits for a click, then explains everything we know about the picked entity.visualize_query— runs a query, color-codes matches by property value, flies the camera to the result.
You can also reach it via the unified CLI:
ifc-lite mcp ./model.ifc
ifc-lite mcp ./model.ifc --read-only
Claude Desktop
Drop this into claude_desktop_config.json:
{
"mcpServers": {
"ifc-lite": {
"command": "npx",
"args": ["-y", "@ifc-lite/mcp", "/abs/path/to/model.ifc"]
}
}
}
Cursor / Windsurf / Goose
The same npx command works as a stdio server in any MCP-aware client.
What the server exposes
| Category | Examples |
|---|---|
| Discovery | model_info, model_list, model_load, model_unload, schema_describe |
| Query | query_entities, count_entities, get_entity, get_entities_bulk, spatial_hierarchy, containment_chain, relationships, properties_unique, materials_list, classifications_list, georeferencing, units, cost_data, cost_evaluate |
| Geometry | geometry_bbox, geometry_volume, geometry_area, geometry_get, raycast, clash_check, clash_matrix |
| Validation | ids_validate, ids_explain, model_audit, gherkin_check |
| IDS authoring | ids_audit, ids_lint, ids_read, ids_apply_ops (grounding-gated), ids_write, ids_schema_search, ids_schema_entity, ids_schema_pset, ids_diff, ids_preview, ids_infer, ids_coverage, ids_test |
| Mutation | entity_set_property, entity_delete_property, entity_set_attribute, entity_create, entity_delete, mutation_batch, mutation_undo, mutation_diff, model_save |
| Hosted modelling | place_opening, place_door, place_window |
| Design modelling | place_curtain_wall, place_grid, place_grid_column |
| Physical edits | edit_hosted_element, edit_element_geometry, copy_elements, duplicate_element, array_elements |
| Native Room | query_rooms, room_command |
| Wall joins | join_walls |
| BCF | bcf_topic_list, bcf_topic_create, bcf_topic_update, bcf_topic_close, bcf_viewpoint_create, bcf_export |
| bSDD | bsdd_search, bsdd_class, bsdd_property_sets, bsdd_match |
| Diff | model_diff (by_content for content-keyed matching), quantity_diff |
| Export | export_ifc, export_csv, export_json, export_glb, export_obj, export_ifcx, export_pdf_report |
| Viewer | viewer_ask, viewer_open, viewer_close, viewer_status, viewer_colorize, viewer_isolate, viewer_hide, viewer_show, viewer_reset, viewer_fly_to, viewer_set_section, viewer_clear_section, viewer_color_by_storey, viewer_color_by_property, viewer_get_selection, viewer_wait_for_selection, viewer_describe_selection |
join_walls joins two straight walls in the same placement frame through the
viewer/SDK core. It writes IfcRelConnectsPathElements and rewrites bodies and
axes atomically. Hosted openings must fit both joined end faces; unreadable cuts
refuse the operation. One mutation_undo restores the complete earlier graph,
including replaced profiles, axes and relationships.
place_opening, place_door and place_window use the viewer/SDK's shared
hosted creation core. Pass host_express_id, optional model_id (required
with several loaded models), and PascalCase params: Offset, Width,
Height, optional Sill (required for a window). Lengths are metres in the
wall's frame. Cuts must fit and avoid existing source/overlay openings;
unreadable geometry is refused. The void/fill graph is written atomically,
and one mutation_undo removes it. These writes reach IFC export; geometry
tools continue to read the parsed model.
entity_create accepts an optional global_id for the new entity's GlobalId
(IfcRoot subtypes only; written to attribute 0). It must be a valid 22-character
IFC GUID not already carried by an entity in the model; an invalid or duplicate
value is refused with INVALID_INPUT and nothing is queued.
model_diff compares by GlobalId, which reads a from-scratch re-export as the
whole model deleted and re-added. Pass by_content: true to run the
@ifc-lite/diff engine's content-keyed matching instead; it is data-scope only
(the server has no geometry pipeline) and reports unresolved duplicated /
deduplicated / ambiguous matches as groups rather than guessing a pairing —
capped by max_matches and max_group_members, both of which report the whole
totals they cut. A model_id names a session rather than a file, so all three
passes fold in mutations queued by entity_create / entity_delete /
entity_set_* and report the count in contentDiff.pendingMutations.
The rest of the read surface folds the same overlay: get_entity,
get_entities_bulk, query_entities (property filters and in_storey alike),
count_entities, model_info, model_list, properties_unique,
materials_list, classifications_list, spatial_hierarchy,
containment_chain and model_audit, plus the model manifest, entity and
spatial-tree resources. Containment folds too: a wall you create and place with
a queued IfcRelContainedInSpatialStructure is found by in_storey, and
deleting a relationship record stops it relating anything. Those payloads carry
pendingMutations whenever edits are queued and omit the field entirely when
none are, which is the line between "in this session" and "on disk" — nothing is
written until export_ifc or model_save.
relationships (voids/fills/groups/connections), units, georeferencing and
the geometry, clash and viewer tools answer from the parsed model and say so by
never carrying pendingMutations.
One GlobalId resolves to one entity everywhere: an entity the session created
wins over a same-GlobalId entity in the file, and a deleted one never resolves.
get_entities_bulk keys its map by that same rule and lists any key that named
more than one live entity in ambiguousGlobalIds.
Resources expose live model state under the ifc-lite:// URI scheme:
ifc-lite://server/manifest
ifc-lite://model/{model_id}/manifest
ifc-lite://model/{model_id}/entity/{global_id}
ifc-lite://model/{model_id}/spatial-tree
ifc-lite://model/{model_id}/materials
ifc-lite://model/{model_id}/property-sets
ifc-lite://viewer/status (open/closed, port, client count)
ifc-lite://viewer/selection (live; supports `resources/subscribe` for push updates)
Pre-baked prompts ship the BIM expertise:
audit_model, find_fire_rated_doors, generate_bcf_from_ids,
compare_versions, space_program_check, clash_review,
prop_quality_pass, migrate_to_ifcx, visual_audit,
interactive_property_inspect, visualize_query.
Programmatic embedding
import {
createMCPServer,
StdioTransport,
loadIfcModel,
InMemoryModelRegistry,
} from '@ifc-lite/mcp';
const registry = new InMemoryModelRegistry();
registry.add(await loadIfcModel('./model.ifc'));
const server = createMCPServer({ version: '0.1.0', registry });
const transport = new StdioTransport();
await transport.connect(server);
For Tauri/Electron hosts, use InProcessTransport:
import { InProcessTransport } from '@ifc-lite/mcp';
const transport = new InProcessTransport();
await transport.connect(server);
const initResp = await transport.send({
jsonrpc: '2.0',
id: 1,
method: 'initialize',
params: { protocolVersion: '2025-11-05', capabilities: {}, clientInfo: { name: 'host', version: '1' } },
});
Errors
Domain errors come back inside the tool result with isError: true and a
stable structuredContent.code:
{
"isError": true,
"content": [{ "type": "text", "text": "Entity not found in model 'arch'" }],
"structuredContent": {
"code": "ENTITY_NOT_FOUND",
"details": { "model_id": "arch", "express_id": 42 },
"hint": "Use query_entities to discover valid IDs."
}
}
That keeps the LLM in the loop instead of aborting the chain on a JSON-RPC error.
Roadmap
Shipped: stdio + Streamable HTTP transports; query, geometry (bbox, volume, area), clash, IDS validation, mutation, BCF, bSDD, diff, export (IFC, CSV, JSON, GLB, OBJ, IFCX), and live viewer control.
Planned: mesh geometry (geometry_get) and raycast (both need the WASM
geometry pipeline), Gherkin validation (gherkin_check), and PDF report export
(export_pdf_report) — these tools are registered but currently return
UNSUPPORTED_OPERATION. Also planned: OAuth 2.1 with PKCE and hosted
multi-tenant deployment, sampling for natural-language descriptions, and public
registry listing.
Docs
See the ifc-lite docs for the full platform documentation.
Licensed under MPL-2.0.
Loaded-model physical edits use the same command cores as the viewer and typed
SDK. edit_element_geometry handles Move/Rotate, Size, Wall Endpoints, Split and
Trim/Extend. copy_elements, duplicate_element and array_elements carry
hosted graph records and share the viewer placement and naming policies.
References are model-local EXPRESS IDs; offsets use IFC storey-local metres
and planar rotations use radians. Every write is one mutation_undo batch;
unsupported sources and unsafe shared geometry refuse before committing.
See the MCP guide
for parameter contracts.
room_command derives Room candidates from the current native geometry and
runs Auto/Pick/Footprint/Update or layout Drag/Split/Remove/Prune through the
shared Room core. It requires the WASM runtime. Query does not write; writes
record one complete Undo batch. Model removal and session termination free
retained native layout handles. Unsupported schema/storey planes return
INVALID_INPUT; unavailable native initialization returns
UNSUPPORTED_OPERATION. Unexpected export, parse, processing or runtime
import failures return INTERNAL_ERROR; cancellation and state conflicts
retain their distinct retryable codes.
AI Flow nodes use explicit host environment configuration (IFC_LITE_AI_MODEL,
IFC_LITE_AI_API_KEY, optional IFC_LITE_AI_BASE_URL). Review-capable runs require
a new allowed checkpoint_path and return a pending artifact. A separate
resume_flow with the exact approved_digest rechecks native source state and
current scope, restores the original budget and consumes one durable disk claim.
See the MCP guide for further pauses and refusals.
propose_flow lets a read-only MCP caller run a native read/AI-only graph to
a pending artifact. It rejects declared or node-defined effects and permits
only model.read and network.ai. The current read scope and model allowlist
still apply; the separate resume_flow requires current mutate authorization.
MCP responses and checkpoint budgets include provider usage receipts without
prompts, replies or credentials; receipt history survives subsequent pauses.
review_findings reads actual retained IDS/information Review facts with read
permission. Native producer capture binds full source SHA-256, definition/run
provenance and exact model ownership; scope revocation suppresses the whole
multi-model envelope. No editor, artifact or decision is created. Unsupported
sources, incomplete overlays and bounded output stay explicit. See
the captured native Review contract.
review_findings can read supplied saved_analysis_runs or
saved_validation_reports using the canonical portable codecs and full-source,
duplicate-preserving identity binding. This is a separate historical read mode;
without either input the existing captured native read remains. Imported
provenance never attests execution or complete native coverage. Read scope,
current permissions/ownership and known-credential guards still apply. See
the supplied-input contract.
Native Flow bcf.createTopic and bcf.addComment writes use a durable,
credential-free publication journal. Local MCP and CLI share
IFCLITE_BCF_OUTBOX_DIR (default ~/.ifc-lite/bcf-outbox); authenticated MCP
principals get stable, separate hashed namespaces across sessions. Keep the
journal when restarting: a committed write whose response was lost remains
unresolved and blocks an identical send.
Use bcf_publications_list to inspect intents and receipts. With mutate
permission, bcf_publication_check reads the original target and stores actual
matching candidates; supply current capabilities, including the target's
network.fetch:<host> and exact secret.read:<NAME> when using token_env.
A separate bcf_publication_reconcile binds entry_id to one checked
candidate_guid without sending a write. Neither command retries an uncertain
create, and reconciliation refuses arbitrary GUIDs or live send ownership.
Checks and reconciliation are unavailable to read-only callers. These native
recovery tools do not replace the viewer's BCF content library or qualify an
external vendor's OAuth/API behavior.
Remote sessions without a stable authenticated principal refuse BCF publication
and recovery; ordinary model flows remain available. A transient session id
never replaces the durable principal boundary.
Checks keep trim-equivalent free text as manual candidates. Rewritten or
omitted fields leave unmatched objects unavailable; they cannot prove absence.
After a complete successful check finds an empty server collection and the caller
explicitly supplies confirm_full_read_access: true for the original write’s
full access scope,
bcf_publication_confirm_absent explicitly releases that entry_id for a
separately reviewed later run. This mutate-only decision never sends a write;
a newer failed check or live sender blocks it. Checking alone never retries.
Successful BCF outputs redact the actual resolved bearer, including literal
and Player tokens, after the original durable receipt is saved.
Native BCF listing is bounded: bcf_publications_list accepts limit (1–1000)
and the preceding cursor, and returns {entries,nextCursor?}. Follow every
nextCursor, including empty progress pages; the pages are not a snapshot
across concurrent inserts. Recovery by known entry_id remains available when
new-create capacity is exhausted; existing immutable receipts are retained.
If a sending process cannot be identified on this machine, bcf_publication_check
requires an operator to establish that the old process has stopped and explicitly
pass confirm_owner_stopped: true. This assertion is persisted, never overrides
an observed live sender, and does not send or retry a create. token_env requires
its exact secret.read:<NAME> grant and may contain a short nonempty bearer.
An empty read without this explicit full-scope confirmation is unavailable,
even with a bearer token. Tokens never imply full visibility. Filtered, partial
or incomparable reads cannot safely release a write; old persisted absence
records without the confirmation marker remain readable but cannot authorize
release. Only a caller who knows the original write’s complete access scope
should make this assertion; live vendor authorization is not qualified.
Related resources

mcp-servers-for-revit
MCPDrive Autodesk Revit with AI: query elements, create walls, doors, windows, floors, grids, levels and rooms, tag in bulk and take material quantities. Needs Revit 2020-2026 on Windows and Node.js, with the plugin from Releases placed in the Revit add-ins folder.
mcp-servers-for-revit/mcp-servers-for-revit384
Archicad Tapir MCP Server
MCPConnects to a running Archicad and exposes 190+ commands from the Tapir add-on and the official JSON API, for querying walls and other elements, batch-editing models and exporting files. Needs Archicad (Windows or macOS), Tapir and uv. Alpha: it edits the open project directly, so back up first.
SzamosiMate/tapir-archicad-MCP124
Pascal Agent Skills
PluginOfficial plugin for Pascal, an open-source 3D architecture editor: lets agents create, edit and validate 3D models of rooms and floors over MCP and check furniture placement for collisions or blocked doors. Local use needs the Pascal CLI (Node.js 22.13+); hosted projects need an API key.
pascalorg/editor24.9k
IFClite CLI
CLICLI for the open-source IFClite BIM toolkit: inspect models, query element properties, build door and window schedules, validate against IDS, run clash detection, diff versions, merge and convert, with JSON output; ifc-lite mcp lets agents query and edit BIM data directly. Needs Node.js.
LTplus-AG/ifc-lite427
DDC Skills for AI Agents in Construction
Skill200+ skills for construction firms: export Revit, IFC and DWG quantities to Excel, estimate with international unit rates, produce daily and photo site reports, and track budget and schedule variance. Needs Python 3.9+; Revit/DWG conversion is Windows-only; some need Docker or an OpenAI key.
datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction357
FreeCAD MCP
MCPLets agents drive the open-source CAD app FreeCAD: create and edit part models in natural language, run Python scripts, capture views and run FEM structural analysis for mechanical and product design. Needs FreeCAD with the addon and its RPC server, plus uv; engineers should verify results.
neka-nat/freecad-mcp2.9k