c4_alarm_arm_away
Arm an alarm/security panel in Away mode (best-effort).
Control a Control4 home from an MCP client — query rooms and devices, run scenes, and change lights, locks, thermostats and media, with writes off until you turn them on.
LABSCO SUMMARY
Writes are disabled until you set the flag, so the first thing you can do is inventory and status — "which doors are unlocked, what is on in the basement, what are the setpoints" — with no risk of changing anything. Turn writes on and the allow and deny lists let you keep specific devices, the garage door being the obvious one, out of reach. Session memory is what makes the follow-up phrasing work rather than needing device ids every time.
A Control4 bridge that turns your project's rooms and devices into a tool surface, over STDIO for desktop clients or HTTP for scripts. It talks to the Director directly, validates every input, and enforces safety rules before anything changes state.
c4_list_rooms, c4_list_devices, c4_list_controls, c4_list_typenamesc4_light_set_by_name, c4_light_set_level, c4_light_ramp, c4_room_lights_set, c4_light_get_statec4_lock_get_state, c4_lock_lock, c4_lock_unlock, c4_lock_set_by_namec4_thermostat_get_state, c4_thermostat_set_target_f, c4_thermostat_set_heat_setpoint_f, c4_thermostat_set_cool_setpoint_f, c4_thermostat_set_hvac_mode, c4_thermostat_set_fan_mode, c4_thermostat_set_hold_modec4_tv_watch, c4_tv_off, c4_media_now_playing, c4_media_remote_sequence, c4_media_launch_app, c4_room_select_audio_device, c4_room_select_video_devicec4_macro_execute_by_name, c4_announcement_execute_by_name, c4_scheduler_list, c4_scheduler_set_enabledc4_alarm_get_state, c4_alarm_arm_away, c4_alarm_arm_stay, c4_alarm_disarmc4_lights_set_last, c4_tv_off_last, c4_memory_get, c4_memory_clearconfig.json pointed to by C4_CONFIG_PATH, or from C4_HOST, C4_USERNAME and C4_PASSWORD directly.pip install c4-mcp route does not work: PyPI has no package by that name.C4_WRITES_ENABLED is true; C4_WRITE_GUARDRAILS, C4_WRITE_ALLOWLIST and C4_WRITE_DENYLIST narrow what writes can reach.Follow the published steps — python -m venv .venv
USE CASES
Turn off the lights except the hallway, lock the exterior doors, set the downstairs thermostat, then report what succeeded and what did not — one request instead of a stack of taps.
With writes off, list unlocked doors, lights still on and current setpoints per zone. Nothing in this path can change state.
When "Basement" matches several rooms the call comes back with the candidates rather than acting on the wrong one; re-issue it with the room or exact device name to make it unambiguous.
Start the source, then follow up with "turn it off" or a remote sequence — session memory resolves the target from the previous call instead of asking again.
Counted once with only startup setup. Other versions, modes or optional credentials may expose a different list.
c4_alarm_arm_awayArm an alarm/security panel in Away mode (best-effort).
c4_alarm_arm_stayArm an alarm/security panel in Stay mode (best-effort).
c4_alarm_disarmDisarm an alarm/security panel (best-effort).
c4_alarm_get_stateGet best-effort alarm/security state from device variables (armed/mode/alarm_active/ready/trouble when available).
c4_alarm_listList alarm/security panel-like devices (best-effort discovery). Returns an empty list when no alarm panel is present.
c4_alarm_set_modeArm/disarm an alarm/security panel (best-effort). Mode must be one of: disarmed, away, stay, night. Optionally pass code (PIN/user code) if the driver requires it. Supports dry_run and returns accepted/confirmed.
c4_announcement_executeExecute a configured Control4 announcement by id. Supports dry_run.
c4_announcement_execute_by_nameExecute a configured Control4 announcement by exact name (case-insensitive exact match). If the name is missing/ambiguous, returns suggestions and does not execute. Supports dry_run.
c4_announcement_listList announcements configured in Control4 (agents/announcements).
c4_announcement_list_commandsList available announcements agent commands (discovery/debug).
c4_capabilities_reportSummarize your Control4 inventory by control/proxy/driver filename/room. Useful for figuring out what else is available to automate next.
c4_contact_get_stateGet best-effort state for a contact/motion sensor device. Returns raw variables plus parsed fields (battery_level, temperature, etc.).
c4_contact_listList contact/sensor-style devices. Currently focuses on Card Access wireless contact/motion drivers (control='cardaccess_wirelesscontact').
c4_control_keypad_listList room_control_keypad devices (programmed 'control buttons' that can trigger presets/lights/room-off, etc.).
c4_control_keypad_send_commandTrigger a command on a room_control_keypad device by command name (exact string from c4_item_commands or the list).
c4_debug_trace_commandForce-send a named Director command and poll for variable/state changes (debug). Useful when cached lock state is stale.
c4_director_methodsList callable methods on the Director object (debug).
c4_doorstation_set_external_chimeEnable/disable the external chime on a Control4 door station (intercom proxy).
c4_doorstation_set_ledEnable/disable the LED indicator on a Control4 door station (intercom proxy).
c4_doorstation_set_raw_settingSet a raw key/value setting on a Control4 door station via the 'Set Raw Settings' command. This is driver-specific; use cautiously.
c4_fan_get_stateGet current fan power/speed (best-effort).
c4_fan_listList fan devices (proxy='fan').
c4_fan_set_powerSet fan power: power must be one of on/off/toggle. Returns accepted/confirmed.
c4_fan_set_speedSet fan speed. speed may be 0-4 or a name: off/low/medium/medium high/high. Returns accepted/confirmed.
c4_find_devicesFind devices by name (case-insensitive, fuzzy). Optional filters: category in {lights, locks, thermostat, media, scenes, shades, alarm} and room_id.
c4_find_roomsFind rooms by name (case-insensitive, fuzzy).
c4_intercom_listList intercom-capable devices (best-effort; proxy contains 'intercom'). Includes touchscreens and door stations where present.
c4_intercom_touchscreen_screensaverControl a touchscreen screensaver: optionally set mode, set start_time_s, and/or action enter/exit. You may combine multiple operations in one call.
c4_intercom_touchscreen_set_featureEnable/disable a touchscreen intercom feature. feature must be one of: autobrightness, proximity, alexa. Uses the device command strings exposed by c4_item_commands.
c4_item_bindingsGet Director bindings for an item (debug).
c4_item_commandsGet available Director commands for an item (debug).
c4_item_execute_commandExecute a specific Director command by command_id (debug).
c4_item_send_commandSend a named Director command to an item (debug). Example: command='UNLOCK' or 'CLOSE'.
c4_item_variablesGet raw Director variables for an item (debug).
c4_keypad_button_actionPerform a keypad button action on a keypad_proxy device. action='tap' sends press+release; action can also be 'press' or 'release'.
c4_keypad_buttonsList button IDs and names for a keypad_proxy device (best-effort; derived from KEYPAD_BUTTON_* command metadata).
c4_keypad_listList physical keypad_proxy devices (keypads/dimmers with programmable buttons). Use c4_keypad_buttons and c4_keypad_button_action for button-based interaction.
c4_light_get_levelGet current brightness level (0-100) of a Control4 light.
c4_light_get_stateGet current on/off state of a Control4 light.
c4_light_rampRamp a Control4 light to a level over time_ms.
c4_light_set_by_nameFast-path: resolve a light by name (optionally scoped by room) and set level/on/off in a single call. Uses inventory caching for fast resolution. Optionally ramps and best-effort confirms final level.
c4_light_set_levelSet a Control4 light level (0-100).
c4_lights_get_lastReturn the last referenced light devices in this session (for follow-ups like 'turn off those lights').
c4_lights_set_lastSet the state/level of the last referenced lights in this session (the safe way to implement 'those lights'). Provide exactly one of: state ('on'/'off') or level (0-100).
c4_list_controlsList Control4 item control values and counts (discovery).
c4_list_devicesList Control4 devices by category (lights, locks, thermostat, media, scenes).
c4_list_roomsList rooms from Control4 (live).
c4_list_typenamesList Control4 item typeName values and counts (discovery).
c4_lock_get_stateGet current lock state (locked/unlocked) for a Control4 lock.
c4_lock_lockLock a Control4 lock.
c4_lock_set_by_nameFast-path: resolve a lock by name (optionally scoped by room) and lock/unlock in one call. Returns accepted/confirmed semantics and includes resolution details.
c4_lock_unlockUnlock a Control4 lock.
c4_macro_executeExecute a configured Control4 macro by id. Supports dry_run.
c4_macro_execute_by_nameExecute a configured Control4 macro by exact name (case-insensitive exact match). If the name is missing/ambiguous, returns suggestions and does not execute. Supports dry_run.
c4_macro_listList macros configured in Control4 (agents/macros).
c4_macro_list_commandsList available macros agent commands (discovery/debug).
c4_media_get_stateGet current state for a Control4 media/AV device (best-effort).
c4_media_launch_appLaunch an app on a media device (primarily Roku). Uses the driver's LaunchApp command when available. Example app: 'Netflix' or 'Home'.
c4_media_now_playingBest-effort 'now playing' for a media device. Returns normalized fields when present, plus candidate variables.
c4_media_remoteSend a basic remote/navigation action to a media device (up/down/left/right/select/menu/home/playpause). Uses the device's transport proxy commands (when available).
c4_media_remote_sequenceSend a sequence of remote actions to a media device (e.g., ['home','down','down','select']). Useful for navigation macros.
c4_media_roku_list_appsList Roku app options for the given Roku device by reading universal mini-app variables (APP_NAME/UM_ROKU) in the same room. Use this to find the exact app name/id to pass to c4_media_launch_app.
c4_media_send_commandSend a named command to a Control4 media/AV device. Use c4_item_commands(device_id) to discover supported command names and params.
c4_media_watch_launch_appHigh-level helper: select the room video source for the given media device (Watch/HDMI) and then launch an app. This makes app launches reliably visible by ensuring the room is on the correct video input first.
c4_media_watch_launch_app_by_nameOne-call helper: resolve a media device by name (optionally scoped by room) and then run c4_media_watch_launch_app. Use this to say things like 'Watch Netflix on <Roku Name> in <Room Name>' without looking up ids. Returns resolution details and preserves accepted/confirmed semantics from the underlying watch+launch...
c4_memory_clearClear this server's in-process session memory for the current MCP client session. Useful if the model got confused about what 'those lights' refers to.
c4_memory_getReturn this server's in-process session memory for the current MCP client session. For HTTP clients, provide/echo a stable X-Session-Id header to persist context.
c4_motion_get_stateGet best-effort motion state for a motion sensor device. Returns raw variables plus parsed fields and motion_detected.
c4_motion_listList motion sensor devices (best-effort). Currently includes contactsingle_motionsensor and wireless PIR proxies.
c4_outlet_get_stateGet current outlet state (as a light).
c4_outlet_listList outlet-controlled loads (control='outlet_light', proxy='light_v2'). These are typically the controllable outlets for outlet switch modules.
c4_outlet_set_powerTurn an outlet load on/off (implemented via light level 0/100).
c4_resolveResolve room and/or device names to ids in one call (best-effort). If room_name is provided, device resolution is scoped to that room.
c4_resolve_deviceResolve a device name to a single device_id (best-effort). Optional filters: category (lights, locks, thermostat, media, scenes, shades, alarm) and room_id. Returns candidates when ambiguous.
c4_resolve_roomResolve a room name to a single room_id (best-effort). Returns candidates when ambiguous. Use c4_find_rooms if you want to pick manually.
c4_room_lights_setFast-path: set all lights in a room to a level (or on/off) in a single call. Optionally exclude/include by device name, ramp, and best-effort confirm each light.
c4_room_list_commandsList available room-level commands (GET /rooms/{room_id}/commands). This is the most universal way to control AV/TV, audio, and navigation in Control4 rooms.
c4_room_list_video_devicesList the selectable video devices (sources) for a room (GET /locations/rooms/{room_id}/video_devices). Use these device ids with c4_tv_watch or c4_room_select_video_device.
c4_room_listenStart a room 'Listen' session by selecting an audio source (SELECT_AUDIO_DEVICE) and confirming activation best-effort. Use c4_room_listen_status to find available sources; this is the audio equivalent of c4_tv_watch.
c4_room_listen_by_nameResolve a room by name and a Listen source device by name, then start a room Listen session. Uses the same safe name resolution as c4_light_set_by_name and c4_media_watch_launch_app_by_name. If resolution is ambiguous, returns candidates and does not execute.
c4_room_listen_statusRead-only: return the room's current Listen status and available Listen sources (best-effort), from UI configuration. Use this to find valid source device ids for c4_room_listen.
c4_room_now_playingRead-only: best-effort room-scoped now playing. Probes the room's Listen sources and returns the first device that exposes usable now-playing metadata (normalized when available), plus probe diagnostics.
c4_room_offTurn off all Audio/Video in a room (ROOM_OFF) and best-effort confirm Watch becomes inactive. Returns accepted/confirmed semantics.
c4_room_presence_reportResolve a room by id or name and return a consolidated presence/status report (read-only). Intended for flows like: user says 'I'm in <room>' and the client wants a single tool call that returns current watch/listen/now-playing status for that room. Returns ambiguity candidates when the room name is not unique.
c4_room_select_audio_deviceSelect a room's audio source (SELECT_AUDIO_DEVICE). Use c4_room_listen_status to discover valid source_device_id values for that room.
c4_room_select_video_deviceSelect a room's active video device (i.e., trigger the Control4 Watch flow for a given HDMI/source device). This is often required before launching Roku apps so the TV is on the correct input.
c4_room_send_commandSend a named room-level command to a room (POST /rooms/{room_id}/commands). Use c4_room_list_commands to discover valid command strings and required params.
c4_room_watch_statusGet best-effort Watch UI status for a room via UI configuration agent. Returns active flag and the current configured sources when available.
c4_scene_activateAlias of c4_uibutton_activate.
c4_scene_activate_by_nameResolve and activate a scene by name (best-effort). Uses UI Button devices as a proxy for scenes. Optionally scope the search by room_name.
c4_scene_listAlias of c4_uibutton_list.
c4_scene_set_state_by_nameFast-path: resolve a scene (UI Button) by name and set its on/off state in a single call. This is ideal for devices like 'Space Heater' that expose SetState(State=On|Off). Optionally scope the search by room_name. Best-effort confirmation polls the STATE variable.
c4_scheduler_getGet details for a scheduler event by event_id (agents/scheduler/{event_id}).
c4_scheduler_listList scheduled events configured in Control4 (agents/scheduler).
c4_scheduler_list_commandsList available scheduler agent commands (discovery/debug).
c4_scheduler_set_enabledEnable/disable a scheduler event by event_id. Supports dry_run. Returns accepted/confirmed based on a best-effort reread.
c4_server_infoReturn process/runtime info for the running MCP server (PID, exe, cwd, argv) plus a tool-registry summary. Useful for diagnosing multiple/stale app.py processes on Windows.
c4_shade_closeClose/lower a shade/blind (best-effort). Returns accepted/confirmed semantics when position is available.
c4_shade_get_stateGet shade/blind state (best-effort). Returns position 0-100 when available.
c4_shade_listList shade/blind-like devices (best-effort discovery).
c4_shade_openOpen/raise a shade/blind (best-effort). Returns accepted/confirmed semantics when position is available.
c4_shade_set_positionSet shade/blind position to 0-100 (best-effort). Uses available item commands when possible and confirms by reading position when available.
c4_shade_stopStop shade/blind movement (best-effort).
c4_thermostat_get_stateGet current state for a Control4 thermostat.
c4_thermostat_set_cool_setpoint_fSet cool setpoint (F) on a Control4 thermostat.
c4_thermostat_set_fan_modeSet fan mode (On/Auto/Circulate) on a Control4 thermostat.
c4_thermostat_set_heat_setpoint_fSet heat setpoint (F) on a Control4 thermostat.
c4_thermostat_set_hold_modeSet hold mode (Off/2 Hours/Next Event/Permanent/Hold Until) on a Control4 thermostat.
c4_thermostat_set_hvac_modeSet HVAC mode (Off/Heat/Cool/Auto) on a Control4 thermostat.
c4_thermostat_set_target_fSet a target temperature (F) without changing HVAC mode. Heat sets heat setpoint; Cool sets cool setpoint; Auto sets heat=target and cool=target+deadband.
c4_tv_get_lastReturn the last referenced TV/media room context in this session (for follow-ups like 'turn off the TV').
c4_tv_listList TV devices in Control4 (control='tv'). Returns tv_device_id plus room_id for universal room-based control.
c4_tv_offTurn off the room's Audio/Video session (ROOM_OFF). Best-effort confirms Watch becomes inactive.
c4_tv_off_lastTurn off the last referenced TV/media room in this session (safe follow-up for commands like 'turn off the TV').
c4_tv_remoteSend a universal room-level remote command for the TV in that room (UP/DOWN/ENTER/BACK/MENU/INFO/EXIT, volume, channel, etc). This is room-based so it works with any TV driver in Control4.
c4_tv_remote_lastSend a room-level remote command to the last referenced TV/media room in this session. Use this for follow-ups like 'turn down the volume' (button='volume_down') or 'mute it' (button='mute').
c4_tv_watchStart/ensure a Watch session in a room by selecting a video device (source) for that room. This is the reliable way to 'turn on the TV' in Control4.
c4_tv_watch_by_nameResolve a room by name and a video source device by name, then start/ensure a Watch session in that room. If resolution is ambiguous, returns candidates and does not execute.
c4_uibutton_activateActivate a UI Button device. By default this sends the best-known activation command (usually 'Select'). Use dry_run=true to see what would be sent.
c4_uibutton_listList UI Button (uibutton) devices. These often represent Navigator shortcuts (mini-apps) and are a good proxy for 'scenes' or automations that users can trigger.
pingHealth check tool to verify the MCP server is reachable.
BEFORE YOU INSTALL
121 tools when we connected.
CONTEXT COST
Rated by the size of the 121 tool definitions that ride along on every turn, not by how many there are
INSTALLATION
git clone https://github.com/randybritsch/c4-mcp
cd c4-mcpWindows (PowerShell):
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txtmacOS / Linux (bash/zsh):
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txtCopy config.example.json to config.json and set your values in it
{
"mcpServers": {
"c4-mcp": {
"command": "C:\\Users\\<YOUR_USERNAME>\\c4-mcp\\.venv\\Scripts\\python.exe",
"args": [
"-u",
"C:\\Users\\<YOUR_USERNAME>\\c4-mcp\\claude_stdio_server.py"
],
"cwd": "C:\\Users\\<YOUR_USERNAME>\\c4-mcp",
"env": {
"PYTHONUTF8": "1",
"PYTHONIOENCODING": "utf-8",
"C4_STDIO_TOOL_MODE": "compact",
"C4_CONFIG_PATH": "C:\\Users\\<YOUR_USERNAME>\\c4-mcp\\config.json",
"C4_WRITE_GUARDRAILS": "true",
"C4_WRITES_ENABLED": "false",
"C4_DIRECTOR_TIMEOUT_S": "30",
"C4_GET_ALL_ITEMS_TIMEOUT_S": "75"
}
}
}
}The c4-mcp path (it appears four times) is the full path of the folder git clone created, written with double backslashes. C4_CONFIG_PATH then points at the config.json you copied from config.example.json and filled in.
curl -s http://127.0.0.1:3333/mcp/call -H "Content-Type: application/json" -d '{"kind":"tool","name":"c4_list_rooms","args":{}}'docker compose up -d