NO

natlabrockies/openstudio-mcp

Developer tools
45 stars 10 forks 품질 75 트렌드 48NOASSERTION

It lets MCP hosts — Claude Desktop, Claude Code, Cursor, VS Code — create, query, and modify OpenStudio models, run EnergyPlus, and read results, all in plain language.

개요

It lets MCP hosts — Claude Desktop, Claude Code, Cursor, 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. - "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.

README

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


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.1

Tags on nrel/openstudio-mcp:

Tag What it is
vX.Y.Z (e.g. v1.2.1) A tagged release. Pin one of these for reproducible work
dev Latest develop branch build; moves on every merge

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-mcp
Machine Build command
Intel/AMD (Linux, Windows, Intel Mac) docker build -t openstudio-mcp:dev -f docker/Dockerfile .
Apple Silicon (M-series) docker build --platform linux/arm64 -t openstudio-mcp:dev -f docker/Dockerfile.arm64 .

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
/inputs (read-only) 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 /inputs/ in your prompt
/runs simulation output Every run writes to /runs// (OSM, SQL, HTML reports). Without the mount, results vanish when the container exits
/measures authored + BCL measures create_measure and BCL downloads land under /measures//{custom,bcl}. Mount it so measures survive restarts; list_local_measures discovers them

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 sandbox user (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_privs prevents 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
OSMCP_SANDBOX auto auto, full, and landlock request environment filtering, UID/GID drop, resource limits, Landlock filesystem confinement, and seccomp network denial. posix omits Landlock and seccomp. off disables child-process confinement and is only appropriate for trusted local code. Unknown values fall back to auto.
OSMCP_SANDBOX_NET deny deny blocks outbound IP networking. allow permits it for trusted measures that must fetch external resources.
OSMCP_SANDBOX_UID / OSMCP_SANDBOX_GID 1001 Account used for confined child processes. Values less than 1 are rejected. The default matches the sandbox user built into the image.
OSMCP_SANDBOX_RLIMIT_FSIZE 10737418240 Maximum size in bytes of one file created by a child process. 0 disables this limit.
OSMCP_SANDBOX_RLIMIT_NPROC 1024 Maximum processes/threads for the sandbox UID. 0 disables this limit.
OSMCP_SANDBOX_RLIMIT_NOFILE 0 Optional open-file descriptor limit.
OSMCP_SANDBOX_RLIMIT_CPU 0 Optional CPU-seconds limit. Disabled by default because annual simulations can be long-running.
OSMCP_SANDBOX_RLIMIT_AS 0 Optional virtual-memory limit. Prefer Docker memory limits because restrictive address-space limits can break EnergyPlus.
OSMCP_SIM_TIMEOUT_SECONDS 7200 Wall-clock timeout for a simulation. 0 disables the timeout.
OSMCP_ALLOW_UNSANDBOXED unset In HTTP mode the server refuses to start (exit 3) unless the full tier is configured (OSMCP_SANDBOX=auto, OSMCP_SANDBOX_NET=deny, Linux). true overrides with a logged warning.
OSMCP_ENABLE_CODE_TOOLS true Set false to not register the code-authoring tools (create_measure, edit_measure, create_python_plugin, edit_python_plugin, install_plugin_packages) on a deployment that must not let agents write code.
OSMCP_TOOLS_ALLOW unset Comma list; when set, only these tools are registered. Unknown names refuse startup.
OSMCP_TOOLS_DENY unset Comma list of tools to hide (deny wins over allow). Unknown names refuse startup.

Secure deployment guidance

  • Mount /inputs read-only: -v /host/inputs:/inputs:ro.
  • Mount only the output directory at /runs; any process allowed to write /runs can modify that host directory by design.
  • Do not mount the repository, home directory, Docker socket, credentials, or broad host paths into production containers. The /repo source mount in the testing commands is for development only.
  • Keep OSMCP_SANDBOX=auto and OSMCP_SANDBOX_NET=deny for untrusted measure authoring. Docker’s --network none can 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
/simulate Workflow one-command simulate + results extraction
/energy-report Workflow comprehensive multi-category energy report
/new-building Workflow full model creation from scratch
/retrofit Workflow before/after ECM analysis
/add-hvac Task guided HVAC system selection
/qaqc Task pre-simulation model quality check
/view Task quick 3D model visualization
/troubleshoot Task diagnose simulation failures
measure-authoring Knowledge measure creation, SDK verification, wiring patterns
ashrae-baseline-guide Knowledge ASHRAE 90.1 system selection
openstudio-patterns Knowledge tool dependencies and model relationships
tool-workflows Knowledge multi-tool recipes for common operations
/attribute-space-types Task attribute standards space types to conditioned spaces (post-gbXML)
/gbxml-import Task Revit gbXML import + geometry-defect repair workflow
/osaf-analysis Task OpenStudio Analysis Framework workflow: algorithm selection, validation, submission
/python-ems Task custom EnergyPlus Python Plugin control/reporting logic (EMS)
/file-transfer 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.


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

25 worked examples with full tool-call sequences:


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-files

Architecture

  • 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//, each with tools.py (MCP registration) + operations.py (business logic); they auto-register
  • State: per-session in-memory model via model_manager; runs under /runs// (or /runs/// 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


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.

View this README on GitHub

설치

docker 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

설정

{ "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" ] } } }