Brix
透過 Claude、ChatGPT 或任何 MCP 用戶端管理您的數位看板螢幕。查看哪些螢幕離線及原因、將內容傳送到螢幕、排定播放清單、擷取螢幕截圖、重新啟動播放器,以及取得播放證明報告。託管式遠端伺服器,支援 OAuth 登入或 API 金鑰。
託管 MCP 伺服器
npx add-mcp 'https://api.brixsignage.com/v1/mcp'可安裝到 Claude Code、Codex、Cursor 等客戶端
文件
Connect an AI agent (MCP)
Control Brix digital signage from Claude or ChatGPT over MCP. Sign in, no key. Endpoint, setup, compatible clients and all 15 tools.
For AI agents: the full docs index is at https://brixsignage.com/llms.txt, and every page has a markdown twin (add .md to the path).
Source: https://brixsignage.com/developers/mcp/
Yes: you can control Brix digital signage from Claude or ChatGPT. Brix runs a hosted Model Context Protocol (MCP) server at https://api.brixsignage.com/v1/mcp. You connect by signing in, with no key to copy, and the MCP server is on every plan ($6 per screen per month billed annually, or $8 billed monthly).
- Works in: claude.ai, Claude Desktop and the Claude mobile apps (Brix is in Claude's connector directory), ChatGPT (Developer mode), Claude Code, Cursor, the Claude API and the OpenAI Responses API. Any client that takes a remote MCP URL works.
- Sign-in: OAuth 2.1 with PKCE. You pick the workspace, an optional location, and View only or View and change for each area. Or use an API key in developer tools.
- 15 tools, the same for every client (an API key adds 2 for uploading large files):
- Every kind of item (screens, media, playlists, schedules, layouts, creatives, apps, data sources, screen groups, locations, folders, emergency templates):
list_items,get_items,create_items,update_items,delete_items,restore_items - People: see who is in the workspace and their roles (
list_items,get_items), and invite a person (create_items) - Put content on screens:
set_screen_content(lasting),start_takeoverandend_takeover(existing content for a while, or an emergency) - Find and fix problems:
get_screen_status,capture_screenshot,control_screens(refresh, reboot, clear cache, TV on or off) - Approvals, data and reports:
review_approval(approve, reject or withdraw),refresh_data,get_fleet_report(uptime, proof of play, audit log)
- Every kind of item (screens, media, playlists, schedules, layouts, creatives, apps, data sources, screen groups, locations, folders, emergency templates):
- Deletes go to the recycle bin for 30 days and come back with
restore_items. A permanent delete takes two calls: the first only shows what would be erased and gives a code, and the second must carry that code after you say yes. No access to billing or API keys, and no changes to a person's access.
No Brix account yet? Start a 7-day free trial. No card needed.
The full list with arguments and permissions is in the tool catalog. Which other signage platforms have MCP, and how they compare: Control digital signage from Claude or ChatGPT.
Connection details
| Setting | Value |
|---|---|
| Endpoint | https://api.brixsignage.com/v1/mcp |
| Transport | Streamable HTTP. POST one JSON-RPC 2.0 message; the reply is a JSON response. No SSE stream. |
| Auth | Sign in with OAuth 2.1 (claude.ai, ChatGPT and other connector apps), or Authorization: Bearer <api key> with the same keys as the REST API. |
| Protocol versions | 2024-11-05, 2025-03-26, 2025-06-18 |
| Rate limit | 30 requests per minute per caller, inside the workspace's 600 per minute. Over it: HTTP 429 with Retry-After. |
| Methods | initialize, ping, tools/list, tools/call, resources/list, resources/templates/list, resources/read, prompts/list, prompts/get |
There are two ways to connect:
- Sign in (Claude, ChatGPT). In Claude, find Brix in the connector directory. In ChatGPT, add the endpoint as a plugin. In Claude you can also add it as a custom connector. The app opens a Brix page where you sign in and choose what it may do. No key to copy.
- API key (Claude Code, Cursor, Claude Desktop config file, the Claude and OpenAI APIs). Create a key and put it in the client's config.
Either way, the permissions you pick decide what the agent can do. See Authentication and scopes.
Find Brix in Claude's connector directory
Brix is listed in Claude's connector directory: claude.ai/directory/connectors/brix. Example requests and what Claude can do: Brix connector for Claude.
- In Claude, go to Customize > Connectors, click + and search for Brix. Or open the listing link above.
- Click Connect.
- Claude opens a Brix page. Sign in, then pick the workspace, a location if you want to limit Claude to one, and the permission areas. Click Allow.
This works in claude.ai, Claude Desktop and the Claude mobile apps, which share the same connectors. On a Team or Enterprise plan, an owner first adds Brix under Organization settings > Connectors, then each member connects it from Customize > Connectors.
Add Brix by URL (ChatGPT plugin, or Claude custom connector)
Use these steps for ChatGPT, or in Claude if you prefer to add the endpoint yourself.
- Copy the endpoint:
https://api.brixsignage.com/v1/mcp. - Add it to the app.
- Claude: Customize > Connectors, click +, then Add custom connector. Enter a name and the endpoint, then click Add.
- ChatGPT: first turn on Developer mode under Settings > Security and login (your workspace policy can hide it). Then go to chatgpt.com/plugins and select +. Enter a name and description, paste the endpoint under Connection, and create it.
- The app opens a Brix page. Sign in, then pick the workspace, a location if you want to limit the app to one, and the permission areas. Click Allow.
The app acts as you, with only the areas you picked. Viewing screens is always included, so if you pick no areas, the app can only view screens. You cannot give the app a permission you do not hold.
Whatever areas you pick, an app connected by signing in cannot use billing, payment, invoice, API key or single sign-on routes. It can see people and roles, and it can invite a person, but only with a role that does not manage people, roles, API keys, settings or billing. It cannot change, remove or re-role a person, or edit a role. A person does these in the CMS. API keys are not affected.
Every connection is listed in the CMS under Settings > AI, API & MCP > Connected apps, with who connected it and when it was last used. Revoke ends it at once: the app's next call is refused and it has to be connected again.
For client developers: the server follows the MCP authorization spec. A call without a token gets 401 with a WWW-Authenticate header that points to the protected-resource metadata at /.well-known/oauth-protected-resource/v1/mcp. The authorization server is https://api.brixsignage.com (metadata at /.well-known/oauth-authorization-server). It supports authorization code with PKCE (S256), dynamic client registration and client ID metadata documents. Access tokens last an hour. Refresh tokens rotate on every use. An access token from this flow works only at /v1/mcp.
API key clients
1. Create a key for the agent
In the CMS: Settings > AI, API & MCP > API keys > New key. Give it only the areas the agent needs. For a first try, a view-only key (Screens, Playlists, Schedules, Files, Proof of Play) is safe: the agent can answer questions but cannot change what plays.
The same page has a Model Context Protocol (MCP) section with the endpoint and Copy config and Copy command buttons.
Claude Code
claude mcp add --transport http brix https://api.brixsignage.com/v1/mcp \
--header "Authorization: Bearer $BRIX_API_KEY"
Then run claude and ask: "Which of my Brix screens are offline, and why?" Check the connection with /mcp.
Claude Desktop
To connect by signing in, connect Brix from Claude's connector directory (see above). To use a key instead: Claude Desktop's config file starts local (stdio) servers, so connect through the mcp-remote bridge. It needs Node.js. Open Settings > Developer > Edit Config and add:
{
"mcpServers": {
"brix": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://api.brixsignage.com/v1/mcp",
"--header", "Authorization:${BRIX_AUTH}"
],
"env": { "BRIX_AUTH": "Bearer ak_us_live_..." }
}
}
}
Restart Claude Desktop. The header value goes through env because some platforms split arguments that contain spaces.
Cursor
Add to ~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project):
{
"mcpServers": {
"brix": {
"url": "https://api.brixsignage.com/v1/mcp",
"headers": { "Authorization": "Bearer ${env:BRIX_API_KEY}" }
}
}
}
${env:BRIX_API_KEY} reads the key from your environment, so it stays out of the file. You can also paste the key in place of it. Open Cursor Settings > MCP to check that brix is connected.
Other clients that accept a remote URL with custom headers use the same shape. This is the config that Copy config in the CMS gives you:
{
"mcpServers": {
"brix": {
"url": "https://api.brixsignage.com/v1/mcp",
"headers": { "Authorization": "Bearer <YOUR_API_KEY>" }
}
}
}
OpenAI API
The OpenAI Responses API sends your key in a header to a remote MCP server:
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5",
"tools": [{
"type": "mcp",
"server_label": "brix",
"server_url": "https://api.brixsignage.com/v1/mcp",
"headers": { "Authorization": "Bearer '"$BRIX_API_KEY"'" },
"require_approval": "never"
}],
"input": "Which of my screens are offline?"
}'
"require_approval": "never" lets the model call tools without a pause. Use it with a view-only key, or set it to "always" and approve each call.
Claude API
The Messages API connects to remote MCP servers with the MCP connector:
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: mcp-client-2025-11-20" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5",
"max_tokens": 4096,
"mcp_servers": [{
"type": "url",
"name": "brix",
"url": "https://api.brixsignage.com/v1/mcp",
"authorization_token": "'"$BRIX_API_KEY"'"
}],
"tools": [{ "type": "mcp_toolset", "mcp_server_name": "brix" }],
"messages": [{ "role": "user", "content": "Which of my screens are offline?" }]
}'
Test the endpoint with curl
curl https://api.brixsignage.com/v1/mcp \
-H "Authorization: Bearer $BRIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_items","arguments":{"kind":"account"}}}'
A tool result comes back as a text block plus structuredContent. A failed tool call returns isError: true with the error text, so the agent can correct itself.
How the tools behave
- Start with
get_itemskindaccountin an unfamiliar workspace. It returns the key, the workspace and its permissions. - Every tool uses the same kind names.
list_itemsfinds ids by name;get_itemsreads items in full. Never guess an id. start_takeovershows existing content for a limited time (default one hour) or fires a prepared emergency. To show a new announcement, make it first withcreate_itemscreatives, then pass its id tostart_takeover.set_screen_contentchanges what a screen plays by default.create_itemsadds items of one kind. It also uploads files you hold (up to 5 files, 6 MB each), copies files from public links (500 MB each) and pairs a device by its 6-digit code.update_itemschanges one item or many with the same changes: playlist items, schedule blocks, screen group members, screen settings, a web link's crop or refresh. It also moves a screen to a new device (the new device's pairing code) and closes an alert by hand.delete_itemsmoves items to the recycle bin;restore_itemsbrings them back.- Tools never take sign-in values. A data feed that needs a sign-in or key (a POS, Stripe, Shopify, HubSpot, a private sheet) is connected by a person in the CMS under Content > Data sources, and tools then use it by its id.
create_itemsmakes the feeds that need no sign-in: a CSV URL, a Google Sheet published to anyone with the link, an iCal feed, a public transit stop or a public JSON URL. It refuses the rest and stores nothing. A stored sign-in value reads as••••••••; sending that back, or leaving it out, keeps what is stored. - Repeat for each row (beta, off until we turn it on for your workspace): one design and one data source play as a slideshow, one slide per row.
create_itemscreativesandupdate_itemstakedataSourceIdandrepeat: { over: "rows", secondsPerRow }(3 to 3600 seconds, default 12);repeat: nullturns it off. Without the feature, the call is refused with403 feature_disabledand nothing is saved.- Bind to the current row with
{{row.column}}in a text box'stext,row.columnin a field box'sfield, and{{row.photo}}as an image box'surl. A picture cell must be a plain https address.{{rows.0.column}}stays on the first row;update_itemsuseEachRow: truemoves those bindings to the current row, like Use each row in the CMS. - The column name is the sheet's header in lower case, with accents removed, every other character changed to
_, repeats collapsed and none at the ends:Date de débutisrow.date_de_debut,Région (€)isrow.region. - At most 200 rows and 3 MB of slides play, and each slide is a whole copy of the design, so a large design fits fewer rows.
get_itemsreturnsrepeatStatuson such a design:rowCount,rowsThatFit,limitedBy,columns,missingColumnsandwarnings. refresh_datasyncs the sheet. A sheet published to the web changes on Google's side up to about 5 minutes after an edit, so a sync straight after an edit can still read the old rows.- A Google Sheet published to anyone with the link works by tool. A sheet that needs a sign-in is connected by a person in the CMS, and tools then use it by its id.
- Bind to the current row with
- Every client gets the same tools. An API key also gets
mint_upload_urlandconfirm_media_uploadfor files over 6 MB. For anything without a tool, use the REST API with the same key. - Every tool declares MCP annotations: read-only, destructive, idempotent, and whether it reaches outside Brix. Clients use them to decide when to ask you first.
- Content created over MCP lands as a draft where the location requires approval.
- Changes made over MCP are recorded in the workspace audit log. Reads are not.
Things to ask
- "Which of my screens are offline, and why?"
- "Why is the lobby screen blank? Show me what it's displaying right now."
- "Put the Summer Menu playlist on every screen at the Downtown location for the next two hours."
- "How many times did the Burger Promo play last week, and on which screens?"
- "Give me this month's uptime report, worst screens first."
Your AI app asks before it runs a tool that changes what a screen shows.
Privacy, disconnecting and support
- The app sees only what the tools return for the workspace, location and permission areas you approved. Brix does not receive your conversation with the app, only the tool calls it makes.
- Disconnect any time in Brix under Settings > AI, API & MCP > Connected apps. Revoke ends the connection at once: the app's next call is refused. Removing the connector or plugin in the app stops the app using it.
- A connection record is deleted 30 days after the connection ends (revoked, refresh token expired, or sign-in never completed). The audit log entries stay for the audit log's normal retention period.
- Brix does not use data accessed through connected apps to train AI models. The app's provider handles what the app receives under its own terms.
- How Brix handles data is in the Privacy Policy. For help, email hello@brixsignage.com.
- To report a security problem, see Reporting a vulnerability.
Tool catalog
17 tools. Each needs the permission shown on the API key. Read-only tools never change anything; the others say what they change.
list_items
List items of one kind with their ids, so other tools can act on them.
When to use:
- A request names a screen, file, playlist or location and you need its id.
- Seeing what runs now (casts, emergencies), what is wrong now (alerts), approval requests, deleted items (recycle_bin), or who is in the workspace and what they may do (people, roles).
When NOT to use:
- Reading one item's contents: use get_items.
- History over time: use get_fleet_report.
What to know:
- Rows are short (id, name, nodeId, counts), never configs or members; only locations this connection can see. people rows add each person's role at each location (never sign-in details); roles rows add their permissions.
- A kind this connection cannot read is an error, not an empty list. people and roles are read-only here (invite with create_items); changing a person's access, roles, API keys and billing stays with a person in the Brix console. To see what this connection itself may do, use get_items kind account.
- media, alerts and recycle_bin come newest first. Every call counts toward the connection's 30 tool calls a minute, so page with offset instead of re-listing.
Parameters:
- kind: the list to read; app_types and connectors are what create_items can make. A connectors row's setup is here (create_items makes it) or console (a person connects it in the Brix console, and it is then used by its id).
- Filters (all optional, combined with AND, ignored on kinds they do not name): q (name contains, any kind but people and roles); status (screens online/offline/pairing; approvals pending by default, approved, rejected, withdrawn); nodeId (screens at that location and below; alerts at that location only); tag (screens, media); mediaKind and folderId (media); severity and screenId (alerts); binKind (recycle_bin).
- limit: page size for media and approvals (default 50); other kinds give 100 a page. offset: pass nextOffset while hasMore.
- Example: {kind:"screens", status:"offline", nodeId:"on_west"}.
Permission: the kind's view permission. Behavior: read-only.
| Argument | Type | Required | Description |
|---|---|---|---|
kind | screens | media | playlists | schedules | layouts | creatives | apps | data_sources | screen_groups | locations | media_folders | emergency_templates | casts | emergencies | alerts | approvals | recycle_bin | app_types | connectors | people | roles | yes | The collection to read. The tool description says what the less obvious kinds hold. |
q | string | no | Text that the item's name must contain. |
status | online | offline | pairing | pending | approved | rejected | withdrawn | no | Only screens in this connection state, or only approval requests in this review state. Left out, screens in every state are listed, and approval requests that still wait for a decision. |
nodeId | string | no | Only screens or alerts at this location. A location id comes from list_items kind locations. |
tag | string | no | Only screens or files that carry this tag, a label people put on them in the console. |
mediaKind | string | no | Only files of this type, for example image or video. |
folderId | string | no | Only files in this media folder. A folder id comes from list_items kind media_folders. |
severity | info | warning | critical | no | Only alerts of this urgency. |
screenId | string | no | Only alerts about this screen. A screen id comes from list_items kind screens. |
binKind | string | no | Only deleted items of this kind from the recycle bin. |
limit | integer | no | The page size for files and approval requests. Left out, a page holds 50 of them. Other kinds have a fixed page size. |
offset | integer | no | Where the page starts: the nextOffset value the previous page returned. |
get_items
Read items of one kind in full.
When to use:
- Before update_items, to see current values and part ids (playlist items pli_…, schedule blocks sb_…).
- Checking how many rows of a sheet a repeating creative plays, and how many fit.
- Checking an approval request, a fired emergency, a device test run, a person's locations and roles, a role's permissions, or who this connection is (kind account).
When NOT to use:
- Searching by name: use list_items first.
- Why a screen is blank, its outages or its TV state: use get_screen_status (get_items returns a screen's settings and assigned content).
What to know:
- Returns a playlist's items in order, a schedule's blocks, a layout's zones, an app's config, a screen's status and content.
- kind app_types, with app type keys from list_items as ids: each app's settings (key, kind, label, help, options with their values, default, required). create_items and update_items check an app's config against them.
- A Now Serving or Goal Tracker app also returns staffLinks (controlUrl, staffCardUrl, takeNumberUrl) when this connection may edit it; a connection that may only view it gets none.
- A creative that repeats for each row also returns repeatStatus: rowCount and rowsThatFit (what the last sync holds and how many play), limitedBy (rows, bytes or null), loopSeconds, columns (each header and its row tag), missingColumns, firstRowBindings, lastSyncedAt and warnings to pass on. rowCount is null when this connection cannot read that data source.
- Sign-in details of feeds and web links stay in the Brix console: a stored one reads as ••••••••, never as its value. Items outside this connection's locations read as not found.
Parameters:
- kind: the kind of every id. account takes no ids and returns this connection's actor, workspace and permissions.
- ids: prefix-typed ids from list_items (pl_… playlist, scr_… screen, sch_… schedule); required for every kind but account. Each id returns its item or not found; the rest still return.
- device_test_runs: call again until status is finished.
- Example: {kind:"playlists", ids:["pl_8f2c"]}.
Permission: the kind's view permission. Behavior: read-only.
| Argument | Type | Required | Description |
|---|---|---|---|
kind | screens | media | playlists | schedules | layouts | creatives | apps | data_sources | screen_groups | locations | media_folders | emergency_templates | approvals | emergencies | device_test_runs | people | roles | account | app_types | yes | The kind of item that every id names. |
ids | array | no | The items to read, by id. Ids come from list_items. |
create_items
Create new items of one kind.
When to use:
- Adding anything new, uploading files (media_files for bytes you hold, media_from_urls for public links), pairing a device by its code or inviting a person.
When NOT to use:
- Changing an existing item: use update_items.
- Showing it on screens: create it, then use set_screen_content or start_takeover.
What to know:
- playlists, schedules, locations and creatives are all-or-nothing: one bad row rejects the call and names it (a location whose externalId exists is skipped, so imports re-run safely). Other kinds are created one by one; each reports ok or its error and the rest continue.
- Returns each new item's id and name, to pass to the other tools, and each item that was not created with the reason.
- New content at a location under review starts as a draft. Needs the kind's create permission there.
- Tools never take sign-in values: a data_sources or apps item holding one, or a feed that cannot work without one, is refused and nothing is created. A person connects those in the Brix console; the feed is then used by its id.
- Now Serving and Goal Tracker apps: leave out the control code (the server makes it). The result has staffLinks: controlUrl (the staff page that calls numbers), staffCardUrl (a card to print) and, when customers take numbers on their phones, takeNumberUrl. Give them to the staff only: anyone with controlUrl can change the number. The prompt set_up_now_serving walks the whole setup.
- Repeat for each row (one slide per row of a sheet): the rules are in the repeat field's description. A workspace without the feature refuses it with 403 feature_disabled.
Parameters:
- Pass exactly one array; its name is the kind and two arrays is an error.
- Ids inside items (refId, contentId, nodeId, screenId, appKey, connector) must already exist; get them from list_items.
- Example: {playlists:[{name:"Lobby loop", items:[{refKind:"media", refId:"med_logo", durationSec:10}]}]}.
Permission: the kind's create permission. Behavior: creates, reaches outside Brix.
| Argument | Type | Required | Description |
|---|---|---|---|
playlists | array | no | Playlists to create, max 500 per call. |
schedules | array | no | Schedules to create, max 200 per call. |
locations | array | no | Locations (org-tree nodes) to create, max 1000 per call. List a parent before its children. |
celebrations | array | no | Celebration entries to import, max 100 per call. |
creatives | array | no | Creatives to create, max 100 per call. |
screens | array | no | Pair new devices, max 20. Each device shows a 6-digit pairing code on its screen; the code pairs it into this workspace. |
screen_groups | array | no | Screen groups, max 50. A group is a flat label across locations; it grants no permissions. |
web_links | array | no | Live web pages or dashboards for the media library, max 50. Set crop, scroll and refresh after with update_items kind media. |
media_from_urls | array | no | Files (image, video, PDF, audio) copied from public URLs into the media library, max 20 per call and 500 MB each. Copies land at the workspace root, so a connection limited to one location is refused. |
media_files | array | no | Files whose bytes you hold (an image you made, a file the person pasted), uploaded straight into the media library, 6 MB each. |
layouts | array | no | Multi-zone layouts, max 50. A new layout starts with one full-screen zone; set zones with update_items (read a layout with get_items to copy its zone shape). |
apps | array | no | App instances (weather, clock, menu board, Now Serving, …), max 50. Find appKey values with list_items kind app_types, and an app's settings with get_items kind app_types. |
data_sources | array | no | Data feeds that need no sign-in, max 20: a CSV URL, a Google Sheet published to anyone with the link, an iCal feed, a public transit stop, or a public JSON URL. A feed that needs a sign-in or key (POS, Stripe, Shopify, HubSpot, a private sheet) is connected by a person in the Brix console and refused here; use it by its id from list_items kind data_sources. list_items kind connectors shows each type's setup. |
media_folders | array | no | Media library folders, max 50. |
emergency_templates | array | no | Pre-armed emergency takeovers (Lockdown, Fire drill, …), max 50. Fire one with start_takeover emergencyTemplateId. |
people | array | no | Invite people, max 10. Each gets an email invitation; inviting someone already here adds the missing locations. Roles that manage people, roles, API keys, settings or billing are refused: a person gives those in the Brix console. |
device_test_runs | array | no | Device Lab test runs, max 10. Each queues at once; read results with get_items kind device_test_runs. Suites content, soak, chaos and full change what the screen plays while they run; chaos and full run only on internal or test-tagged screens. |
update_items
Change existing items of one kind, the same changes on every id.
When to use:
- Renaming, moving or retagging items; editing what is inside a playlist, schedule, layout or screen group; screen, web link and data feed settings; swapping a screen's device; closing an alert.
- Turning Repeat for each row on, changing its seconds or turning it off on a creative (repeat, useEachRow).
- Franchise menus: share a creative live with child workspaces (shareWithWorkspaces), and set one location's own prices on a creative shared to it (localText).
When NOT to use:
- Showing content on screens: use set_screen_content.
- New items: use create_items. Removing: use delete_items.
What to know:
- Per id, changes run as steps in a fixed order and stop at that id's first failure; earlier steps stay and are named; other ids go on. Each id returns the item as it is now.
- Content that airs where review is required goes back to draft. Needs the kind's edit permission (screen moves: at both locations).
- Changes go live at once: every screen playing an edited playlist, schedule or layout shows the new version at its next sync. There is no undo; overwritten values and removed playlist items are gone, so note the old values with get_items first.
- Repeat for each row (one slide per row of a sheet): the rules are in the repeat field's description. A workspace without the feature refuses it with 403 feature_disabled.
Parameters:
- kind and ids: every id must be of that kind; get them from list_items. Every id gets identical changes; for different values per item, call once per value.
- changes: only the fields to change. Each field's description names the kinds that take it; a field the kind does not take is refused before anything changes.
- zones, boxes, config and tags replace the whole value: read it with get_items first.
- Example: {kind:"screens", ids:["scr_lobby7", "scr_lobby8"], changes:{nodeId:"on_store12", tags:["lobby"]}}.
Permission: the kind's edit permission. Behavior: changes existing data, reaches outside Brix.
| Argument | Type | Required | Description |
|---|---|---|---|
kind | screens | media | playlists | schedules | layouts | creatives | apps | data_sources | screen_groups | locations | media_folders | emergency_templates | alerts | yes | The kind of item that every id names. |
ids | array | yes | The items to change, by id. Ids come from list_items. |
changes | object | yes | The fields to change and their new values. A field left out keeps its value. |
delete_items
Delete items of one kind into the 30-day recycle bin.
When to use:
- The person has confirmed what should go (show it with list_items or get_items first).
When NOT to use:
- Taking a screen out of a group: use update_items removeScreenIds.
- Stopping a takeover: use end_takeover.
What to know:
- restore_items undoes a delete within 30 days. A deleted playlist or schedule stops on every screen playing it; a deleted screen's device returns to pairing; a deleted location hands its content to its parent.
- Refused: the root, a location with child locations, items shared to another workspace. Each id reports ok or its error. Needs the kind's delete permission.
Parameters:
- kind and ids: every id must be of that kind.
- permanent: true erases for good instead (recycle-bin kinds only). The first call deletes nothing and returns wouldErase and a confirmCode.
- confirmCode: only with permanent:true; send the code from the first call, after the person says yes, with the same kind and ids. It lasts 10 minutes and fits only those ids; without permanent it is an error.
- Example: {kind:"playlists", ids:["pl_8f2c"]}.
Permission: the kind's delete permission. Behavior: changes existing data, idempotent, reaches outside Brix.
| Argument | Type | Required | Description |
|---|---|---|---|
kind | screens | media | playlists | schedules | layouts | creatives | apps | data_sources | screen_groups | locations | media_folders | emergency_templates | yes | The kind of item that every id names. |
ids | array | yes | The items to delete, by id. Ids come from list_items. |
permanent | boolean | no | Erase the items for good and skip the recycle bin. This needs a second call with confirmCode. |
confirmCode | string | no | The code the first permanent call returned, sent back after the person agrees. |
restore_items
Bring back deleted items of one kind from the 30-day recycle bin.
When to use:
- Undoing delete_items.
When NOT to use:
- Items deleted more than 30 days ago: they are gone and report not found.
What to know:
- Whatever used a restored item (playlists, screens) uses it again; a restored screen re-pairs by itself if its device still holds its pairing. Each id reports ok or not found. Needs the kind's delete permission.
Parameters:
- kind: the list_items kind name, so a recycle_bin row of kind playlist is restored with kind playlists.
- ids: up to 50, from list_items kind recycle_bin. An id that is not in the bin reports "not in the recycle bin"; one deleted over 30 days ago reports not found.
- Example: {kind:"playlists", ids:["pl_8f2c"]}.
Permission: the kind's delete permission. Behavior: creates, idempotent, reaches outside Brix.
| Argument | Type | Required | Description |
|---|---|---|---|
kind | screens | media | playlists | schedules | layouts | creatives | apps | data_sources | media_folders | screen_groups | yes | The kind of item that every id names. |
ids | array | yes | The deleted items to bring back, by id. Ids come from list_items kind recycle_bin. |
set_screen_content
Set what screens play by default until it is changed again.
When to use:
- Putting a playlist, schedule, app, media file or creative on one screen, a list, or every screen under a location.
When NOT to use:
- A takeover that ends by itself: use start_takeover.
- Changing what a playlist contains: use update_items (every screen playing it follows).
What to know:
- Screens update within seconds. In a bulk call, screens the content is not shared to or whose location needs approval for it are skipped and counted (notShared, needsApproval); the rest change. Needs screen.cast.
Parameters:
- screenId, screenIds and nodeId (every screen at and under it, up to 1000): give at least one; they combine into one set.
- contentKind: playlist, schedule, app, media or creative. null clears what plays and needs exactly one screen and no nodeId.
- contentId: the playlist, schedule, app, media or creative id from list_items; omit only with contentKind null.
- Example: {nodeId:"on_ca", contentKind:"playlist", contentId:"pl_spring"}.
Permission: none. Behavior: changes existing data, idempotent, reaches outside Brix.
| Argument | Type | Required | Description |
|---|---|---|---|
screenId | string | no | The one screen that gets the content. A screen id comes from list_items kind screens. |
screenIds | array | no | The screens that get the content, when there are several. Screen ids come from list_items kind screens. |
nodeId | string | no | A location: every screen at it and under it gets the content. A location id comes from list_items kind locations. |
contentKind | playlist | schedule | app | media | creative | yes | The kind of content that contentId names. A null value clears what one screen plays. |
contentId | string | no | The content to play, by id, from list_items of that kind. It must be of contentKind. Leave it out only to clear a screen, with contentKind null. |
start_takeover
Show something on screens over their normal content, now.
When to use:
- Existing content for a while (the lunch menu until 2 pm), or a pre-armed emergency.
When NOT to use:
- A lasting change: use set_screen_content.
What to know:
- Content ends by itself; an emergency stays above everything until end_takeover, so confirm its scope with the person first. Returns castId for end_takeover. Needs screen.cast.
Parameters:
- Pass exactly one of: contentId with contentKind (from list_items), or emergencyTemplateId (from list_items kind emergency_templates).
- scopeKind: all (default, every screen this connection reaches), node with scopeNodeId, or screens with screenIds. An emergency ignores scope and uses its template's.
- expiresAt: ISO 8601 with offset, default one hour from now.
- Example: {contentKind:"playlist", contentId:"pl_lunch", scopeKind:"node", scopeNodeId:"on_store12", expiresAt:"2026-10-20T14:00:00-07:00"}.
Permission: screen.cast. Behavior: changes existing data, reaches outside Brix.
| Argument | Type | Required | Description |
|---|---|---|---|
contentKind | media | playlist | app | creative | schedule | no | The kind of content that contentId names. |
contentId | string | no | The content to show during the takeover, by id, from list_items of that kind. |
emergencyTemplateId | string | no | A saved emergency message to fire, in place of contentKind and contentId. Ids come from list_items kind emergency_templates. |
scopeKind | all | node | screens | no | Which screens the takeover reaches: all of them, one location, or a list of screens. |
scopeNodeId | string | no | The location whose screens are taken over, with every location under it. A location id comes from list_items kind locations. |
screenIds | array | no | The screens that are taken over, when the scope is a list of screens. Screen ids come from list_items kind screens. |
expiresAt | string | no | The time the takeover ends and screens return to their normal content, as an ISO 8601 date and time with offset. Left out, it ends one hour after it starts. |
headline | string | no | A name for this takeover in lists of what runs now. Use it with contentId only. |
end_takeover
End a running takeover or emergency on every screen it covers, in one call.
When to use:
- Taking down what start_takeover started, early.
When NOT to use:
- Changing default content: use set_screen_content.
- Calling once per screen: one call ends it everywhere.
What to know:
- Screens return to their normal content at once. Ending one that already ended succeeds with alreadyEnded:true; an unknown id fails and lists what is running. Needs screen.cast (emergency-override.create for an emergency).
Parameters:
- castId: the castId start_takeover returned, an emergency id (emg_…), the id of the content on screen, or the takeover's exact headline. The last two end every running takeover of it. Find running ones with list_items kind casts or emergencies.
Permission: screen.cast. Behavior: changes existing data, idempotent, reaches outside Brix.
| Argument | Type | Required | Description |
|---|---|---|---|
castId | string | yes | The takeover to stop: the castId that start_takeover returned, or an id from list_items kind casts or emergencies. |
get_screen_status
Explain the state of one screen.
When to use:
- Why a screen shows what it shows, why it is blank or wrong, when it was down, or what its TV did.
When NOT to use:
- A screen's settings, tags or assigned content: use get_items kind screens.
- Many screens: use get_fleet_report. A picture: use capture_screenshot. A fix: use control_screens.
What to know:
- Reads what the screen already reported and never contacts it, so it answers for offline screens. Needs screen.view.
Parameters:
- screenId: one scr_… id from list_items kind screens.
- view: why (the source on screen: deactivated, emergency, takeover, schedule or default); diagnose (likely cause plus a checklist; guided:true marks a TV/input/cable guess, not a reading); outages (each outage with length and cause); tv (TV off, other input, cable lost; Signage Sticks only).
- days: outages default 30; tv default and max 14. limit: default 50; max 200 for outages, 500 for tv. Both are ignored for why and diagnose.
- Example: {screenId:"scr_lobby7", view:"outages", days:7}.
Permission: screen.view. Behavior: read-only.
| Argument | Type | Required | Description |
|---|---|---|---|
screenId | string | yes | The screen to explain. A screen id comes from list_items kind screens. |
view | why | diagnose | outages | tv | yes | The question to answer about the screen. The tool description says what each view returns. |
days | number | no | How many days back the outage or TV history goes. Left out, outages go back 30 days and TV history 14. |
limit | number | no | A cap on the outage or TV history rows, newest first. Left out, 50 rows return. |
capture_screenshot
Take a new screenshot of one screen and return it as an image; nothing on the screen changes.
When to use:
- Checking what a screen shows, e.g. after set_screen_content or control_screens.
When NOT to use:
- Learning why: use get_screen_status. Polling in a loop.
What to know:
- Waits up to about 5 seconds; a slow or offline screen returns its last frame with fresh:false. A frame over 2 MB returns latestFrameUrl only. Needs screen.edit (it sends a device command).
Parameters:
- screenId: one scr_… id from list_items kind screens; for several screens, call once each. An id outside this connection's reach reads as not found and nothing is sent.
Permission: screen.edit. Behavior: creates, reaches outside Brix.
| Argument | Type | Required | Description |
|---|---|---|---|
screenId | string | yes | The screen to take a picture of. A screen id comes from list_items kind screens. |
control_screens
Send a device action to one or many screens.
When to use:
- A change has not appeared, a screen is frozen, an old or broken file keeps playing, or the TV must go on or off.
When NOT to use:
- Changing content: use set_screen_content. New data from a feed or web page: use refresh_data.
What to know:
- Devices act within seconds; offline ones act when they come back. Check the result with capture_screenshot. Needs screen.edit.
Parameters:
- action: refresh (reload content, no restart; try first), reboot (restart; about a minute blank), clear_cache (delete stored files so they download again; media shows late meanwhile), tv_on or tv_off (HDMI-CEC TVs only; the player keeps running).
- screenId and screenIds: give either or both; they combine into one set, each screen gets the action once, and screens out of reach are skipped.
- Example: {action:"refresh", screenIds:["scr_7", "scr_8"]}.
Permission: screen.edit. Behavior: changes existing data, reaches outside Brix.
| Argument | Type | Required | Description |
|---|---|---|---|
action | refresh | reboot | clear_cache | tv_on | tv_off | yes | What each device does. The tool description says what each action costs; start with the lightest one. |
screenId | string | no | The one screen that gets the action. A screen id comes from list_items kind screens. |
screenIds | array | no | The screens that get the action, when there are several. Screen ids come from list_items kind screens. |
review_approval
Approve, reject or withdraw one pending approval request.
When to use:
- This connection's person is an approver and a request is waiting (list_items kind approvals; read it with get_items kind approvals).
- Cancelling a request that is no longer wanted, or one left behind by a person who has gone: withdraw.
When NOT to use:
- Editing the content: use update_items (an edit opens a new request).
What to know:
- approve airs the content where it is assigned, at once; reject keeps it off screens; withdraw closes the request with no decision and puts the content back to draft. Each is final.
- approve and reject need this connection's person to be an approver in the request's chain; withdraw needs the requester or such an approver. Otherwise the call is refused.
Parameters:
- approvalId: an ar_… id from list_items kind approvals.
- reason: required with reject and shown to the requester word for word; with approve, an optional note; ignored with withdraw.
- Example: {approvalId:"ar_12", decision:"reject", reason:"Price on slide 2 is wrong."}.
Permission: an approver for the request. Behavior: changes existing data, reaches outside Brix.
| Argument | Type | Required | Description |
|---|---|---|---|
approvalId | string | yes | The approval request to act on. Ids come from list_items kind approvals. |
decision | approve | reject | withdraw | yes | The outcome for the request. Each outcome is final. |
reason | string | no | A note for the person who asked. They see it with the decision. A rejection needs it; left out of an approval, the decision carries no note. |
refresh_data
Pull fresh content now instead of at the next scheduled refresh.
When to use:
- Before an announcement, so menus and prices are current; after someone edits a sheet that a creative repeats over; after changing a web link's crop with update_items, to see the result.
When NOT to use:
- Changing a feed's or link's settings: use update_items. A screen that has not picked up a change, or is frozen: use control_screens.
What to know:
- Settings never change. A failing feed is reported in the result, not thrown. Screens showing the data update when a sync succeeds. Needs integration.edit for feeds, media.edit for a web link.
- A sheet published to the web changes on Google's side up to about 5 minutes after an edit, so a sync straight after an edit can still read the old rows: synced true says the sync ran, not that the edit arrived. Check rowCount with get_items and sync again after a few minutes if it is old.
Parameters:
- Pass exactly one; none or two is an error.
- dataSourceId: one ds_… feed from list_items kind data_sources.
- allDataSources: true syncs every feed you can edit, one after another; one failure does not stop the rest; limited to 5 calls a minute.
- webLinkId: one med_… web link (list_items kind media, mediaKind web); renders a new snapshot.
Permission: integration.edit (media.edit for a web link). Behavior: creates, idempotent, reaches outside Brix.
| Argument | Type | Required | Description |
|---|---|---|---|
dataSourceId | string | no | The data source to sync now. Ids come from list_items kind data_sources. |
allDataSources | boolean | no | Sync every data source in the workspace, in place of one id. |
webLinkId | string | no | The web link whose picture is taken again. Ids come from list_items kind media. |
get_fleet_report
Read a report across screens for a time window.
When to use:
- Uptime and outage causes, what actually played, or who changed what.
When NOT to use:
- One screen's detail: use get_screen_status. What is wrong now: use list_items kind alerts.
What to know:
- Reads stored history only; only screens this connection can see count. Needs screen.view (uptime), playback-log.view (proof_of_play) or audit-log.view (audit_log).
Parameters:
- report: uptime (online % per screen, outages with causes, worst first, one-line insights), proof_of_play (plays, watch time, skips and failures per content, and where) or audit_log (who changed what, newest first, by name).
- from and to: uptime and proof_of_play only; ISO 8601; default the whole stored window (30 days for uptime) up to now; a non-ISO value is refused. screenId: uptime and proof_of_play only, one screen. screenIds, contentIds and detail: proof_of_play only.
- since, limit (default 50) and cursor (nextCursor of the previous page): audit_log only.
- Parameters for another report are ignored. Example: {report:"uptime", from:"2026-10-13T00:00:00Z"}.
Permission: per report. Behavior: read-only.
| Argument | Type | Required | Description |
|---|---|---|---|
report | uptime | proof_of_play | audit_log | yes | The report to read. The tool description says what each report holds. |
from | string | no | The start of the time window the report covers, as an ISO 8601 date and time. Left out, the window starts at the oldest stored history. |
to | string | no | The end of the time window the report covers, as an ISO 8601 date and time. Left out, the window ends now. |
screenId | string | no | Only this screen counts in the report. A screen id comes from list_items kind screens. |
screenIds | array | no | For proof of play: only plays on these screens count. Screen ids come from list_items kind screens. |
contentIds | array | no | For proof of play: only plays of these items count, for example one advertiser's ads. An id is the id of a file, playlist, app or creative from list_items of that kind. |
detail | screens | no | For proof of play: adds a breakdown with one row per content item and screen. Left out, the report has one row per content item. |
since | string | no | For the audit log: only events at or after this time, as an ISO 8601 date and time. Left out, the newest events come first with no start time. |
limit | integer | no | For the audit log: the page size. Left out, a page holds 50 events. |
cursor | string | no | Where the next page starts: the cursor value the previous page returned. |
mint_upload_url
Get a one-shot upload URL for a large file. The model's host PUTs bytes to it then calls confirm_media_upload with the same uploadId.
Permission: media.create. Behavior: creates.
| Argument | Type | Required | Description |
|---|---|---|---|
contentType | string | yes | MIME type of the file, e.g. video/mp4 or image/png. |
name | string | yes | Display name for the asset. |
confirm_media_upload
Finalize an upload after PUTting bytes to a mint_upload_url. Creates the media_assets row.
Permission: media.create. Behavior: creates.
| Argument | Type | Required | Description |
|---|---|---|---|
uploadId | string | yes | The upl_… id that mint_upload_url returned. |
folderId | string | no | Library folder to file it in; omit for the library root. |
tags | array | no | Tags to set on the new asset. |
Resources
Read with resources/read. Each one checks its own view permission.
brix://screens: Every screen in the workspace, with status + location + assigned content.brix://playlists: Playlists with their items (refKind/refId/duration), approval state and org node.brix://schedules: Time-of-day schedules and which screens they target.brix://alerts/open: Currently open alert events — anything offline / storage-critical / playback-failing.brix://org-tree: The hierarchical org-node structure (Spaces / districts / schools / rooms).brix://media: Images, videos, PDFs, web links and fonts — id, name, kind, folder, tags, state.brix://creatives: Canvas creatives (data-bound designs) with stage + box count.brix://apps: Installed app instances (weather, RSS, menus…) with their app key + node.brix://layouts: Multi-zone layouts a screen can be pointed at, each with itstheme(the Brand Kit look — { source: "brand", mode?, radius? } — or null for a bare canvas). Zone geometry, bindings and per-zoneframe/radius/rolecome from GET /v1/layouts/:id.brix://data-sources: Connected data feeds (CSV, Sheets, POS…) with connection + last-sync status.brix://screen-groups: Named saved cohorts of screens — the unit for bulk commands and casts.brix://emergency-templates: Pre-armed emergency takeover recipes; pass one's id to start_takeover as emergencyTemplateId.brix://approvals/pending: Content awaiting an approve/reject decision before it can air.brix://screens/{screenId}/why: The resolution chain (deactivated / emergency / cast / scheduled / default) for one screen.brix://playlists/{playlistId}: One playlist WITH its ordered items.brix://media/{mediaId}/usage: Where a media asset is used (playlists/creatives/layouts) and when it last played.
Prompts
fleet_health_report: A daily ops digest: fleet status, open alerts, worst uptime offenders and what to do about each.diagnose_offline_screen: Walk the likely-cause diagnosis for one screen and hand back a guided next-step checklist. Arguments:screen_id(optional).onboard_new_location: Set up a new org location end-to-end: create the node, home its screens there and assign starter content. Arguments:location_name.weekly_content_review: Proof-of-play rollup for the last 7 days: top content, skipped/failed plays, unused media worth pruning.set_up_now_serving: Set up a Now Serving queue board end to end: the app with its counters, on a screen, and the staff link and card for the people who call numbers. Arguments:business_name,counters(optional).