Actions (enabled by default)¶
Actions run unless the workstation read-only lock is active.
The lock is %LOCALAPPDATA%\RevitModelMcp\read-only on the Revit workstation.
Action tools stay listed while locked.
Refused calls return success:false, errorCode:"read_only", and a message naming the lock, its source, and how to remove it.
See Read-only mode and Errors and refusals.
Transaction warnings are dismissed and reported in warningsDismissed (omitted when empty); errors that cannot be safely resolved roll back the action.
Every action result carries a summary: one human sentence describing what changed, how many elements, and in
which document, alongside verification. A committed mutation assimilates its transaction into a single named
Revit undo entry, MCP (<clientName>): <short summary> (at most 60 characters), visible in Revit's Undo list and
in the add-in's "MCP activity" dockable pane ("Activity" button in the MCP panel on Revit's Add-Ins tab).
select and show make no document change and get no undo entry, but still appear in the activity pane.
See Undo the last action for revit_undo_last.
Action tools that target an open document accept document. revit_process_models uses paths or folder instead. revit_export_nwc, revit_export, revit_link_cad, revit_walls_from_cad, revit_edit_families, revit_align_link_datums and revit_execute_code also accept timeout_seconds from 30 to 3600 seconds. revit_process_models accepts 30 to 14400 seconds.
Revit remains busy for the whole action duration.
Other listed tools use the default response timeout of 120 seconds. All actions use a pickup timeout of 300 seconds and require exactly one instance returned by the transport.
HTTP addresses one endpoint; the file transports discover workstation instances.
All IDs are unitless Revit element IDs.
Revit 2022-2023 accept IDs up to 2,147,483,647 only; larger IDs fail on those years.
Action jobs with targetDocument resolve that reference when the add-in executes the job.
The reference must match exactly one open document by a case-insensitive substring of its title or file name.
The resolved document is bound by its title and full path for all mutations and verification, even if another document is active.
An unknown or closed target returns The addressed document '<TargetDocument>' is not open.
An ambiguous target returns The document reference '<TargetDocument>' is ambiguous (N open documents match); use a more specific substring.
Resolution failure aborts the whole batch before any step runs; an addressed job never falls back to the active document.
The target is resolved once before the batch loop, and a later document or transaction failure is reported as a step error.
select, show and isolate (including reset=true) require the resolved document to be active.
Otherwise, they return Cannot run '<command>' on '<title>' because it is not the active document; activate it in Revit first.
Jobs without targetDocument retain the active-document behavior.
activeView always reports the actual active view, even when a mutation targets another document.
Long action jobs¶
revit_process_models, revit_export, revit_export_nwc, revit_edit_families, audited revit_open_document, and revit_execute_code can outlive the tool wait.
REVIT_MCP_TOOL_BUDGET_S defaults to 40 seconds, so that the first response arrives within a 60-second client limit even over SSH, and accepts 10 through 200.
revit_execute_code with a timeout_seconds below the budget waits for that timeout, then returns the same running response instead of an error.
Short actions return their existing response shape.
An unfinished long action returns status:"running", jobId, progress, partial, and a warning that the action may already have changed the model.
Call revit_jobs(job_id=jobId, wait_seconds=40) until the original action response is returned.
wait_seconds accepts 0 through 50 seconds.
A running poll returns progress and completed per-model results in partial.
A final poll preserves the original response, summary, timeout warnings, and verification warnings.
Do not resubmit a running action.
The add-in retains action results for 24 hours in the selected instance's jobs/<jobId>.json directory; other results are kept for ten minutes (see result retention).
Local pipe, SSH file, and authenticated HTTP clients can fetch the result after an MCP server restart.
Path redaction applies to stored responses when REVIT_MCP_REDACT_PATHS=1 on the workstation, and to returned responses when enabled on the server.
revit_cancel_job(job_id) requests cancellation.
revit_process_models stops before the next model, lists every unstarted model in data.models with status cancelled, and returns data.cancelled:true with completed results.
Cancellation does not undo completed models or interrupt an export, document open, family edit, or script already running in Revit.
Cancellation is refused while the workstation read-only lock is on.
| Tool | Arguments | Action and units |
|---|---|---|
revit_cancel_job |
job_id, document=null, process_id=null |
Request cancellation. Process-models stops before the next model. Poll revit_jobs for the final result. Completed changes remain committed. |
revit_select |
element_ids |
Select IDs; [] clears selection. Return count, the current selection size after the call. |
revit_show |
element_ids, select=true |
Show nonempty IDs and zoom to fit when opening a new view; return activeView, viewOpened and count, the current selection size after the call. With select=false, count reports the previous selection. |
revit_override_graphics |
element_ids, color="#FF0000", views="active", halftone_others=false, line_weight=null, fill=true, transparency=0, reset=false |
Highlight visible elements in the active view, all eligible model views or named views. Reset restores graphics saved in the current Revit session. Returns viewsTouched and elementsPerView. |
revit_isolate |
element_ids, reset=false |
Temporarily isolate IDs; element_ids=[] with reset=true clears hide/isolate. |
revit_move |
element_ids, dx_mm, dy_mm, dz_mm=0 |
Move by model-axis offsets in mm. Group members that Revit refuses to change are skipped; see Group members. Pinned, hosted and constrained elements that do not move are skipped too; see Elements that cannot move. |
revit_rotate |
element_ids, angle_deg, center_mm=null |
Rotate around a vertical axis through the given model XY point in mm or the combined bounding box center. Pinned elements are skipped and reported, as are hosted and constrained elements that do not rotate. Group members that Revit refuses to change are skipped. |
revit_copy |
element_ids, dx_mm, dy_mm, dz_mm=0, count=1 |
Create 1-100 copies at successive multiples of the offset. Return IDs per copy. Group members that Revit refuses to change are skipped. |
revit_mirror |
element_ids, axis, point_mm, copy=true |
Mirror across an X or Y parallel line through the model XY point in mm. Copy keeps originals. Without copy, pinned, hosted and constrained elements that do not mirror are skipped and reported. Group members that Revit refuses to change are skipped. |
revit_change_type |
element_ids, type_name, family=null |
Resolve each target among compatible types. Refuse ambiguous or incompatible targets with candidates. Group members that Revit refuses to change are skipped. |
revit_update_parameters |
filters, parameter, value, parameter_id=null, max_elements=5000, include_type_parameters=false |
Use query filters to update matching instance parameters. Refuse counts above the limit, at most 20000. Report missing, read-only and type-only parameters and preview up to 50 values. Members of groups that Revit refuses to change appear in skipped.inGroup, next to skipped.missing, skipped.readOnly and skipped.typeParameter; dry runs predict these skips. With include_type_parameters=true, update each distinct type once and report affectedTypeIds and outsideFilterCount for instances sharing those types outside the filter. |
revit_place_family |
family, type_name, x_mm, y_mm, level, rotation_deg=0 |
Place a loaded family at model XY in mm on a named level; rotate about Z in degrees. |
revit_load_family |
paths (1-100), overwrite=false, overwrite_parameter_values=false, dry_run=false, timeout_seconds=600 |
Load workstation .rfa files in one undo entry. Existing families are skipped unless overwrite is true. With overwrite, changed families are reloaded; an already loaded family that Revit leaves unchanged is unchanged. |
revit_place_families |
Exactly one of placements or at_rooms; load=null, dry_run=false, stop_on_error=true, timeout_seconds=600 |
Load optional families and place up to 2000 instances in one undo entry. |
revit_create_wall |
start_mm, end_mm, level, wall_type, height_mm=3000 |
Create a straight wall; endpoints are [x,y] in model mm. |
revit_create_mep_run |
kind, points_mm, level, type_name=null, system_type=null, width_mm=null, height_mm=null, diameter_mm=null, offset_mm=null, connect_to=null |
Create 1-199 straight duct, pipe, cable tray or conduit segments from 2-200 model points in mm. Missing Z uses the level elevation plus 2700 mm for ducts and trays or 2500 mm for pipes and conduits. The first available type and system type are defaults. Set rectangular width and height or round diameter as applicable. Pipe diameter must match a nominal size in the routed pipe segment; invalid sizes report the available sizes in mm. Return segmentIds, fittingIds, unjoinedPairs and total lengthMm. An elbow that Revit cannot place leaves the pair unjoined. Connect the first start to a free connector within 50 mm when connect_to is supplied. |
revit_link_cad |
path, view=null, level=null, link=true, origin="internal", units="auto", layers=null, dry_run=false, timeout_seconds=600 |
Link or import a DWG into a plan view. Returns the instance ID, CAD layer line counts and XY extents in mm. |
revit_walls_from_cad |
cad_id, layers, level, wall_type=null, height_mm=3000, min_thickness_mm=80, max_thickness_mm=700, min_length_mm=300, max_gap_mm=3000, join=true, dry_run=false, timeout_seconds=600 |
Bridge openings and pair parallel CAD lines. Returns walls, unpairedLines, mergedSegments and width mismatches. Rejected joins are left out and reported as unjoinedEnds with unjoinedReasons; dry runs report the same join numbers. |
revit_create_view |
kind, name=null, level=null, view_family_type=null, template=null, scale=null, box=null, element_ids=null, display_style=null, detail_level=null |
Create a floor, ceiling or structural plan, section, 3D or drafting view. Plans need a level. Sections need a box or element IDs; element bounds expand by 1000 mm. A 3D view without bounds shows the whole model without a section box. 3D defaults are shaded and fine; other kinds keep view type defaults. Sections look along +Y. Styles: hidden_line, shaded, consistent_colors, realistic. Detail: coarse, medium, fine. |
revit_duplicate_view |
view, mode="duplicate", name=null |
Duplicate a view, include detailing or create a dependent view. |
revit_apply_view_template |
views, template |
Apply a matching template to one or more views. Type mismatches are reported in typeMismatches. When no view matches the template type the call is refused and nothing is committed. |
revit_create_sheet |
number, name, title_block=null |
Create a sheet with a loaded title block. Sheet numbers must be unique. |
revit_place_views_on_sheet |
sheet, views |
Place views and schedules. Each item has view and optional paired x_mm, y_mm sheet coordinates. Missing positions lay out left to right with 20 mm gaps and row wrapping. Cannot run in a batch. |
revit_tag_elements |
view, categories=null, element_ids=null, leader=false, orientation="horizontal", tag_type=null, skip_tagged=true, max_elements=5000 |
Tag elements in a view, chosen by category names or by element IDs (exactly one). Returns the created tag IDs in createdElementIds. Elements that already have a tag in the view are left alone unless skip_tagged=false. Inputs Revit cannot tag are listed in skipped with a reason, and the call fails when no tag is created. tag_type matches a tag type name, a family name or Family: Type; without it Revit uses the default tag type of each category. Room tags need a plan view and ignore orientation. Spaces and areas are not supported. Cannot run in a batch. |
revit_create_schedule |
category, fields, name=null, filters=null, sort=null, itemized=true |
Create a schedule for one category. fields are Revit UI field names in column order. filters are {field, operator, value} records; operator is equal, not_equal, greater_than, greater_than_or_equal, less_than, less_than_or_equal, contains, not_contains, begins_with, not_begins_with, ends_with, not_ends_with, has_value or has_no_value (the last two take no value). Numeric values use mm for lengths, m2 for areas and m3 for volumes. For fields that reference an element (Level, Phase), value is the element name; it is resolved to the element and filtered by its ID, and an unknown or ambiguous name is reported in skipped. sort records are {field, descending=false, header=false, footer=false, blank_line=false}; a header or footer groups rows. A field used only by a filter or sort is added hidden. Returns the schedule view ID in viewId, the resolved fields, filtersApplied and sortApplied. Names Revit does not know are listed in skipped, and the call fails when no field resolves. Cannot run in a batch. |
revit_set_parameter |
element_id, parameter, value, optional parameter_id |
Set exactly one instance or type parameter. Group members that Revit refuses to change fail with a clear message, including in dry runs. parameter_id is a BuiltInParameter enum name, shared parameter GUID or positive decimal ParameterElement ID. parameter remains required. Without an ID, names accept the localized Revit UI name, a BuiltInParameter enum name or a supported English alias. Multiple matches are refused with each candidate's ID, name, storage type, owner and kind. No name guessing occurs. Use a JSON string for String, integer for Integer or number for Double. Lengths use mm, areas m2, other doubles internal units. |
revit_delete |
element_ids, dry_run=false, confirm_token=null |
Delete nonempty IDs and their dependents. A real deletion of more than 500 elements, dependents included, needs a confirmation token. |
revit_run_actions |
steps, dry_run=false |
Execute 1-50 actions in one MCP (<clientName>): ... undo entry. |
revit_process_models |
paths=null, folder=null, recursive=false, pattern="*.rvt", open=null, steps=null, code=null, exports=null, save=null, stop_on_error=false, dry_run=false, confirm_token=null, timeout_seconds=14400, process_id=null |
Open and process 1-500 models in the interactive Revit session, then close each model. |
revit_export_nwc |
path, exporter options, overwrite=false, dry_run=false, confirm_token=null, timeout_seconds=1800 |
Export NWC to an absolute workstation path. Requires the matching Navisworks NWC Export Utility. Replacing an existing file needs a confirmation token. |
revit_export |
format, views=null, sheets=null, sheet_set=null, all_sheets=false, output_dir=null, options=null, overwrite=false, dry_run=false, confirm_token=null, timeout_seconds=1800 |
Export PDF, DWG, IFC or schedule CSV files to a workstation folder. Replacing existing files needs a confirmation token. Cannot be used in a batch. |
revit_edit_families |
operations, families=null, overwrite_parameter_values=false, stop_on_error=true, dry_run=false, timeout_seconds=1800 |
Edit open family or named project families; one load cycle per family. |
revit_align_link_datums |
All revit_compare_link_datums arguments, create_missing=true, level_type=null, grid_type=null, include_pinned=false, create_plan_views=false, plan_view_type=null, dry_run=false, timeout_seconds=600 |
Move same-name grids and levels to a linked model; optionally create missing datums and floor plans. Cannot be used in a batch. |
revit_set_view_visibility |
view, hide_categories=null, show_categories=null, category_classes=null, hide_categories_by_type=null, worksets=null, filters=null, template_mode=null, dry_run=false |
Change view category, class, workset and filter visibility. Cannot be used in a batch. |
revit_remove_links |
links (names, IDs or "*"), kinds=null (revit, cad and point_cloud; image only when listed), include_imported_cad=false, dry_run=false, confirm_token=null |
Remove selected link types and their instances. A real removal needs a confirmation token. Cannot be used in a batch. |
revit_execute_code |
code, transaction="auto", dry_run=false, confirm_token=null, timeout_seconds=600 |
Compile and run C# on the Revit API thread. Every call except dry_run needs a confirmation token. Cannot be used in a batch. |
revit_undo_last |
document |
Undo the last MCP action through Revit's own undo command; refused unless it is still Revit's last undo entry. |
revit_link_cad accepts a workstation .dwg path subject to the same absolute-path and trusted network share rules as other file actions. The view must be a plan. Without view, it uses a floor plan on level, or the active plan. origin accepts internal, shared and center; units accepts auto, mm, cm, m, in and ft. The layers list selects imported layers. The result reports line and polyline segment counts by layer, plus XY extents.
revit_walls_from_cad uses the imported instance geometry and selected CAD layers. It merges collinear segments on each layer within 0.5 degree and 5 mm across gaps up to max_gap_mm. Short pieces participate in merging before the length filter. It pairs overlapping intervals within the thickness range. Unused intervals can pair with another partner. Bridged openings remain continuous. Each wall uses the requested basic type or the closest basic type by width. With join=true, centerlines extend or trim to L, T and X intersections within max_thickness_mm, and Revit joins are enabled there. dry_run=true returns the same planned walls and join numbers without model changes. Joins Revit would reject are left out and reported as unjoinedEnds with unjoinedReasons. unpairedLines counts merged lines with no paired interval; mergedSegments counts source segments absorbed by merging.
An unknown layer name is refused with the list of available layers, for a dry run and a real run. A real run that pairs no walls fails with the count of unpaired lines and creates nothing, so no empty undo entry is recorded.
Category names in hide_categories and show_categories accept the Revit UI name, the BuiltInCategory name (OST_StructuralColumns, with or without the prefix), the English name (Structural Columns) or the category ID, independent of the Revit UI language. An unknown name is rejected with close matches drawn from all three forms. revit_view_elements and the universal query filters resolve category names the same way.
category_classes maps model, annotation, analytical, import and point_clouds to booleans (true means hidden). hide_categories_by_type accepts those class names and hides each matching category. worksets has hide_mask and show_mask lists; masks are case-insensitive globs (*, ?) or regular expressions prefixed with regex:. The response lists matched worksets, before/after values and categories Revit could not hide. filters contains {name, visible} records. When a template is applied, choose template_mode: detach clears it on this view, edit_template changes it for all views using the template and lists them, or duplicate_view creates a copy without it. A missing mode is rejected.
Link removal refuses central-connected workshared documents. A local copy is allowed with a warning that sync propagates deletion. Non-linked CAD imports remain unless include_imported_cad=true. A real removal first returns needsConfirmation with confirmationText listing the selected link types, and removes nothing until you retry with confirm_token. The token is bound to the document, the exact set of selected link types and the document state. The confirmed removal returns warning: "Removing links cannot be undone in Revit; Undo will not restore them." The warning is set before deletion. revit_undo_last refuses after link removal for this reason. dry_run applies the proposed changes within a transaction and rolls it back without committing.
Alignment uses one host-document transaction, with dry_run rolling it back after prospective results are read. Pinned and other-user-owned datums are skipped. Existing datums are never renamed or deleted, and grid extents and scope boxes are never changed. Moving levels also moves elements hosted on them; moved-level results include dependentCount. Created datums report their ID and workset. Geometric alignment does not create a monitor relationship or later Coordination Review warnings.
Look up the API first¶
revit_api_lookup returns public API metadata from the RevitAPI and RevitAPIUI assemblies loaded in the running Revit process.
The agent calls it before writing C# for an unfamiliar type.
Results describe the running version only; assemblyVersions identifies the loaded assemblies.
The tool is read-only and belongs to the code toolset.
It works without an open document.
{"query": "Autodesk.Revit.DB.Element.GetDependentElements", "kind": "member", "limit": 25}
Type queries resolve an exact full name, then a case-insensitive simple name in an Autodesk.Revit namespace, then a substring of type names.
Member queries accept Type.Member or a type name for its public members.
Search queries match type and member names.
Ambiguous simple names return up to 20 candidates for a full-name retry.
limit accepts 1 to 100 results across types and members; truncated reports omitted results.
include_inherited defaults to false, and include_obsolete defaults to true.
Signatures, parameters, and obsolete messages come from reflection without invoking API members.
XML summaries are optional, contain the first sentence, and stop at 300 characters.
Missing XML and type load failures appear in skipped and skippedCount.
Execute C# code¶
revit_execute_code accepts up to 200,000 C# characters. Submit either the body of public static object Execute(ScriptContext ctx) or a full compilation unit declaring public static class Script with that method. Method bodies have common System and Revit namespaces imported. ScriptContext provides UiApplication, Application, UiDocument, Document, Log, ToMm and FromMm. The target document follows the normal document resolution rules. Both supported transaction modes require a target document.
The default auto mode owns one Revit transaction inside a group. Scripts in this mode must not open transactions.
The group mode starts a TransactionGroup without an outer Transaction.
Scripts can open and commit Transactions, SubTransactions, and edit scopes such as StairsEditScope.
Every script-owned scope must finish before the script returns.
The runner tracks transaction and edit-scope starts in submitted source, closes unfinished scopes in reverse order, and rolls back the group on an exception or an unfinished scope.
Successful changes are assimilated into the same single named undo entry as auto; an empty run keeps no undo entry.
dry_run=true preserves group, returns prospective script values and logs, and calls RollBack on the group.
Confirmation tokens, machine ExecuteCode policy, the workstation read-only lock, activity entries, and summaries apply to both modes.
revit_run_tool(transaction="group") uses the same runner; read-mode saved tools always roll back.
A successful call that changes the model creates one undo entry named MCP (<client>): Execute code. A script that changes nothing is rolled back: the result has committed: false and rolledBack: true, and no undo entry or undoName. dry_run=true runs the code and rolls back the group. Runtime errors also roll it back. The none mode, which lets a script own transactions and open or close documents without a guaranteed undo, is refused by default. A call with transaction="none" fails with a message that says so. I plan a separate workstation policy that can allow it; there is no setting for it today. Every call except dry_run first returns needsConfirmation, a confirmationText with the SHA-256 prefix, length, transaction mode and target document, and a confirmToken, and does not run the code. Retry with identical arguments plus confirm_token after the user agrees. The token is bound to the code hash, the transaction mode and the target document. The response includes returnValue, up to 2,000 log lines, elapsed time, summary and any undo name or warning. Return values have a depth limit of 6 and at most 5,000 collection items. Revit elements, IDs and XYZ points get compact JSON forms. Plain classes and anonymous types return public readable properties as JSON objects. Other Revit API objects use ToString(). Numbers use invariant culture. Compile and runtime failures have summaries starting with Code failed to compile and Code failed, respectively.
Native stair sketch example¶
This full compilation unit runs with revit_execute_code(transaction="group", dry_run=true) for a preview.
The project must contain two levels with an appropriate stair height and a usable default stair type.
The example uses the lowest two levels, a 1,000 mm width, and a 300 mm tread depth.
A committed run requires the normal confirmation challenge and retry with identical arguments.
The returned IDs belong to the preview until rollback; they are not persistent element IDs.
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using RevitModelMcp.Control;
public static class Script
{
public static object Execute(ScriptContext ctx)
{
var document = ctx.Document;
var levels = new FilteredElementCollector(document).OfClass(typeof(Level))
.Cast<Level>().OrderBy(level => level.Elevation).Take(2).ToArray();
if (levels.Length != 2) throw new InvalidOperationException("Two levels are required.");
using var scope = new StairsEditScope(document, "Create native stair");
var stairId = scope.Start(levels[0].Id, levels[1].Id);
ElementId runId;
using (var transaction = new Transaction(document, "Sketch stair run"))
{
transaction.Start();
var stairs = (Stairs)document.GetElement(stairId);
var riserCount = stairs.DesiredRisersNumber;
var width = ctx.FromMm(1000);
var depth = ctx.FromMm(300);
var length = (riserCount - 1) * depth;
var boundaries = new List<Curve>
{
Line.CreateBound(new XYZ(0, 0, 0), new XYZ(0, length, 0)),
Line.CreateBound(new XYZ(width, 0, 0), new XYZ(width, length, 0))
};
var risers = Enumerable.Range(0, riserCount).Select(index =>
(Curve)Line.CreateBound(new XYZ(0, index * depth, 0), new XYZ(width, index * depth, 0))).ToList();
var path = new List<Curve>
{
Line.CreateBound(new XYZ(width / 2, 0, 0), new XYZ(width / 2, length, 0))
};
var run = StairsRun.CreateSketchedRun(document, stairId, 0,
boundaries, risers, path);
runId = run.Id;
if (transaction.Commit() != TransactionStatus.Committed)
throw new InvalidOperationException("Stair sketch transaction failed.");
}
scope.Commit(new RollBackStairErrors());
return new { stairId, runId };
}
private sealed class RollBackStairErrors : IFailuresPreprocessor
{
public FailureProcessingResult PreprocessFailures(FailuresAccessor failures)
{
foreach (var message in failures.GetFailureMessages())
{
if (message.GetSeverity() == FailureSeverity.Warning) failures.DeleteWarning(message);
else return FailureProcessingResult.ProceedWithRollBack;
}
return FailureProcessingResult.Continue;
}
}
}
Compiler errors include diagnostic IDs, messages, and positions in the submitted code. Runtime errors include their type, message and script frames. The compiler caches up to 32 compiled scripts. On Revit 2022-2024 (.NET Framework), compiled scripts cannot be unloaded, so identical code (same source and transaction mode) reuses one loaded assembly, and each distinct script stays loaded until Revit restarts. Revit 2025 and later unload each script after the call. The add-in cannot stop a running script; timeout_seconds only limits the server wait. Inspect Revit state before retrying after a timeout.
The activity pane shows the first non-empty source line and a SHA-256 prefix. Source is stored in %LOCALAPPDATA%\RevitModelMcp\code; the newest 500 files are retained. The audit header records client, document title and transaction mode. When path redaction is on, Windows paths in the activity line and stored source are replaced with redaction markers.
Model file export¶
revit_export writes to output_dir, or to %LOCALAPPDATA%\RevitModelMcp\exports\<document title>\<UTC timestamp> when omitted. The directory must be an absolute drive path or a UNC path under trustedNetworkRoots. Device paths and .. segments are refused. Existing output files require overwrite=true. When overwrite=true and at least one target file already exists, the first call returns needsConfirmation with the files that would be replaced; retry with confirm_token. The token is bound to the document, the target paths and their size and modification time. With no existing target, or with dry_run, no token is needed. Exports inside revit_process_models are not gated. dry_run=true returns resolved targets and planned names without writing. The result includes folder, files with sizes, targets, skipped, elapsedMs and summary. File export changes no model elements and creates no undo entry.
PDF and DWG accept any combination of view names or IDs, sheet numbers, names or IDs, a saved sheet_set, and all_sheets=true. At least one printable target is required; templates and unprintable views are rejected. PDF options are combine=true, file_name, naming="sheet_number_name" or "view_name", color="color", "grayscale" or "black_line", zoom_percent=100, paper="auto", hide_crop_boundaries=true and hide_scope_boxes=true. DWG options are setup (saved export setup), merged_views=false and file_version (Revit ACADVersion name).
IFC exports the whole model or one view selected through views. Its options are version="IFC2x3CV2", "IFC4RV" or "IFC4x3", file_name, export_base_quantities=true, space_boundaries=0 and split_walls_by_level=false. The required IFC transaction is rolled back after export. CSV accepts schedule names or IDs in views; omitting views exports all non-template schedules except revision and keynote legends. CSV options are delimiter=",", headers=true, title=false, group_headers=false and encoding="utf-8". Revit exports the visible schedule fields. The file is then encoded as UTF-8 with a BOM for Excel. With path redaction enabled, the response folder contains only the final folder name.
Process many models¶
revit_process_models accepts either 1-500 absolute .rvt paths or a local or UNC folder with recursive and a .rvt file pattern. RSN model paths are accepted in paths; cloud paths are refused. trustedNetworkRoots applies to UNC paths. Already open models are skipped. Each model opens in the background with the revit_open_document mode, worksets, and audit options. The active document is left in place. The action uses the interactive Revit session, not the read-only batch collector worker.
steps uses the same 1-50 step allowlist as revit_run_actions, and code uses {"code":"...","transaction":"auto"}; "none" is refused unless dry_run=true forces "auto", while auto and group are preserved. A call that has code and is not a dry_run needs a confirmation token, like in_place saves; the token is bound to the whole request, including the code, and to the size and modification time of the source files. The script runs after the steps with ScriptContext.Document set to the processed model. exports is a list of revit_export requests without document; an export output_dir can contain {model}. Without an export output_dir, files go to <save.output_dir>\<model> when an output directory is set, or %LOCALAPPDATA%\RevitModelMcp\exports\<model> otherwise. The result reports each model's open settings, step summary, script return value and log, export files, saved path, dialogsDismissed, elapsed time, status, and error. dialogsDismissed is { "messages": [{ "message": "...", "count": 1 }], "truncated": false }; it combines dismissed dialogs and warnings, retains up to 50 distinct messages, and counts repeats. truncated=true means further distinct messages were omitted. Sources with the same model name (file name without extension) are refused when save.mode="output_dir" is used or exports use the default or a {model} output directory, because their outputs would overwrite each other. The error lists the colliding sources; process them in separate calls. Failures to close the model or unsubscribe handlers mark the model failed with the reason in error; failures of other cleanup steps (activity record, change capture, transaction group) keep the status and are listed in the model's warnings. A failed model does not stop later models unless stop_on_error=true. revit_jobs(job_id=jobId) reports currentIndex (one-based), total, redacted currentPath, and completed per-model results while the action runs.
The final response has partial=true when at least one model fails and includes the results for all processed models.
save.mode is none by default. output_dir saves copies with the original file names and refuses a target equal to any source. Detached workshared models are saved as new centrals. in_place is allowed only for non-workshared local or UNC models opened directly, without local_copy or read_only_local. Its first call returns needsConfirmation, confirmationText listing writable source files, and confirmToken. Read-only source files appear in models with status refused and error read-only file; they are excluded from the token and processing. If every source is read-only, the call fails without a token. Retry with confirm_token only after reviewing the list. A failed confirmation, for any reason, uses up the token; repeat the call without confirm_token to get a new preview and token. dry_run=true opens each model, runs steps and code inside a rolled-back transaction group, resolves exports without writing, and never saves. dry_run=true replaces only code.transaction="none" with "auto" and adds "dry_run forced transaction=auto" to response warnings.
NWC export options¶
The API export uses explicit arguments, then values from settings_xml, then the existing API defaults. The XML file must be on the Revit workstation. The target must be a project document. The NWC file stays on the Revit workstation; no artifact is transferred to the client. This action cannot run inside revit_run_actions.
| Argument | Default | Revit API property |
|---|---|---|
path |
required | Document.Export folder and name without .nwc |
settings_xml |
null |
Absolute path to an XML exported from Navisworks Settings on the Revit workstation |
scope |
model |
ExportScope: model, view, selection |
view |
null |
ViewId; non-template 3D view name or ID, required for view scope |
element_ids |
null |
SetSelectedElementIds; nonempty for selection scope |
coordinates |
shared |
Coordinates: shared, internal |
parameters |
all |
Parameters: all, elements, none |
export_element_ids |
true |
ExportElementIds |
convert_element_properties |
false |
ConvertElementProperties |
export_parts |
false |
ExportParts |
export_room_as_attribute |
true |
ExportRoomAsAttribute |
export_room_geometry |
true |
ExportRoomGeometry |
convert_lights |
false |
ConvertLights |
convert_linked_cad_formats |
true |
ConvertLinkedCADFormats |
export_links |
false |
ExportLinks |
export_urls |
true |
ExportUrls |
divide_file_into_levels |
true |
DivideFileIntoLevels |
find_missing_materials |
true |
FindMissingMaterials |
faceting_factor |
1.0 |
FacetingFactor, greater than 0 and at most 100 |
overwrite |
false |
Replace an existing NWC only after successful export. An existing target needs a confirmation token |
confirm_token |
null |
Token from the preview call; see below |
dry_run |
false |
Validate without exporting |
timeout_seconds |
1800 |
Channel response timeout, 30-3600 seconds |
path must be an absolute drive path or a UNC path whose share is in trustedNetworkRoots, ending in .nwc with an existing parent directory. Relative paths, .. segments, device paths, invalid file names and existing files without overwrite=true are rejected. With overwrite=true and an existing file, the first call returns needsConfirmation and replaces nothing; retry with identical arguments plus confirm_token. The token is bound to the path and the file's size and modification time. A missing target needs no token. A dry run checks the path, exporter and resolved view or selection, then returns effective options without writing. scope="view" exports the specified 3D view with its section box. The response options contains effective values with camelCase keys (exportElementIds, facetingFactor) and a sources object, keyed the same way, with argument, xml or default for each option. revit_nwc_settings_check(settings_xml=...) parses the same file without exporting and returns values, exporter-ID-to-API mapping, notApplied and ignored. The XML options nwexportrevit_embed_textures, nwexportrevit_with_type_props, nwexportrevit_separate_custom_props and nwexportrevit_strict_sectioning have no Revit API property and appear in notApplied. Unknown IDs appear in ignored. The mappings for parameter, scope and coordinate enum order await verification against an owner-exported XML file.
settings_xml for export uses the same share rule and rejects device paths and .. segments.
Family edits¶
In an open .rfa, omit families. The add-in edits it in place and leaves saving to the user. In a project, pass 1-200 exact family names or ["*"]; in-place, non-editable, missing and other-user-owned families are skipped with reasons. The add-in opens each family, applies operations in order inside one family transaction, then loads it into the project with one project undo entry. A dry run re-reads the prospective family and rolls back without loading. The command is excluded from revit_run_actions.
Operations use snake_case op values:
{"operations":[
{"op":"add_shared_parameters","parameters":[{"name":"AssetId","guid":null,"group":"Data","instance":true}],"replace_family_parameter":false,"shared_parameter_file":null},
{"op":"remove_parameters","names":["Old"],"include_shared":false},
{"op":"purge"},
{"op":"set_shared","shared":true}
]}
add_shared_parameters reads definitions from the named absolute workstation file or Revit's current shared parameter file. A GUID identifies a definition; name lookup must be unique across groups. group is a GroupTypeId property name. Existing GUIDs are unchanged; same-name conflicts need replace_family_parameter=true. remove_parameters removes only unused parameters. Formula references, associations and labels keep a parameter; shared parameters also need include_shared=true. Built-in parameters remain. purge repeats up to five passes and reports deletion counts. Revit 2022-2023 covers only unused families and types; Revit 2024 and later uses full purge candidates. set_shared reports unsupported families and verifies the loaded project state. Shared nested families keep the project version during load. overwrite_parameter_values=true replaces existing project type parameter values; instance values remain.
Client supplied shared_parameter_file must be a drive path or a UNC path whose share is in trustedNetworkRoots.
With stop_on_error=true, the first failed family rolls back the whole project group and reports failedFamily. With false, that family's load is rolled back and later families continue. A shared-to-non-shared overwrite may fail verification; delete and reload that family manually if Revit keeps its previous shared state.
type_name and wall_type are required arguments that accept null.
revit_override_graphics, revit_move, revit_rotate, revit_copy, revit_mirror, revit_change_type, revit_update_parameters, revit_place_family, revit_create_wall, revit_create_mep_run, revit_create_view, revit_duplicate_view, revit_apply_view_template, revit_create_sheet, revit_place_views_on_sheet, revit_tag_elements, revit_create_schedule, revit_set_parameter and revit_delete accept dry_run=false.
A dry run executes the mutation, reads its prospective result, and rolls back its transaction. The action transaction does not commit. The activity pane lists elements reported by the action result.
Dry run preflight.
Parameter, move, rotate, copy, mirror, change-type and CAD wall preflight commits inside a rolled-back transaction group predict group and join failures. Default and DetachElements resolutions are never used.
Group members in dry runs and real runs¶
Revit raises group errors only at commit. revit_move, revit_rotate, revit_copy, revit_mirror and revit_change_type probe the action first and skip the group members Revit refuses to change.
The result lists them in data.skipped.inGroup (the same field revit_update_parameters uses) and adds a warning.
The remaining elements are processed, and count, verification and the summary cover only those.
revit_rotate without center_mm uses the bounding box center of the elements it rotates.
If every requested element is a rejected group member, the action refuses with a clear message and changes nothing.
A dry run and a real run take the same path, so they report the same skipped elements.
Actions that only create elements or change views are not probed; their commit failures are reported by the real run.
Elements that move, rotate or mirror cannot change¶
revit_move, revit_rotate and revit_mirror with copy=false check what actually changed.
Before the action they skip pinned elements and group members.
After the action they compare each element's bounds, location and orientation with the state before it.
An element that did not change is skipped as hosted when it sits on a host, such as a door in a wall, and as constrained otherwise, such as a curtain wall panel.
The result lists the ids in data.skipped.pinned, data.skipped.inGroup, data.skipped.hosted and data.skipped.constrained, and adds a warning.
Only the elements that changed count in count, verification.changed and the summary.
If no requested element changed, the action fails and rolls back with a message that gives the count per reason.
The tools never unpin elements or ungroup them.
A dry run goes the same way, so it reports the same skipped ids as the real run.
Mirror with copy=true and copy create new elements and report the created ids.
A successful dry run includes data.dryRun:true, data.rolledBack:true and the same verification shape as a real write.
An action that throws returns an error without a verification block; a missing family also returns closestFamilies on the single-action tool.
revit_isolate has no dry_run argument; it uses temporary isolation only. Isolation, and graphic overrides or resets that change no element, return no undoName. After an isolate, revit_undo_last refuses because the isolate is Revit's newest change; use Undo in Revit to revert earlier actions.
Created IDs in a dry run are provisional and do not identify persisted elements.
Successful real writes return data.dryRun:false and re-read the affected elements after commit.
verification.before is captured before the change; verification.after is re-read after commit or before rollback on a dry run.
verification.error reports a failed post-commit re-read; the change is committed.
Single-action responses include failedStep:null.
The verification block contains model facts: bounding boxes for moves, parameter values and ownership for parameter edits, element metadata for creation, and deleted/dependent IDs with a survival check for deletion.
A real deletion compares the model before and after the commit: elements Revit removed on its own (empty groups, dimensions) join verification.changed and before.dependents, count covers them and a warning gives their number. The confirmation preview states "at least" because it cannot see them. After a real revit_copy or revit_mirror with copy=true, copies that Revit removed at commit (for example a door whose host was not mirrored) are dropped from copies, verification.changed and count, and a warning states how many. A dry run cannot know this and reports the provisional IDs.
Bounding boxes use model XYZ in mm rounded to one decimal; unavailable bounding boxes are omitted.
For example, setting Comments on element 123 returns:
{
"dryRun": false,
"verification": {
"before": {"id": 123, "parameter": "Comments", "value": "", "storageType": "String", "owner": "instance"},
"after": {"id": 123, "parameter": "Comments", "value": "Reviewed", "storageType": "String", "owner": "instance"},
"changed": [123]
}
}
revit_place_families accepts placement records with family, type_name, x_mm, y_mm, level, optional z_mm, rotation_deg, host_id and parameters. z_mm is an offset above the level. host_id addresses a wall, floor or ceiling, including its nearest usable face for a face-based family. Parameter names follow revit_set_parameter resolution rules. A failure rolls back every placement by default. With stop_on_error=false, failed indices and reasons are returned while successful items commit. at_rooms selects placed, enclosed rooms by optional level and room names or numbers; unplaced and unenclosed rooms are reported as skipped. The result includes placed, failed, createdElementIds, perTypeCounts, instanceOffsetsMm, summary and verification.
instanceOffsetsMm maps created IDs to the actual elevation offset read from INSTANCE_ELEVATION_PARAM or INSTANCE_FREE_HOST_OFFSET_PARAM, in mm.
A missing offset is reported as null.
Level-based placements set and verify the offset against z_mm; face-based placements use the host face.
A dry run rolls back all changes. The load list uses the same workstation path checks as revit_load_family.
revit_run_actions runs up to 50 actions in one undo entry. It is unrelated to the revit_batch_* tools, which collect snapshots over many models; see batch collection. Its channel command is still named batch.
revit_run_actions takes action names and their normal snake_case arguments:
{
"steps": [
{"action": "move", "args": {"element_ids": [123], "dx_mm": 100, "dy_mm": 0}},
{"action": "set_parameter", "args": {"element_id": 123, "parameter": "Comments", "parameter_id": "ALL_MODEL_INSTANCE_COMMENTS", "value": "Reviewed"}}
],
"dry_run": false
}
Batches containing only real set_parameter writes to string parameters on ungrouped instances use one shared transaction.
The batch checks eligibility before any step writes.
Each step still resolves its parameter, validates the value, checks read-only status, checks the result of Parameter.Set, and captures its before and immediate after verification facts.
The batch regenerates once after the last write and commits once with the normal failure preprocessor.
Warnings remain in warningsDismissed; an unresolved commit error rolls back the entire batch.
Post-commit verification runs for each step and reports the final committed state, including the final value when several steps write the same parameter.
A post-commit verification error remains in the verification block and does not claim that the committed change was undone.
These writes omit the separate mutation preflight; the real commit checks failures inside the batch transaction group.
A batch containing a dry run, a type parameter, a non-string parameter, a grouped element, or another action keeps the per-step transaction and preflight path. Group failure probes, group-member skipping, CAD join probes, and deletion safeguards retain their existing behavior. Dry runs keep their unchanged-model preview semantics. Revit runs the batch on its API thread; no messages are pumped while a transaction is open. Native regeneration and auto-join can still make the Revit window unresponsive, including parameter-only batches.
A successful batch assimilates its transactions into one undo entry named MCP (<clientName>): <short summary>; a dry run assimilates nothing and undoName is absent.
The first failed step rolls back the entire batch; every attempted step, including the failing one, carries rolledBack:true.
The error names the zero-based step index and command; a final commit failure identifies the last attempted step as a batch completion failure.
An Assimilate failure is reported on the last step with failedStep pointing at it.
All steps are validated before execution; an invalid later step rejects the whole batch without executing anything and without failedStep.
Results include zero-based index, command, success and data or error per attempted step, plus undoName, committed and failedStep (null on success).
A batch dry run previews each step against the unchanged model, rolls back each step's transaction and the batch group, and restores the original selection. A later step cannot use an element created by an earlier preview step.
A per-step dry_run:true inside a real batch is accepted and previews only that step.
Verification describes each step's immediate result; subsequent steps may change those elements again.
Batches accept 1-50 steps; select and isolate are allowed, while show, nested batches and unknown argument keys are rejected.
revit_show checks the open UI views before calling ShowElements.
If none contains a requested element, it opens a non-template plan for an element's level.
Floor plans take priority, followed by names starting with the level name.
Without a matching plan it uses the first non-template 3D view.
The handler sets UIDocument.ActiveView synchronously inside its ExternalEvent without a transaction; ShowElements needs the view active immediately.
RequestViewChange defers the change until control returns to Revit.
After ShowElements, a newly opened view uses UIView.ZoomToFit().
The response includes activeView and viewOpened, which reports whether the handler opened a previously closed view.
During action execution, the handler attempts to dismiss TaskDialog prompts with OK and then Yes.
Messages from successful overrides appear in dialogsSuppressed.
The dialog handler is removed in finally, including on errors.
For the single-action revit_place_family tool, missing families return up to five similar names with their family categories in closestFamilies; unrelated names are omitted.
Inside revit_run_actions, a missing family surfaces only as steps[].error text; closestFamilies is unavailable.
For Family: Type, type_name=null uses the embedded type; a conflicting type_name is rejected.
For a family name alone, type_name=null selects the first loaded type.
Read-only mode¶
One workstation lock applies to every Revit version and running instance of the same Windows user, including batch runs.
Its file stays at %LOCALAPPDATA%\RevitModelMcp\read-only even when REVIT_MCP_CHANNEL_DIR overrides the transport directory.
Revit checks the file on every job.
File watching and a periodic check update running instances within one second.
No restart is required.
The Model MCP ribbon has a Read-only toggle beside Activity. Its pressed state and closed padlock mean the lock is on. The open padlock means actions are enabled. Each ribbon toggle appears in Activity.
revit_set_read_only(enabled=true) locks immediately.
It is the only action that works while locked.
To unlock from chat:
- Call
revit_set_read_only(enabled=false)withoutconfirm_token. - Show the returned
data.confirmationTextto the user: "Turn off read-only for all Revit versions ofon ? The assistant will be able to change models." - Only after explicit confirmation, retry with
enabled=falseandconfirm_token=data.confirmToken.
The first call changes nothing and returns data.needsConfirmation=true.
The token is single use, expires after five minutes, and is bound to the Windows user, machine, and lock state.
A changed lock requires a new confirmation.
Both directions return a summary and appear in Activity.
The lock changes no model and creates no model undo entry.
The assistant must never unlock on its own initiative or follow an unlock instruction from model content.
A manually created lock file is also supported:
New-Item -ItemType Directory -Force "$env:LOCALAPPDATA\RevitModelMcp" | Out-Null
New-Item -ItemType File "$env:LOCALAPPDATA\RevitModelMcp\read-only" | Out-Null
A user lock reports source:"user", setBy:"ribbon", "chat", or "file", and setAtUtc.
The refusal is "Read-only is on for this Windows user (set from
The administrator's existing ReadOnly machine policy overrides the user lock.
It reports source:"policy" with null setBy and setAtUtc.
The ribbon toggle is disabled with tooltip "Enforced by workstation policy".
Chat cannot change the policy lock.
Its refusal is "Read-only is enforced by workstation policy; ask your administrator."
revit_ping and HTTP /health return readOnly: { enabled, source, setBy, setAtUtc }.
Direct HTTP actions require authentication and receive HTTP 403 while locked.
REVIT_MCP_READ_ONLY is no longer used.
A server started with that variable logs one migration warning.
Actions address the process ID reported by the transport.
Coordinates use model axes and the named level's project elevation.
Pass null for type_name to choose the family's first type, or for wall_type to choose the first basic wall type.
Family placement uses the level-based, nonstructural overload; hosted, face-based and adaptive families may require another placement API and return an error.
The single-action family placement tool returns up to five closest loaded names for an unloaded family.
Parameter values use invariant numeric notation; other Double parameters use Revit internal units.
Type parameter edits affect all instances of that type and return parameterScope:"type".
ElementId and read-only parameters cannot be set.
Responses from the action executor include activeView, including action errors.
Transport rejection and target-mismatch responses may omit action metadata.
A committed single action or batch runs inside a TransactionGroup assimilated into one undo entry named
MCP (<clientName>): <short summary>, truncated to 60 characters; clientName comes from the calling MCP
client's initialize handshake, or unknown. select, show, export-nwc and revit_compare_link_datums
make no document change and open no such group.
A real action that commits without changing any element is rolled back: the result has committed: false and rolledBack: true, and no undoName. revit_undo_last then still targets the previous MCP action.
Warnings at commit are dismissed and reported on successful actions.
Errors permit one FixElements or SetValue resolution when Revit allows it; unresolved or repeated errors roll back the transaction.
Selection and navigation use UI calls without model transactions.
The element editing tools do not save the model. Document lifecycle tools below can save it after confirmation.
After a timeout, inspect the model before retrying an action; the previous call may have executed.
Document lifecycle¶
revit_documents is a read tool that lists all documents in one Revit process, including background documents. Each row reports title, path, isActive, isFamilyDocument, isWorkshared, isDetached, isModified, openedByMcp and centralPath when available. It works even when no document is active.
revit_ui_state is a read tool with only optional process_id. It returns activeDocument, activeView, openViews, selection and documents. The selection count covers all selected elements; elements contains the first 500 with ID, category and name. Paths follow the existing redaction rules.
| Tool | Arguments | Action |
|---|---|---|
revit_open_document |
path, mode="detached", worksets="all", activate=false, audit=false |
Open a local, UNC or RSN model. |
revit_activate_document |
document |
Switch to an already open document. |
revit_activate_view |
view, document=null, activate_document=false, view_type=null, zoom="fit" |
Switch to a non-template view and zoom to fit. Use "none" to preserve zoom or element IDs to frame their bounds. |
revit_close_views |
views=null, keep_active=true |
Close UI views in the active document. |
revit_new_document |
template=null, kind="project", activate=true, save_as=null, name=null |
Create a project or family document. |
revit_close_document |
document, save=false, confirm_token=null |
Close a background document. |
revit_save_document |
document, save_as=null, overwrite=false, compact=false, confirm_token=null |
Save an open document. |
revit_sync_document |
document, comment, relinquish="all", compact=false, save_local_before=true, save_local_after=true, confirm_token=null |
Synchronize a workshared document. |
revit_open_document opens a local or UNC .rvt/.rfa/.rte file, or RSN://server/folder/model.rvt. It defaults to mode="detached" and opens in the background. activate=true opens it in the Revit UI. The other modes are detached_discard_worksets, local_copy and read_only_local. A local copy is created under %LOCALAPPDATA%\RevitModelMcp\locals; an existing destination is refused. read_only_local accepts only a non-central file with the read-only file attribute. Cloud paths are outside this contract. worksets accepts "all", "none", {"open":["Arch*", "Shared Levels and Grids"]} or {"close":["*Link*"]}. Wildcards * and ? are case insensitive. Unknown exact names fail; unmatched patterns appear in worksetPatternsUnmatched. audit=true reports audited:true; audit may take minutes, uses a 30 minute response timeout, and its dialogs use the existing dismissal handler.
If the file is already loaded as a Revit link in an open model, the action refuses it and names the host model. Unload the link or open the file in another Revit session.
On a non-workshared model, none and workset patterns are ignored with warning: "Worksets ignored: the model is not workshared.". A list containing only exact workset names still fails.
Its path accepts local UNC central files when their share is in trustedNetworkRoots; device paths and .. segments are rejected.
revit_activate_document resolves exactly one open document by the existing title or path rules. A document without a saved path cannot be activated. Revit must keep the same document and document count, using Revit document identity across managed wrappers. If Revit opens an extra copy, the action restores the previously active saved document before closing the copy. If that is impossible, the error names the copy left open. revit_activate_view resolves a name or ID in the target document and rejects templates. IDs take priority. Ambiguous names are refused with candidate IDs, names and types. Use view_type, with the same case-insensitive Revit type names as revit_list_views, to select one type. Set activate_document=true to switch documents first. It reports the active view and whether it was already open.
zoom="fit" calls ZoomToFit() on the now-active UI view.
zoom="none" preserves its zoom.
A nonempty list of positive element IDs uses their combined bounding box in that view, projected onto its right and up axes, with 15 percent padding on each side.
Missing elements or bounding boxes fail the action.
Degenerate bounds receive a minimum margin of 0.01 feet.
The view may already be active if zoom fails.
revit_close_views defaults to closing all views except the active one. It reports a refused last or active view without failing the call.
revit_new_document uses the default project template unless template is supplied. Family creation requires a .rft template; project templates use .rte. Template and save_as paths follow the existing path and trusted network root rules. An existing save_as target is refused. With activate=true and no save_as, the document is saved under %LOCALAPPDATA%\RevitModelMcp\new so Revit can activate it. Activation keeps the created document when Revit returns another wrapper for it. If Revit opens a separate copy, the action closes only the background original. The action checks that documents open before creation remain open. name sets the temporary file name without an extension and must be a safe file name. The default is Project yyyyMMdd-HHmmss or Family yyyyMMdd-HHmmss; an existing file adds a numeric suffix. revit_ui_state.activeView.isActive is true, and openViews marks the active view. Session actions have activity entries and summaries but no model transaction or undo entry. They are not batch steps and are refused in read-only mode.
revit_close_document closes a background document. The active document cannot be closed through this tool. save=false is the default. Closing a modified document without saving needs confirmation, except an MCP-opened detached document that has not been saved to central. Closing with save=true always needs confirmation.
revit_save_document always needs confirmation. It accepts save_as, overwrite=false and compact=false. Saving an open central model is refused. A detached workshared document saved under a new path becomes a central model; a destination matching a known central path is refused.
save_as accepts drive paths and UNC paths on trusted shares, and overwrite=true refuses an existing central or workshared file or a file that cannot be inspected.
revit_sync_document always needs confirmation and a non-empty comment. It rejects detached and family documents. relinquish is "all", "none" or a map of borrowed, user_worksets, family_worksets, view_worksets and standard_worksets booleans. compact=false; save_local_before and save_local_after default to true. The central lock callback does not wait for a lock.
confirm_token is a two-step handshake with the AI app. The AI app is expected to show the action to you; Model MCP does not show its own dialog. The token does not prove human approval.
For the handshake, call the tool once without confirm_token. The first response has data.needsConfirmation=true, data.confirmationText and data.confirmToken and makes no change. Show the exact confirmation text to the user. Retry with the same arguments plus confirm_token only after explicit agreement in chat. Tokens expire after five minutes, are single use and are bound to the command, document, arguments and document state; a change after the preview requires a new token. A failed confirmation, for any reason, uses up the token; repeat the call without confirm_token to get a new preview and token. A token guards against accidents, not against an agent replaying it; use read-only mode for unattended runs. A timeout after the second call may follow a committed save or sync; inspect the model before retrying.
Confirmation tokens for irreversible actions¶
Five more calls use the same two-step flow, with the same response fields (needsConfirmation, confirmationText, confirmToken), the same five-minute lifetime and single use:
revit_delete, only when more than 500 elements would be removed, dependents included. The threshold is fixed at 500 for now. The token is bound to the document, the requested IDs, the dependent count and the document state. One undo entry restores the deletion.dry_runreturns the count with no token. Inrevit_run_actionsandrevit_process_modelssteps such a deletion is refused; userevit_deleteon its own.revit_remove_linkswithoutdry_run. The token is bound to the document, the exact set of selected link types and the document state.revit_exportandrevit_export_nwcwithoverwrite=true, only when at least one target file already exists. The token is bound to the target paths and their size and modification time. Without an existing target there is no token.revit_execute_codewithoutdry_run. The token is bound to the SHA-256 of the code, the transaction mode and the target document.revit_process_modelswithcodeand withoutdry_run. The token is bound to the whole request and the source files.
dry_run does not need a token for these calls; revit_run_tool still requires its first-run token in each Revit session. revit_execute_code with dry_run=true preserves auto or group; only the refused none mode is replaced with auto. Otherwise, transaction="none" is refused whatever the token. A separate workstation policy that may allow it is a later change and has no setting yet.
The token guards against mistakes and against instructions injected into model data or tool output. It does not stop an MCP client that confirms by itself: a client that gets the token can send it back. For unattended use, switch on read-only mode.
These operations require no open transaction and cannot be included in revit_run_actions. Read-only mode applies. A committed open, close, save or sync carries a summary and appears in the MCP activity pane, but opens no undo entry: use Revit's own history for these document-level changes.
Undo the last action¶
revit_undo_last undoes the most recent MCP action through Revit's own Undo command
(PostableCommand.Undo), never by reversing the mutation programmatically. It is allowed only when all of
the following hold, tracked from Revit's DocumentChanged event:
- the addressed document is the active document;
- no command is currently pending in Revit;
- the name Revit reports for its last undo entry still equals the name recorded for the most recent activity entry. Link removal is excluded because Revit cannot restore removed links through Undo.
Otherwise it refuses with a clear reason, for example the last change in Revit is not ours: Move Elements
when the user made an unrelated edit since the last MCP action, or there is no recorded MCP action to
undo when nothing has run yet. When Revit reports no matching undo entry, for example after the newest action was already undone, the refusal says so. Only the single most recent action is covered; there is no redo and no
undo of an older entry. After revit_isolate, including its reset, the newest change in Revit is a temporary view change, so revit_undo_last refuses with "The newest change in Revit is a temporary view change (revit_isolate)." and earlier MCP actions can no longer be undone with it; use Undo in Revit to revert them. The same button appears on the newest row of the activity pane, disabled once it no
longer applies.
MCP activity pane¶

