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:

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

ToolDoes
moor_get_stateThe active profile, and every profile, dock and theme by id and name. Agents call this first
moor_list_profilesEvery profile in full
moor_switch_profileSwitch to a profile
moor_create_profileNew profile: from the current Dock, empty, or a copy of another
moor_update_profileRename, Dock mode, which docks it shows, Dock settings, color, symbol
moor_list_docks · moor_get_dockEvery Custom Dock, or one, with its items
moor_create_dockNew dock with items, placement, behavior and theme, optionally attached to a profile
moor_update_dockRename, move to another edge or display, auto-hide and other behavior, theme
moor_add_item · moor_update_item · moor_remove_item · moor_move_itemChange a dock's items
moor_list_themes · moor_create_theme · moor_update_themeDock themes (built-in themes are duplicated, not edited)
moor_widget_catalogEvery widget, with its sizes and default settings
moor_set_custom_widgetUpdate the Custom widget
moor_get_settings · moor_update_settingsMoor's settings
moor_run_commandNext 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

MethodPathDoes
GET/v1Moor's version and the API version
GET/v1/stateActive profile; profiles, docks and themes by id and name
GET/v1/profiles · /v1/profiles/{id}Every profile, or one
POST/v1/profilesCreate: {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}/activateSwitch to it
GET/v1/docks · /v1/docks/{id}Every Custom Dock, or one
POST/v1/docksCreate: {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}/itemsAdd {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}/moveMove it: {index}
GET/v1/themes · /v1/themes/{id}Every theme, or one
POST/v1/themesCreate: {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/catalogEvery 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/settingsMoor'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:

ItemJSON
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”."}}
StatuscodeWhen
400bad_requestSomething in the request is wrong (the message says what)
404not_foundNo profile, dock, theme or item with that id or name
409conflictTwo things have that name (use the id), or the change isn't allowed, like deleting the last profile
503disabledThe API is turned off
500internalSomething went wrong in Moor

Privacy and safety

This page as Markdown: /docs/api.md