uc-remote-mcp
This MCP server lets an AI set up, inspect, customize, back up, and control an Unfolded Circle Remote 3/Remote Two through its API.
Discover and set up remotes via mDNS, PIN, and API key; retrieve remote status.
Browse devices/entities, device commands, activities, and button mappings; send one-off device commands.
Create, edit, delete, and reorder UI pages; manage activity power sequences and create activities.
Set button mappings individually or across many activities, with dry-run previews and automatic backups.
Back up full configs, diff against backups, and restore with confirmation.
Manage integrations: list entities, expose them, enable/disable/restart/install/delete drivers or instances, and run setup flows.
Manage activity/macro scope entities that buttons and pages are allowed to use.
Restart the remote's UI, core, or system.
Enables controlling an Apple TV through an Unfolded Circle Remote, including setting up the Apple TV integration, restarting it when unresponsive, and mapping remote buttons or activities to Apple TV commands such as play/pause.
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., "@uc-remote-mcp What's the battery level on my remote?"
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.
An MCP server for the Remote 3 / Remote Two. Works with Claude and any other MCP client.
What it does
Layouts: build an activity, device or page.
Buttons: ask what a button does, or remap it.
Integrations: install, set up and restart them.
Backups: snapshot your config, see what changed, restore it.
Updates: keep the remote current.
Related MCP server: rc505mk2-mcp
Installation
Install uv. You already have it if you use another Python MCP server.
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # Windowscurl -LsSf https://astral.sh/uv/install.sh | sh # macOS / LinuxAdd it to your MCP client. For Claude Desktop, edit
%APPDATA%\Claude\claude_desktop_config.json(Windows) or~/Library/Application Support/Claude/claude_desktop_config.json(macOS):{ "mcpServers": { "uc-remote": { "command": "uvx", "args": ["--from", "git+https://github.com/b2dmx/uc-remote-mcp@v1.0.0", "uc-remote-mcp"] } } }Restart the client. First launch takes a minute while it builds.
Onboarding
On the remote: Settings → Web Configurator, turn it on and note the PIN.
Tell your AI: "Discover my Unfolded Circle remote and set it up with PIN 1234."
Try: "What does the volume button do in each activity?"
Tips
Every change previews first and takes a backup, so it's safe to experiment.
Say "Back up my config" before big changes, and "What changed since that backup?" after.
Removing an entity also strips the buttons and page items using it.
A stopped device? "Restart the Apple TV integration."
To update, change the version in your config and restart. Watch → Custom → Releases to hear about new ones.
Tested on a Remote 3 (firmware 2.8.x). The Remote Two shares the API but is untested.
More
All the tools → · Field notes →
Tool design informed by ha-mcp. API reference from the Unfolded Circle Core API.
License
The code is MIT. The Unfolded Circle MCP logo and icons (brand-source/, brand/, and the logo images in docs/) are © Goobis, all rights reserved. They are not covered by the MIT license, so please don't reuse them without permission.
Available Tools
41 toolsadd_scope_entitiesA
Allow an activity or macro to use more entities. Exposing an entity from an integration is not enough on its own — it must also be added here before a button or page item can use it. Existing entries are preserved.
Inputs: scope_id (required), entity_ids (required), host, scope, +1 more. Returns: object
answer_integration_setupB
Answer the current setup screen and return the next. Send every field the screen asks for; a rejected step ends the flow and it must be restarted.
Inputs: values (required), driver_id (required), host. Returns: object
backup_configA
Dump the entire remote configuration (system, entities, activities, remote-entities, UI pages — full detail) to one JSON file. Defaults to %APPDATA%/uc-remote-mcp/backups/.json, keeping the last 50.
Inputs: host, output_path. Returns: object
bulk_set_button_mappingA
Set the same button binding across many activities at once (e.g. route VOLUME_UP on every activity to the AVR). Filter with activity_ids and/or name_contains; no filter = all activities. Invalid activities are skipped with a reason. One backup before the batch. Defaults to dry_run=True (returns the full per-activity plan); set dry_run=false to apply.
Inputs: button (required), command (required), entity_id (required), host, +5 more. Returns: object
cancel_integration_setupA
Abandon an in-progress setup flow, changing nothing.
Inputs: driver_id (required), host. Returns: object
configure_integration_entitiesA
Expose entities from an integration so activities and pages can use them. Additive; removes nothing. Setup finishing does not do this for you.
Inputs: entity_ids (required), integration_id (required), host, dry_run. Returns: object
confirm_integration_setupA
Answer a confirmation screen ("press the button on the device, then continue") and return the next one. Use answer_integration_setup for screens with fields; this is for the ones without.
Inputs: driver_id (required), host, confirm. Returns: object
create_activityA
Create an activity — a "device" on the remote's home screen.
Pass entity_ids to build from scratch, or clone_from to copy an existing activity/macro/remote-entity; not both. icon takes "uc:name" or "custom:file.png". The empty page the remote creates alongside it is removed, and the result says if it joined the default activity group, which can make its tile power devices on and off.
Inputs: name (required), host, icon, dry_run, +3 more. Returns: object
create_ui_pageA
Add a new page to an activity or remote-entity. scope is "activity" or "remote". grid is {"width": N, "height": M}; items use the same shape as get_ui_page returns. The page is appended last; reorder with set_default_ui_page. Every item command is validated first.
Inputs: grid (required), name (required), scope (required), scope_id (required), +3 more. Returns: object
delete_integrationA
Remove a driver, its instance and all its entities. Also strips every button mapping and page item that used them. Read the preview before applying.
Inputs: driver_id (required), host, dry_run. Returns: object
delete_integration_instanceA
Remove one configured instance and its entities, keeping the driver. The teardown for firmware-shipped drivers. Also strips every button mapping and page item that used those entities — read the preview.
Inputs: integration_id (required), host, dry_run. Returns: object
delete_ui_pageA
Delete a UI page from an 'activity' or 'remote'. IRREVOCABLE on the device — the auto-backup taken before the write is the only way back. Dry-run (default) shows the full page content that would be lost.
Inputs: scope (required), page_id (required), scope_id (required), host, +1 more. Returns: object
diff_configA
Show what changed between the current live config and a backup file (read-only). Reports the operations a restore would perform plus differences that cannot be restored.
Inputs: against_path (required), host. Returns: object
discover_remotesA
Scan the LAN via mDNS for UC remotes. Returns a list of {name, host, port, model, fw, id}.
Inputs: timeout_s. Returns: result
get_activityC
Full activity config: included entities, on/off power sequences, button overrides, and the list of UI pages.
Inputs: activity_id (required), host. Returns: object
get_button_mappingA
Physical-button -> command bindings. scope is 'activity' (needs scope_id=activity_id), 'remote' (needs scope_id=remote entity_id), or 'device' (needs scope_id=target entity_id; returns every binding across all activities and remotes that targets that device).
Inputs: scope (required), host, scope_id. Returns: object
get_deviceB
Full config for one device (entity): features, available commands, current attributes, and options.
Inputs: device_id (required), host. Returns: object
get_integrationB
One integration instance in full, including the entities it has configured.
Inputs: integration_id (required), host. Returns: object
get_integration_setupB
The current screen of a setup flow. 404 means no flow is in progress.
Inputs: driver_id (required), host. Returns: object
get_remote_infoA
Return model, firmware, battery level/status, and currently active activities. Uses the first configured remote if host is not specified.
Inputs: host. Returns: object
get_ui_pageA
Items on one UI page: grid size and each item's position, type, and command. Identify the page by its parent scope ('activity'/'remote'), the scope's entity_id, and the page_id (from list_ui_pages).
Inputs: scope (required), page_id (required), scope_id (required), host. Returns: object
install_integrationA
Install a custom driver from a .tar.gz archive on this machine. There is no in-place update: delete the old driver first. Restart the system afterwards or its setup flow will not start.
Inputs: file_path (required), host, dry_run. Returns: object
list_activitiesC
List all activities with id, name, state, description, and included entities.
Inputs: host. Returns: result
list_device_commandsA
Commands a device exposes, for picking when mapping buttons. Returns {features, simple_commands}.
Inputs: device_id (required), host. Returns: object
list_devicesA
List all configured devices (entities). Each physical device may appear as several entities (e.g. a TV has both a media_player and a remote entity). Optionally filter by entity_type (media_player, remote, light, switch, sensor). Returns {id, name, type, integration, device_class, state} per entity.
Inputs: host, entity_type. Returns: result
list_integration_entitiesB
Entities an integration offers. only_new re-polls the integration and lists what is not exposed yet, which is required after pairing a new device.
Inputs: integration_id (required), host, only_new. Returns: object
list_integrationsA
Installed integration drivers and their configured instances.
device_state is not a health signal: an instance reports CONNECTED while its entities are stale. Check the entities too.
Inputs: host. Returns: object
list_scope_entitiesC
Entities an activity or macro is currently allowed to use. scope is "activity" or "macro" — both keep their own list, and a command naming an entity outside it is rejected.
Inputs: scope_id (required), host, scope. Returns: object
list_ui_pagesA
List UI pages for a scope: 'activity' or 'remote'. scope_id is that entity's id. Returns page ids, names, grids, and item counts.
Inputs: scope (required), scope_id (required), host. Returns: object
remove_scope_entitiesB
Stop an activity or macro using entities. Every button mapping and page item referencing them is removed too, so read the preview before applying.
Inputs: scope_id (required), entity_ids (required), host, scope, +1 more. Returns: object
restart_integrationA
Disable and re-enable an integration. The usual fix when devices stop responding but the integration still claims to be connected.
Inputs: integration_id (required), host, dry_run. Returns: object
restart_remoteA
Restart the remote's "ui", "core", or "system". Sends no device commands and changes no configuration. "ui" is how configuration changes are made to repaint; "system" is required after installing a driver.
Inputs: host, target, dry_run. Returns: object
restore_configA
Restore activities/remotes customization (names, button mappings, UI pages, sequences) from a backup file. First call returns a confirmation_token + full plan without writing; call again with the token and dry_run=false to apply. Auto-backup of the current state is taken before applying.
Inputs: input_path (required), host, dry_run, confirmation_token. Returns: object
send_commandA
Fire a one-off command at a device (entity). Transient (does not change saved config) but affects the device, so defaults to dry_run=True. Set dry_run=false to actually send. Body: PUT /entities/{id}/command {cmd_id, params?}.
Inputs: command (required), device_id (required), host, params, +1 more. Returns: object
set_button_mappingA
Set one physical-button -> command binding on an 'activity' or 'remote'. entity_id is REQUIRED for activities (the command target) and ignored for remotes. Defaults to dry_run=True (shows before/after); auto-backs-up before any real write. Set dry_run=false to apply.
Inputs: scope (required), button (required), command (required), scope_id (required), +5 more. Returns: object
set_default_ui_pageA
Make a page the first/default page of an 'activity' or 'remote' UI (the page shown when it opens). Implemented as a page reorder — the API has no explicit default-page property. Defaults to dry_run=True.
Inputs: scope (required), page_id (required), scope_id (required), host, +1 more. Returns: object
set_integration_enabledC
Enable or disable an integration instance.
Inputs: enabled (required), integration_id (required), host, dry_run. Returns: object
setup_remoteB
First-run setup. Authenticate with admin PIN, create a long-lived API key, and save config. Only needed once per remote.
Inputs: pin (required), host (required), name, port. Returns: object
start_integration_setupA
Begin an integration's setup and return its first screen.
Some drivers require a value up front (usually an API key) and answer "400 Setup data not provided for field: X" without it — pass setup_data={"X": "..."}. A 503 means the driver process is not running yet, which is normal right after installing: restart the system first.
Inputs: driver_id (required), host, setup_data, reconfigure. Returns: object
update_activity_sequenceA
Replace an activity's on and/or off power sequence. Steps are {"type":"command","command":{"entity_id","cmd_id","params"?}} or {"type":"delay","delay":}. Omitted sequence = unchanged; empty list clears it. Command steps are validated against the activity's included entities. Defaults to dry_run=True; auto-backup before any real write.
Inputs: activity_id (required), host, dry_run, on_sequence, +1 more. Returns: object
update_ui_pageA
Update a UI page's name, grid, and/or items on an 'activity' or 'remote'. Omitted fields stay unchanged; an EMPTY items list clears the page. Item commands are validated against the scope before writing. Defaults to dry_run=True; auto-backup before any real write.
Inputs: scope (required), page_id (required), scope_id (required), grid, +4 more. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 41 tools
Most tools target a distinct resource+action, and descriptions explicitly disambiguate close pairs like delete_integration vs delete_integration_instance and answer vs confirm_integration_setup. A few entity-listing tools (list_devices, list_integration_entities, list_scope_entities) require careful reading, but their scope qualifiers make selection possible.
All tools use snake_case verb_noun names with consistent verbs (list/get/create/update/delete/set/restart). Pluralization is predictable (list_* plural, get_* singular), and modifiers like bulk_ and diff_ are used consistently.
At 41 tools, the surface is far beyond the typical 3-15 tool sweet spot and falls in the 'too many' range even for a broad remote-control domain. While most tools are individually justified, the count makes selection harder and suggests consolidation opportunities.
The surface covers integration lifecycle, setup flows, devices, activities, UI pages, mappings, and backup/restore, which is broad. However, activities have create/get/partial update but no delete/rename, and backup_config has no companion list_backups tool, leaving some dead ends.
Maintenance
Related MCP Connectors
Deploy, monitor, and manage your OpenClaw AI assistants via natural language.
Turns a phone into a camera+Bluetooth remote so AI assistants can see and control any PC.
Interact with the Stitch API using natural language commands.
Control your Tesla from your AI assistant - climate, charging, access, and security.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables voice conversations with AI assistants directly in the browser, supporting 30+ languages and remote access from any device.531 npm93MIT
- AlicenseNot gradedqualityCmaintenanceEnables controlling a Roland RC-505mk2 loop station via natural language, allowing creation and upload of FX rack presets to the device over USB.4MIT
- AlicenseCqualityDmaintenanceEnables configuring Morningstar MIDI foot controllers using natural language, including switch mapping, MIDI CC lookup, conflict detection, and USB programming.92MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to control Home Assistant via natural language, including device control, automation management, and system monitoring.MIT