openstudio-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@openstudio-mcpCreate an example model and tell me about it"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
OpenStudio®-MCP SWR 26-035
Model Context Protocol server for OpenStudio building energy simulation. It lets MCP hosts — Claude Desktop, Claude Code, Codex, VS Code — create, query, and modify OpenStudio models, run EnergyPlus, and read results, all in plain language. The server handles the OpenStudio/EnergyPlus complexity behind MCP tool calls.
150+ tools · bundled workflow skills · 500+ integration tests
Published in SoftwareX — see Cite this work.
Contents
Related MCP server: ladybug-tools-mcp
What you can ask for
"Create a 10-zone office with VAV reheat and run an annual simulation."
"What's the EUI? Show me the unmet heating hours."
"Switch the HVAC from VAV to VRF heat pumps and compare energy use."
"Add R-30 roof insulation and see how it affects the cooling load."
"Build two adjacent zones from floor plans, match the shared wall, add 40% south glazing."
"Write a measure that sets all lights to 8 W/m², test it, apply it, and compare the EUI."
"Submit this OpenStudio analysis JSON to my server, wait for completion, and download the results"
"Apply the AEDG Small Office measure from my local measures directory"
The AI picks the right tools, calls them in sequence, and summarizes — no scripting.
Quick start (local)
Runs the server locally over stdio — one container per user, launched by your MCP host. For a shared deployment, see Remote & multi-user.
Prerequisites: Docker Desktop running, and an MCP host (Claude Desktop is the easiest start).
1. Get the image
Option A: Pull from Docker Hub (no checkout needed)
docker pull nrel/openstudio-mcp:v1.2.1Tags on nrel/openstudio-mcp:
Tag | What it is |
| A tagged release. Pin one of these for reproducible work |
| Latest |
Every tag is a multi-arch manifest (amd64 + arm64), so the same docker pull works on Intel/AMD and Apple Silicon.
Option B: Build locally (for development, or to run unreleased changes)
git clone https://github.com/NatLabRockies/openstudio-mcp.git
cd openstudio-mcpMachine | Build command |
Intel/AMD (Linux, Windows, Intel Mac) |
|
Apple Silicon (M-series) |
|
Both produce a local image tagged openstudio-mcp:dev. The arm64 Dockerfile builds natively from NREL's arm64 .deb (the upstream nrel/openstudio base is amd64-only, so plain Dockerfile runs under slow emulation on Apple Silicon).
Remember your image name. Step 2 uses openstudio-mcp:dev (the local build). If you pulled instead, substitute nrel/openstudio-mcp:v1.2.1 (or whichever tag you pulled) wherever openstudio-mcp:dev appears.
2. Configure your host
Pick three host folders first: one with your models (mounted read-only at /inputs), one for simulation output (/runs), and one for measures you author or download (/measures). Create them if they don't exist. In the snippets below they are /path/to/models, /path/to/runs, and /path/to/measures; replace them with absolute paths.
Option A: Claude Desktop (JSON)
Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows), then restart Claude Desktop.
{
"mcpServers": {
"openstudio-mcp": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"-v", "/path/to/models:/inputs:ro",
"-v", "/path/to/runs:/runs",
"-v", "/path/to/measures:/measures",
"-e", "OPENSTUDIO_MCP_MODE=prod",
"openstudio-mcp:dev", "openstudio-mcp"
]
}
}
}Option B: Codex & other clients (TOML)
Add to your client config (e.g., ~/.codex/config.toml on macOS/Linux, %USERPROFILE%\.codex\config.toml on Windows).
[mcp_servers.openstudio-mcp]
command = "docker"
startup_timeout_sec = 120
args = [
"run", "--rm", "-i",
"-v", "/path/to/models:/inputs:ro",
"-v", "/path/to/runs:/runs",
"-v", "/path/to/measures:/measures",
"-e", "OPENSTUDIO_MCP_MODE=prod",
"openstudio-mcp:dev", "openstudio-mcp"
]Image name: the second-to-last argument (openstudio-mcp:dev) must match the image from step 1. If you pulled from Docker Hub, change it to nrel/openstudio-mcp:v1.2.1 (or the tag you pulled). Otherwise Docker fails with Unable to find image 'openstudio-mcp:dev'.
Mounts: each -v host:container line shares a host folder with the container. The container is discarded on exit (--rm), so anything you want to keep must live on a mount:
Container path | Host folder | Why |
| your models, weather files, gbXML, error files | The AI can only open files it can see. Put a file here and refer to it as |
| simulation output | Every run writes to |
| authored + BCL measures |
|
Use absolute paths. On Windows, use forward slashes in Docker args:
"-v", "C:/Users/you/models:/inputs:ro",
"-v", "C:/Users/you/openstudio-runs:/runs",
"-v", "C:/Users/you/openstudio-measures:/measures",Restart your client after saving the config file.
3. Verify and chat
Open your host's tools menu (in Claude Desktop, the tools/connectors button under the prompt box) and confirm the openstudio-mcp server is listed with its tools. Then try these prompts in order of complexity:
Simple: "Create an example model and tell me about it"
Medium: "Create a baseline office with ASHRAE System 3 and show me the HVAC components"
Advanced: "Load my model at /inputs/MyBuilding.osm, apply the 90.1-2019 typical building template, and run a simulation"
The AI reads your prompt, picks the right tools from the 150+ available, calls them in sequence, and summarizes the results, no scripting required.
Working with Your Own Files
Place files in the host folder mapped to /inputs (see step 2) rather than uploading them (drag-and-drop or attach) through the web or desktop chat interface. Uploads never reach the MCP tools; mounted files do.
# Example: analyzing an EnergyPlus error file in an AI-chat session
# 1. Copy to the host folder mounted at /inputs
cp eplusout.err /path/to/models/
# 2. Reference by MCP path in your prompt
"Analyze the warnings in /inputs/eplusout.err and create a measure to fix them"Why not upload? Attaching a file to the chat (drag-and-drop, the paperclip button, or paste) only gives the AI the file's contents in the conversation. It never lands on disk inside the Docker container, so MCP tools like load_osm_model can't open it, and the AI may fall back to writing scripts instead of using the 150+ MCP tools. A file in the /inputs mount is on disk where the tools can read it. Simulation outputs (results, SQL, HTML reports) are already under /runs and need no copying.
Client Compatibility
Any MCP host can launch the same docker run command. See the MCP documentation for host-specific config locations (VS Code Copilot, Claude Code, Codex, Windsurf, Gemini CLI).
Client | Status | Notes |
Claude Desktop | Full support | All tools available |
Claude Code | Full support | ToolSearch auto-defers tools for efficient discovery |
Codex | Compatible | MCP client via config |
VS Code Copilot | Compatible | MCP support via config |
Windsurf | Compatible | Host tool cap is ~100; use includeTools/excludeTools to limit the exposed tool set |
Gemini CLI | Compatible | Use includeTools/excludeTools if needed |
OpenAI API | Compatible | Use defer_loading for best results |
Remote & multi-user (HTTP)
The quick start runs one container per user over stdio. To host it on one machine and let teammates connect from their own laptops — each with an isolated session, run directory, and optional bearer-token or JWT auth — run it over streamable HTTP (-e MCP_TRANSPORT=http). Works with Claude Code, VS Code, and any host that supports streamable-HTTP MCP servers.
Since a remote server can't see files on your laptop, the file_transfer tools (request_upload / get_upload / request_download) move models, weather files, and measure .zips in and out over a signed, out-of-band channel — see docs/remote-multi-user.md §6.
See docs/remote-multi-user.md for setup, auth, the isolation model, and log access — and docs/run-retention.md for optional disk garbage-collection.
Security and simulation sandbox
OpenStudio measures are Ruby or Python programs and must be treated as untrusted
code. EnergyPlus workflows can also invoke measure code. Docker isolates the
container from the host, while openstudio-mcp adds a second sandbox around the
child processes used by apply_measure, test_measure, measure metadata
refresh, and simulations.
The default OSMCP_SANDBOX=auto mode provides the following controls on Linux,
including Docker Desktop's Linux VM:
Privilege drop: child processes run as the image's unprivileged
sandboxuser (UID/GID 1001), while the MCP server retains only the privileges needed to prepare run directories.Filesystem policy: Landlock denies filesystem access by default. The current run or staged measure directory is writable; required system and OpenStudio directories are read-only.
/repo,/inputs, and other users' run directories are not exposed to measure code.Network policy: seccomp denies outbound IP networking by default.
Secret isolation: child processes receive an allowlisted environment instead of inheriting API keys, tokens, and other server environment variables.
Process hardening:
no_new_privsprevents privilege recovery through setuid executables. Resource limits constrain generated file size and process count, and simulations have a wall-clock timeout.Staging: input models, weather files, measures, and OSWs are copied into a private run directory before execution. Escaping symlinks are rejected.
On Linux, auto fails closed if Landlock or the seccomp network filter cannot
be installed: the untrusted child process does not run. On native macOS or
Windows without Docker, kernel confinement is unavailable and the server warns
that only environment filtering is active. Use the Docker image when running
untrusted measures.
Sandbox options
Variable | Default | Behavior |
|
|
|
|
|
|
|
| Account used for confined child processes. Values less than 1 are rejected. The default matches the |
|
| Maximum size in bytes of one file created by a child process. |
|
| Maximum processes/threads for the sandbox UID. |
|
| Optional open-file descriptor limit. |
|
| Optional CPU-seconds limit. Disabled by default because annual simulations can be long-running. |
|
| Optional virtual-memory limit. Prefer Docker memory limits because restrictive address-space limits can break EnergyPlus. |
|
| Wall-clock timeout for a simulation. |
Secure deployment guidance
Mount
/inputsread-only:-v /host/inputs:/inputs:ro.Mount only the output directory at
/runs; any process allowed to write/runscan modify that host directory by design.Do not mount the repository, home directory, Docker socket, credentials, or broad host paths into production containers. The
/reposource mount in the testing commands is for development only.Keep
OSMCP_SANDBOX=autoandOSMCP_SANDBOX_NET=denyfor untrusted measure authoring. Docker's--network nonecan provide an additional container-wide network boundary when remote access is not required.Use Docker CPU, memory, PID, and disk quotas as outer limits. The in-process resource limits are defense in depth, not replacements for container limits.
The sandbox protects the host and other run directories, but it intentionally allows measure code to modify its own staged run directory. Treat resulting OSM, SQL, report, and log files as untrusted outputs.
Skills & Tools (150+ total)
In Claude Code, the bundled skills add workflow automation and domain knowledge:
Skill | Type | What it does |
| Workflow | one-command simulate + results extraction |
| Workflow | comprehensive multi-category energy report |
| Workflow | full model creation from scratch |
| Workflow | before/after ECM analysis |
| Task | guided HVAC system selection |
| Task | pre-simulation model quality check |
| Task | quick 3D model visualization |
| Task | diagnose simulation failures |
| Knowledge | measure creation, SDK verification, wiring patterns |
| Knowledge | ASHRAE 90.1 system selection |
| Knowledge | tool dependencies and model relationships |
| Knowledge | multi-tool recipes for common operations |
| Task | attribute standards space types to conditioned spaces (post-gbXML) |
| Task | Revit gbXML import + geometry-defect repair workflow |
| Task | OpenStudio Analysis Framework workflow: algorithm selection, validation, submission |
| Task | custom EnergyPlus Python Plugin control/reporting logic (EMS) |
| Task | move files to/from a remote server (signed upload/download URLs) |
Workflow/task skills are invoked with /name; knowledge skills load automatically. Any MCP host can also discover these guides via the list_skills() and get_skill(name) tools (baked into the image at /skills).
Tool reference
150+ tools, grouped by area — expand a group to see its tools. New here? create_new_building, run_simulation, and extract_summary_metrics cover most workflows; list_skills() and recommend_tools(task) help the AI find the rest.
Tool | Description |
| Create a complete building end-to-end (geometry + weather + typical template) |
| Create bar-building geometry from type, floor area, aspect ratio |
| Add constructions, loads, HVAC, SWH to a model with geometry |
| Minimal single-zone example (testing/demos) |
| 10-zone baseline with ASHRAE system 1–10 (testing/demos) |
| Quick structural summary of an OSM file |
| Load OSM into memory for querying/editing |
| Save the in-memory model to disk |
| Discover files in /inputs and /runs |
| Building name, area, volume, orientation |
| Object counts by category |
| Delete any named object (28+ types) |
| Rename any named object |
Read/write any OpenStudio object by introspection — covers types without a dedicated tool.
Tool | Description |
| List objects of any type (CamelCase, IDD colon, or underscore) |
| Read all properties of an object — returns values + available setters |
| Write any property via official setters — auto-coerces types |
Tool | Description |
| List spaces with area/volume |
| Surfaces, loads, zone for a space |
| List thermal zones with spaces |
| Zone equipment, thermostat, multiplier |
| Create a space (optional story/space type) |
| Create a thermal zone, assign spaces |
Tool | Description |
| List surfaces (walls, floors, roofs) |
| Vertices, construction, boundary |
| List windows, doors, skylights |
| Create a surface from explicit 3D vertices |
| Create a window/door on a parent surface |
| Extrude a floor polygon into a space with all surfaces |
| Intersect + match shared walls between adjacent spaces |
| Add a centered window by glazing ratio |
| Import geometry from a FloorSpaceJS JSON file |
| Synthesize a RoofCeiling for spaces with a floor but no ceiling |
| Set the outside boundary condition on a batch of named surfaces |
| Snap near-coincident vertices to a shared point, closing corner gaps |
| Merge same-space coplanar fragments into fewer, larger surfaces |
| Trim same-space surfaces with a genuine 2D overlap to their remainder |
| Reconstruct a space's missing surfaces from unpaired polyhedron edges |
Revit gbXML → OSM translation and geometry-defect repair. See examples 21, 22.
Tool | Description |
| Translate a Revit-exported gbXML file into an OpenStudio model |
| Check for surface overlaps and non-enclosed space volumes, optionally repair |
List constructions/sets via list_model_objects("Construction") / ("DefaultConstructionSet").
Tool | Description |
| Materials with thermal properties |
| Construction layers with thermal properties |
| Material with conductivity/density |
| Layered construction from materials |
| Assign a construction to a surface |
| Add a material layer to an existing construction (copies it) |
List schedules via list_model_objects("ScheduleRuleset").
Tool | Description |
| Schedule type, values, rules |
| Constant schedule (Fractional/Temp/OnOff) |
List loads via list_model_objects("People"), ("Lights"), etc.; use get_object_fields for definitions.
Tool | Description |
| Detailed info for any load by name |
| People load (by area or count) |
| Lighting load (by area or wattage) |
| Electric equipment load |
| Gas equipment load |
| Infiltration (by area or ACH) |
List space types via list_model_objects("SpaceType").
Tool | Description |
| Space-type loads, schedules, standards |
| One standards combo -> every conditioned space, one call |
| Scan conditioned spaces, start the multi-turn assignment wizard |
| Narrow the wizard to one or more standards templates |
| Narrow to building types, show the remaining space table |
| Wizard progress + a page of the remaining space table |
| Assign one standards combo to a batch of space indices |
| Save the model and end the wizard |
| Abandon wizard tracking (does not undo assignments) |
Tool | Description |
| Air loops with zones served |
| Air-loop components, sizing, OA system |
| Create an air loop and connect zones |
| Plant loops (heating, cooling, condenser) |
| Plant-loop supply/demand components |
| Zone-level HVAC equipment |
| Zone equipment details |
Tool | Description |
| ASHRAE 90.1 baseline system (types 1–10) |
| All baseline + modern template types |
| Metadata for a specific system type |
| Replace ALL terminals on an air loop |
| Replace the terminal on a single zone |
| DOAS with fan coils, radiant, or chilled beams |
| VRF multi-zone heat-pump system |
| Low-temperature radiant heating/cooling |
List components via list_model_objects("BoilerHotWater"), loop detail tools, etc. Covers 15 component types (see reference).
Tool | Description |
| Read all properties of a named component |
| Modify properties on a named component |
| OA economizer settings on an air loop |
| Plant-loop sizing (exit temp, delta-T) |
| Air-loop SizingSystem (SAT, OA, flow methods) |
| Read all SizingSystem properties |
| SizingZone properties (supports zone lists) |
| Read all SizingZone properties |
| Read SPM properties (7 types) |
| Modify SPM properties (7 types) |
Tool | Description |
| Plant loop with pump, bypass, SPM |
| Add boiler/chiller/tower to supply side |
| Remove supply-side equipment |
| Add coil/heater to the demand side |
| Remove a demand-side component |
| Add a coil or fan to an air loop's supply branch (append or insert before/after) |
| Remove a coil or fan from an air loop, keeping its setpoint managers |
| Swap a coil or fan in place (add-first order, avoids the SDK segfault) |
| Put one of 7 setpoint manager types on a loop node; refuses silent same-control-variable collisions |
| Delete a setpoint manager; warns when a loop outlet loses temperature control |
| Add baseboard/unit heater to a zone |
| Remove zone equipment |
| Batch-remove all equipment from zones |
| Reorder zone cooling/heating priority |
Tool | Description |
| Available EPW files (with .stat/.ddy) |
| City, lat, lon, timezone from a weather file |
| Add a heating/cooling design day |
| Read sizing flags and timesteps/hour |
| Modify sizing flags and/or timestep |
| Read run-period dates |
| Set run-period dates |
Tool | Description |
| Run a simulation from an OSM + optional EPW |
| Run EnergyPlus from an OSW file |
| Validate an OSW workflow file |
| Pre-sim check: weather, design days, HVAC, constructions |
| Poll run status |
| Tail simulation logs |
| List output files |
| Cancel a running simulation |
| Add an EnergyPlus output variable |
| Add an EnergyPlus output meter |
Reclaim disk from old run directories. See docs/run-retention.md.
Tool | Description |
| Delete old run dirs you own (preview with |
| Delete one of your run directories |
| Protect a run from automatic cleanup |
| Allow a pinned run to be cleaned up again |
Move files between your machine and a remote server over signed, one-time URLs. See Remote & multi-user.
Tool | Description |
| Get a one-time URL to upload a local file to the server |
| Check an upload's status and get its server-side path |
| List your uploaded files |
| Delete an uploaded file and free its quota |
| Get a one-time URL to download a server file to your machine |
OSA JSON validation blocks DOE analyses with fewer than two measure variables
and, by default, requires the foundational view_model, openstudio_results,
and generic_qaqc measures in the workflow. Package validation also requires
those measures in the support ZIP. Use single_run for a single datapoint, a
schema-supported sampling type such as lhs for one-variable sampling, or add
another real variable before choosing DOE. OSAF's DOE runner accepts a
one-variable payload but later fails during analysis startup.
Tool | Description |
| Create an OpenStudio Server OSA JSON file |
| Validate an OSA JSON file locally |
| Return the foundational output variables used by generated OSA JSON |
| Return the common measures appended to generated OSA workflows |
| Simulate/reuse a seed run and write seed QA/QC evidence before packaging |
| Create an OSAF support ZIP only after seed simulation QA/QC passes |
| Create OSA JSON from measure directories, static arguments, and variable parameters |
| Add a measure step and optional algorithm variables to an existing OSA JSON workflow |
| Create an OpenStudio Server project |
| Submit OSA JSON and optional support ZIP to a project |
| Check analysis status |
| Start an existing analysis with OSAF's action endpoint |
| Poll analysis status until completion/failure/timeout |
| Check server health, submit a single_run smoke test, and run one datapoint |
| Download exported analysis data |
| Fetch analysis result data as JSON |
| Submit analysis, wait for completion, and download results |
| List OSAF analysis algorithms and when to use them |
| Validate an OSAF analysis support ZIP before upload |
| Start a sampled analysis in the required OSAF order |
Tool | Description |
| EUI, energy, unmet hours |
| Energy by end use and fuel (IP/SI) |
| Opaque + fenestration U-values and areas |
| Autosized zone/system HVAC capacities |
| Per-zone areas, conditions, multipliers |
| Autosized component values (filterable) |
| Time-series output data with date/cap filters |
| Parse eplusout.err into Fatal/Severe/Warning |
| Output variables from a completed run |
| Compare two runs: EUI delta + end-use breakdown |
| Read any file by absolute path (mounts only) |
| Copy a file to a host-mounted path |
Find, download, and apply bundled/BCL measures, or write/test/apply custom ones. See examples 1, 2, 19.
Tool | Description |
| Discover mounted, downloaded, bundled, and custom OpenStudio measures |
| Find a measure locally first, then BCL; download a strong BCL match |
| Search BCL measure candidates without downloading |
| Download and extract a measure ZIP into your per-user BCL cache ( |
| List ~61 bundled ComStock measures |
| List a measure's arguments, defaults, choices |
| Apply an OpenStudio measure to the in-memory model |
| Create a custom Ruby/Python ModelMeasure |
| Edit a custom measure's code or arguments |
| Run a custom measure's tests (auto-detects language) |
| List custom measures you've created |
Custom EnergyPlus Python Plugin control/reporting logic. See example 20.
Tool | Description |
| Discover valid EMS actuators (component, control type, key) for the loaded model |
| Add a Python EMS plugin (control or reporting) to the model |
| List the model's Python plugins or inspect one by name |
| Replace an existing plugin's script source |
| Install Python packages (e.g. numpy) for use inside plugins |
Typed wrappers over ~79 bundled common measures (reporting, envelope, renewables, visualization, cleanup).
Tool | Description |
| List bundled measures by category |
| Interactive 3D Three.js viewer of geometry |
| 3D viewer with simulation data on surfaces |
| ~25-section HTML report |
| ASHRAE baseline QA/QC checks |
| Shift heating/cooling setpoints |
| Bulk-replace exterior window constructions |
| Ideal air loads on all zones (quick sizing) |
| Remove orphan/unused objects |
| Set weather + climate zone + design days |
| Apply thermostat schedules from a library |
| Replace existing thermostat schedules |
| Shift schedule profiles by hours |
| Add rooftop PV panels |
| Add PV to shading surfaces |
| Add EV charging load |
| Add zone ventilation design flow |
| Set lifecycle-cost parameters |
| Add cost per floor area |
| Set walls/floors adiabatic |
Tool | Description |
| List available workflow guides |
| Step-by-step instructions for a workflow |
| Fetch a supporting file advertised by |
| Recommend the relevant tool group for a task |
| Look up OpenStudio SDK classes + methods (verify before calling) |
| Ruby wiring recipes for HVAC, plus SDK crash hazards for remove/addToNode queries |
| Server health check |
| OpenStudio, EnergyPlus, Ruby versions |
Reference
ASHRAE baseline systems
All 10 ASHRAE 90.1 Appendix G baseline systems via add_baseline_system, plus modern templates DOAS, VRF, Radiant.
# | Type | Description |
1 | PTAC | Packaged terminal AC (zone-level) |
2 | PTHP | Packaged terminal heat pump (zone-level) |
3 | PSZ-AC | Packaged single-zone rooftop AC |
4 | PSZ-HP | Packaged single-zone heat pump |
5 | Packaged VAV w/ Reheat | VAV with hot-water reheat |
6 | Packaged VAV w/ PFP Boxes | VAV with parallel fan-powered boxes |
7 | VAV w/ Reheat | Central VAV, chiller + boiler + tower |
8 | VAV w/ PFP Boxes | Central VAV, parallel fan-powered terminals |
9 | Gas Unit Heater | Heating-only (warehouses, garages) |
10 | Electric Unit Heater | Heating-only, electric |
HVAC component types
The component-properties tools query/modify these 15 types:
Category | Components |
Coils | CoilHeatingGas, CoilHeatingElectric, CoilHeatingWater, CoilCoolingWater, CoilCoolingDXSingleSpeed, CoilCoolingDXTwoSpeed, CoilHeatingDXSingleSpeed |
Plant | BoilerHotWater, ChillerElectricEIR, CoolingTowerSingleSpeed |
Fans | FanConstantVolume, FanVariableVolume, FanOnOff |
Pumps | PumpConstantSpeed, PumpVariableSpeed |
Examples
24 worked examples with full tool-call sequences:
# | Example | # | Example |
1 | 12 | ||
2 | 13 | ||
3 | 14 | ||
4 | 15 | ||
5 | 16 | ||
6 | 17 | ||
7 | 18 | ||
8 | 19 | ||
9 | 20 | ||
10 | 21 | ||
11 | 22 | ||
23 | 24 |
Testing
Full guide — framework, annotated examples, CI shards, writing tests — in docs/testing/.
# Unit tests (no Docker)
pytest tests/test_skill_registration.py -v
# Integration tests (Docker)
docker build -t openstudio-mcp:dev -f docker/Dockerfile .
docker run --rm -v "$PWD:/repo" -v "$PWD/runs:/runs" \
-e RUN_OPENSTUDIO_INTEGRATION=1 -e MCP_SERVER_CMD=openstudio-mcp \
openstudio-mcp:dev bash -lc 'cd /repo && pytest -vv -s tests/'Linting and formatting (uv + pre-commit)
CI runs the same pre-commit hooks (.github/workflows/format_and_lint.yml).
# Install dev dependencies with uv
uv pip install -e ".[dev]"
# Run the pre-commit hooks locally
uv run pre-commit run --all-filesArchitecture
Transport: stdio (default) or streamable HTTP for remote/multi-user
Protocol: MCP (JSON-RPC); in stdio prod mode, stdout is reserved for JSON-RPC and logs go to stderr
Skills: 30+ skill modules under
mcp_server/skills/<name>/, each withtools.py(MCP registration) +operations.py(business logic); they auto-registerState: per-session in-memory model via
model_manager; runs under/runs/<run_id>/(or/runs/<user>/<run_id>/in HTTP mode)
Set OPENSTUDIO_MCP_MODE=prod for MCP hosts (quiet logs, no banner). Full system diagram, security analysis, and hardening notes: docs/architecture.md.
Contributing
New MCP skill
Create
mcp_server/skills/<name>/__init__.py,operations.py,tools.pyoperations.py— pure logic, returns{"ok": True/False, ...}tools.py— exportsregister(mcp), defines tool schemasAdd
tests/test_<name>.pyand a CI step in.github/workflows/ci.ymlAuto-registers via
skills/__init__.py; add each tool name toEXPECTED_TOOLSintests/test_skill_registration.py— the roster's single source of truth (never hardcode counts)
New Claude Code skill (workflow guide)
Create
.claude/skills/<name>/SKILL.mdwith YAML frontmatter (name,description)Add workflow instructions referencing MCP tool names;
user-invocable: true|false,context: forkfor fire-and-forgetAdd
tests/test_skill_<name>.py+ a CI shard, an example indocs/examples/, and a README rowAuto-appears in
list_skills()via the/skillsmount
New HVAC component type
Add
_get_<type>_props(obj)/_set_<type>_props(obj, props)incomponents.pyAdd an entry to
COMPONENT_TYPES; add a test intests/test_component_properties.pyNo dynamic dispatch — every OpenStudio API call must be explicit and grepable
Cite this work
If you use OpenStudio-MCP in research, please cite the SoftwareX article:
Ball, B.L., Long, N., Fleming, K., Goldwasser, D., 2026. OpenStudio-MCP: a model context protocol (MCP) server for AI agent-driven building energy modeling with the OpenStudio SDK. SoftwareX 36, 103020. https://doi.org/10.1016/j.softx.2026.103020
@article{ball2026openstudiomcp,
title = {{OpenStudio-MCP}: a model context protocol ({MCP}) server for {AI} agent-driven building energy modeling with the {OpenStudio} {SDK}},
author = {Ball, Brian L. and Long, Nicholas and Fleming, Katherine and Goldwasser, David},
journal = {SoftwareX},
volume = {36},
pages = {103020},
year = {2026},
issn = {2352-7110},
doi = {10.1016/j.softx.2026.103020}
}License
See LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Design, solve and simulate HVAC systems from real components, weather years and buildings.
Solar, weatherization, EV charging, battery and heat-pump decision tools for AI agents.
- AeviaOAuthai.aeviamodeler
AI-powered life cycle assessment and modelling: connect to LCA databases, build and analyze systems
1 Natural-language queries over a verified emissions knowledge graph, plus standards validation
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceEnables AI assistants to interact with OpenStudio building energy models through natural language, allowing users to load, inspect, and manipulate OSM files including building geometry, HVAC systems, materials, schedules, and internal loads.11MIT
- AlicenseNot gradedqualityBmaintenanceEnables natural-language interaction with Ladybug Tools for building performance simulation, 3D modeling, and data visualization, allowing agents to perform complex environmental analysis tasks without CAD software.8GPL 3.0
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to understand, query, and manipulate Honeybee building energy models through natural language via the Model Context Protocol.17GPL 3.0

idfkit-mcpofficial
AlicenseAqualityBmaintenanceEnables AI assistants to create, edit, and simulate EnergyPlus building energy models via natural language. Supports schema exploration, model editing, simulation execution, and documentation search.393MIT