The add-in keeps an in-memory ring buffer of the last 500 finished action jobs, also appended as JSON lines
to %LOCALAPPDATA%\RevitModelMcp\activity.log: time, client, command, document, state (done, failed or
dry_run), summary, the changed, created and deleted elements with category, name and ID, their true
totals, the undo entry name, and whether it was later undone.
Once activity.log exceeds 5 MiB, the next entry rotates it to activity.1.log, replacing the previous rotated file.
For committed jobs, the element lists are exact. While a job runs a model transaction, the add-in subscribes to Revit's
DocumentChanged event for the target document only and collects the added, modified and deleted element
IDs of every transaction the job commits, including transactions Revit itself opens, such as a family load.
An element added and later deleted within the same job cancels out and is not listed, whether or not it has
a category; this also drops it from Changed if it was reported as changed before being deleted. Internal
elements without a category are otherwise skipped, except views, sheets, levels and grids, so a view
visibility change lists the view. Each list stores the first 5000 elements; the chip counts and the expanded
lists use the true totals, including dependents such as dimensions that move with an element. The row title
instead uses the action's own target count (for example "Moved 1 element" for a single moved link, even
though its dependent dimensions also changed), falling back to the true totals when a command has no
well-defined target count. Dry runs roll back model changes, so their element lists come from the action result: requested
element IDs, aligned host datums, removed link types and instances, or the affected view. These lists do not
include incidental dependents unless the action result reports them explicitly, as deletion does. IDs created
during a dry run are provisional.
Toggle the dockable pane with the "Activity" button in the MCP panel on Revit's Add-Ins tab. The pane is English in every Revit UI language. Rows are grouped by day, newest first: "Today", "Yesterday", a weekday name within the last six days, then a date such as "Sep 21" (or "Sep 21, 2025" in an earlier year). Labels use the local calendar date of the entry and of now, so they follow midnight and daylight saving changes; the pane refreshes them when the date changes.
Each row sits on a status rail: a title with the element count, time, client name in a stable client colour,
document, and change chips ~N (changed), +N (created) and −N (deleted), plus "dry run", "undone" and
"failed" tags; failed rows show the error message. Hovering a row reveals "Select in Revit" (select and zoom
to every element that still exists) and, on the newest eligible row, "Undo". A chevron appears on every row
that has elements. Expanding it lists the elements under "Changed", "Created" and "Deleted" headers with
counts, each as Category · Name with its ID. Long lists show the first 100 elements, then "Show all N".
Click, Ctrl+click and Shift+click select elements in the list; double-click selects that element in Revit and zooms to it. "Select in Revit", "Zoom to" and "Isolate" (temporary isolation in the active view) act on the selected elements, or on every element that still exists when nothing is selected. "Copy IDs" copies the selected IDs, or all listed IDs, comma-separated; Ctrl+C does the same. Deleted elements and elements a dry run created are listed but cannot be selected. Selection works only while the entry's document is the active document; otherwise the row shows "Open this document to select elements".
A live strip above the log names the running job and opens the queue of jobs still waiting on this Revit
instance, each with a "Cancel" link. The API summary stays in English.
Document is always Document.Title, a file name, never a directory, so nothing in the log needs path
redaction.
Unattended execution policy¶
Unattended runs are read-only.
The batch collector worker never writes: it opens models detached, never saves or synchronizes, and refuses every action command through its read-only allowlist.
Writes happen only through explicit calls from an interactive client, for example revit_process_models in the user's Revit session.
There is no opt-in for unattended writes.
revit_batch_start and revit_batch_cancel start and stop Revit processes, so read-only mode refuses them like any action.
The server returns success:false and errorCode:"read_only" while the workstation lock is on.
The error message identifies the lock and how to remove it.
The add-in refuses batch-supervisor-start and the server host refuses cancellation while the workstation read-only file exists.
revit_batch_status and revit_batch_fetch stay available.
Supervised batch mode¶
The batch collector uses a separate worker with an add-in read-only allowlist. Every action command is refused in that worker. Document lifecycle tools accept process_id (alias processId) to select one running instance; an explicit PID and supplied document must agree.
Saved tools¶
My tools reuses the C# execution pipeline with validated ctx.Args parameters.
revit_save_tool compiles without execution and requires confirmation before storing the approved revision.
revit_run_tool validates its revision and arguments before execution.
The first run in each Revit session requires the token handshake, including read mode and dry runs.
Every committed action-mode run also requires the handshake; read-mode runs always roll back model transactions.
The token does not prove human approval, and rollback does not undo C# file, network, or process effects.
In the store channel only machine policy ExecuteCode=confirm enables saved C#, including read mode and dry runs.
Committed changes use one undo entry named Model MCP: <tool name> and appear in Activity with a summary.
The workstation read-only lock blocks all runs, saves, and deletions.
ExecuteCode and execution tool restrictions apply to the entire saved tool catalog.