Agents & API
Ask an AI agent to set up your docks and it does it, the same way you would by hand. Moor includes an MCP server for agents (Claude Code, Codex, Cursor and any other MCP client) and a local API for scripts. Both can read and change everything you can change in Moor: profiles, Custom Docks and their items, themes, widgets, settings and commands.
It's on your Mac only. Nothing listens on a network port, and nothing leaves your Mac.
What you can ask for
Once it's set up, just ask:
- “Put a dock on the left of my second display with Xcode, Terminal and the Agents widget.”
- “Make a Writing profile that hides Apple's Dock and shows only Pages, Safari and a clock.”
- “Switch to my Work profile.” Then: “Undo that.”
- “Add my Downloads folder to the Coding dock as a grid, newest first.”
- “Duplicate the Glass theme, give it rounder corners, and use it on every dock.”
- “Show the build status in my Custom widget: 3 failing, in red.”
The agent starts by reading your current setup (profiles, docks and themes), so it can use the names you already have.
Setting it up
The MCP server is the moor command, so install it first: Settings → Advanced → Install Command-Line Tool… (see Command line). Moor must be running, and Settings → Automation → Let apps and agents control Moor must be on (it's on unless you turned it off).
Claude Code:
claude mcp add moor -- moor mcp
Codex: add this to ~/.codex/config.toml:
[mcp_servers.moor]
command = "moor"
args = ["mcp"]
Cursor: add this to ~/.cursor/mcp.json (or a project's .cursor/mcp.json):
{
"mcpServers": {
"moor": { "command": "moor", "args": ["mcp"] }
}
}
Any other MCP client: run moor mcp as a stdio server. If the client doesn't find moor on your PATH, use the full path the installer showed you, like /usr/local/bin/moor or ~/.local/bin/moor.
If Moor isn't running, or the setting is off, the agent is told so and can tell you.
Tools
| Tool | Does |
|---|---|
moor_get_state | The active profile, and every profile, dock and theme by id and name. Agents call this first |
moor_list_profiles | Every profile in full |
moor_switch_profile | Switch to a profile |
moor_create_profile | New profile: from the current Dock, empty, or a copy of another |
moor_update_profile | Rename, Dock mode, which docks it shows, Dock settings, color, symbol |
moor_list_docks · moor_get_dock | Every Custom Dock, or one, with its items |
moor_create_dock | New dock with items, placement, behavior and theme, optionally attached to a profile |
moor_update_dock | Rename, move to another edge or display, auto-hide and other behavior, theme |
moor_add_item · moor_update_item · moor_remove_item · moor_move_item | Change a dock's items |
moor_list_themes · moor_create_theme · moor_update_theme | Dock themes (built-in themes are duplicated, not edited) |
moor_widget_catalog | Every widget, with its sizes and default settings |
moor_set_custom_widget | Update the Custom widget |
moor_get_settings · moor_update_settings | Moor's settings |
moor_run_command | Next or previous profile, back to the last one, undo, picker, search, edit mode, or any moor:// link |
Wherever a tool asks for a profile, dock or theme, an agent can give its name instead of its id.
HTTP API
Scripts can use the same API directly. It's HTTP with JSON, over a Unix socket at ~/Library/Application Support/Moor/moor.sock (or in MOOR_STORE_ROOT if you set it).
With curl:
SOCK="$HOME/Library/Application Support/Moor/moor.sock"
curl --unix-socket "$SOCK" http://localhost/v1/state
curl --unix-socket "$SOCK" -X POST http://localhost/v1/docks \
-H "Content-Type: application/json" \
-d '{"name": "Coding", "placement": {"edge": "left"}, "items": [{"type": "app", "bundleID": "com.apple.dt.Xcode"}, {"type": "app", "bundleID": "com.apple.Terminal"}]}'
curl --unix-socket "$SOCK" -X POST http://localhost/v1/profiles/Work/activate
Or with the moor command, which finds the socket for you and prints the reply as formatted JSON:
moor api GET /v1/state
moor api POST /v1/docks '{"name": "Coding"}'
moor api PATCH /v1/docks/Coding @dock.json # body from a file
echo '{"index": 0}' | moor api POST /v1/docks/Coding/items/<item id>/move -
moor api exits with status 1 when Moor answers with an error (the message goes to stderr), 2 for bad arguments, and 3 when Moor isn't running or the API is off.
Endpoints
| Method | Path | Does |
|---|---|---|
| GET | /v1 | Moor's version and the API version |
| GET | /v1/state | Active profile; profiles, docks and themes by id and name |
| GET | /v1/profiles · /v1/profiles/{id} | Every profile, or one |
| POST | /v1/profiles | Create: {name, from?, mode?}. from is current (the Dock as it is now), empty, or a profile to copy |
| PATCH | /v1/profiles/{id} | Change name, mode, customDockIDs, settings, color, symbol, display rules |
| DELETE | /v1/profiles/{id} | Delete (not the last one) |
| POST | /v1/profiles/{id}/activate | Switch to it |
| GET | /v1/docks · /v1/docks/{id} | Every Custom Dock, or one |
| POST | /v1/docks | Create: {name, items?, placement?, behavior?, themeID?, profile?} |
| PATCH | /v1/docks/{id} | Change name, placement, behavior, themeID |
| DELETE | /v1/docks/{id} | Delete (and remove it from profiles) |
| POST | /v1/docks/{id}/items | Add {item, index?} (at the end without an index) |
| PATCH | /v1/docks/{id}/items/{itemID} | Change an item's label, a widget's size or settings, a folder's view, sort or display |
| DELETE | /v1/docks/{id}/items/{itemID} | Remove an item |
| POST | /v1/docks/{id}/items/{itemID}/move | Move it: {index} |
| GET | /v1/themes · /v1/themes/{id} | Every theme, or one |
| POST | /v1/themes | Create: {name, from?, …} |
| PATCH | /v1/themes/{id} | Change one of your themes (light, dark and layout are merged) |
| DELETE | /v1/themes/{id} | Delete one of your themes (docks using it go back to Glass) |
| GET | /v1/widgets/catalog | Every widget: kind, name, sizes, default size and settings, whether it needs an account |
| POST | /v1/widgets/custom/{key} | Update the Custom widget (value, title, badge, color, symbol) |
| GET · PATCH | /v1/settings | Moor's settings |
| POST | /v1/commands | {command}: next, prev, toggle, undo, picker, search, edit-docks, focus-off, snapshot. Or {url} with any moor:// link |
{id} is an id or a name (not case-sensitive). Replies are the same JSON Moor saves, so you can GET something, change it, and send it back. PATCH changes only the keys you send.
Items
Add items in this short form:
| Item | JSON |
|---|---|
| App | {"type": "app", "bundleID": "com.apple.Safari"} or {"type": "app", "path": "/Applications/Safari.app"} |
| Folder | {"type": "folder", "path": "~/Downloads", "view": "grid", "sort": "dateAdded", "display": "stack"}. view: auto, grid, fan, list; sort: dateAdded, name, kind, dateModified, dateCreated; display: stack, folder |
| File | {"type": "file", "path": "~/Documents/plan.pdf"} |
| Link | {"type": "url", "url": "https://moorapp.com", "label": "Moor"} |
| Widget | {"type": "widget", "kind": "time.clock", "size": "wide", "config": {}}. Kinds, sizes and settings are in /v1/widgets/catalog; leave out config for the defaults |
| Shortcut | {"type": "shortcut", "name": "Start Focus"} |
| Divider, spacer, Trash | {"type": "divider"}, {"type": "spacer", "small": false}, {"type": "trash"} |
| Open apps | {"type": "runningApps"}: apps that are open but not in the dock |
| Group | {"type": "group", "label": "Design", "items": [ … ]} |
Apps must be installed. Labels default to what Moor would show.
Errors
Errors come back with an HTTP status and a message written for a person:
{"error": {"code": "not_found", "message": "There's no dock named “Lefty”."}}
| Status | code | When |
|---|---|---|
| 400 | bad_request | Something in the request is wrong (the message says what) |
| 404 | not_found | No profile, dock, theme or item with that id or name |
| 409 | conflict | Two things have that name (use the id), or the change isn't allowed, like deleting the last profile |
| 503 | disabled | The API is turned off |
| 500 | internal | Something went wrong in Moor |
Privacy and safety
- On your Mac only. The API is a Unix socket only your user account can open. Nothing listens on a network port, so other computers and web pages can't reach it.
- API keys stay private. Keys and accounts for widgets are in your Keychain, and the API can't read or change them. An agent can add a revenue widget, but you connect the account yourself.
- Turn it off with Settings → Automation → Let apps and agents control Moor. Moor then stops listening.
- Same as doing it yourself. Every change goes through the same steps as Moor's own windows and menus, and syncs through iCloud if that's on. A profile switch can be undone (Undo in the menu, or ask the agent to undo it). Your original Dock is always kept, as described in Privacy & safety.
- Want a safety net? Before letting an agent rework your setup, save a backup with Settings → Advanced → Export All Profiles….
This page as Markdown: /docs/api.md