Tool reference

All 409 tools, grouped by what they do — reads, device control, entries, scripting, settings, and more.

Every tool the Busymate MCP server exposes, grouped by what it does. There are 409 tools in total — a one-to-one mirror of the dashboard's read/write surface.

How to read this page

Each tool carries permission gating, enforced server-side on every call:

  • section:view / section:edit — a capability check against your RBAC role. You need the named capability (e.g. devices:edit) for the call to run. Built-in admin grants all; built-in viewer is read-only.
  • confirm-gated — a destructive action that requires an explicit confirm: true (or confirm: "all") argument. The agent must opt in deliberately; a stray call is rejected.
  • admin-only — restricted to admin roles regardless of capabilities.

Tools are scoped to your account and RLS — you only ever see and touch your own devices, entries, and settings.


Generic CRUD — db_* (5)

Low-level PostgREST access to allowlisted tables. The section gate is per-table: each table maps to a capability section, and db_select/db_rpc need view, the mutators need edit. Update and delete reject empty filters.

ToolWhat it doesGating
db_selectGeneric select against an allowlisted table (columns, filters, order, limit, offset).per-table :view
db_insertGeneric insert / upsert (with onConflict).per-table :edit
db_updateGeneric update; empty filters rejected.per-table :edit
db_deleteGeneric delete; empty filters rejected.per-table :edit
db_rpcCall an allowlisted Postgres function.per-table :view

Realtime & introspection (2)

ToolWhat it doesGating
realtime_broadcastSend a Broadcast message on a Realtime channel (the same fan-out the dashboard uses).global:edit
list_tablesList the tables / RPCs available to the generic CRUD tools.global:view

Device reads (3)

ToolWhat it doesGating
list_devicesList devices — YOUR OWN by default (owner-scoped), or the whole fleet with all:true (devices:view operators, re-verified server-side). Slim rows: uuid/name/model/platform/os_version, parent linkage (host NAME resolved), online + vpn_state, per-device connection type override, pac_port/pac_url.devices:view (own devices via owner-fallback)
test_pac_connectionPROVE whether PAC capture actually works for ONE device — 8 checks, each pass/fail/unverified with a specific human fix: connection mode, PAC port + URL, the served PAC is a PROXY directive and NOT the silent DIRECT fallback (the headline), egress IP allowlisted, the proxy is really routing its traffic, a NON-EMPTY effective SSL list that covers hosts it contacts, genuinely DECRYPTED in-scope traffic (a CONNECT/raw-TCP row is never counted as proof), and the device-reported CA-trust readiness. A check that could not verify returns unverified, never a pass.devices:view (own/demo devices via owner-fallback)
get_deviceFetch one device by uuid or name.devices:view
get_device_statusLive status / heartbeat for a device.devices:view

Device realtime control (8)

Control flows delivered over Realtime to a paired device. The destructive ones are confirm-gated.

ToolWhat it doesGating
rename_deviceRename a device.devices:edit
delete_deviceDelete a device record.devices:edit · confirm-gated
unpair_deviceUnpair / revoke a device.devices:edit · confirm-gated
vpn_on_deviceTurn the on-device VPN tunnel on.devices:edit
vpn_off_deviceTurn the on-device VPN tunnel off.devices:edit
open_sheet_deviceRemotely open the iOS app's settings / cert / pac sheet (foreground only).devices:edit
set_device_connection_typeSet a device's connection type (e.g. VPN vs PAC).devices:edit
set_live_activity_messageSet or clear the per-device Live Activity lock-screen pill text.devices:edit

External / upstream proxy control (2)

Route a device's egress through an upstream proxy so its public IP and country become the proxy's.

ToolWhat it doesGating
list_proxiesList available proxies from the MyPrivateProxy pool (filter by country / free-text). Credentials never returned.devices:view
set_device_external_proxySet or clear a device's upstream proxy — by country (auto-select a healthy proxy) or explicit host+port.devices:edit · confirm-gated

Remote browser / CDP control (7)

Drive a real Chrome that a bmc (cdp-connector) device controls. Every command needs the per-device remote-control opt-in to be ON; the raw escape hatch is admin-only.

ToolWhat it doesGating
set_device_cdp_controlTurn the per-device remote-browser/farm opt-in on / off (ON by default for an automation-class device — a CDP browser / bmc-daemon host / bmfarm host — owner-gated opt-out; a personal/iOS device stays OFF).devices:edit
browser_targetsList the open browser targets / tabs the device controls.devices:edit
browser_openOpen a URL in the controlled Chrome.devices:edit
browser_evalEvaluate JavaScript in a target (resolves {{VAR}} env refs server-side).devices:edit
browser_screenshotCapture a screenshot of a target.devices:edit
browser_snapshotCapture an accessibility / DOM snapshot of the page.devices:edit
browser_cdpSend a raw Chrome DevTools Protocol command (arbitrary-code power).devices:edit · admin-only

Named CDP device daemon (5)

Lifecycle of named CDP "devices" (Chrome instances on a bmc machine), plus hot-updating the daemon itself. The mutators are confirm-gated.

ToolWhat it doesGating
list_cdp_instancesList the named CDP instances a machine runs.devices:view
start_deviceStart a named CDP device.devices:edit · confirm-gated
stop_deviceStop a named CDP device.devices:edit · confirm-gated
create_deviceProvision a new named CDP device (fresh port + profile, pairs its JWT).devices:edit · confirm-gated
update_cdp_hostHot-update the bmc daemon on a machine to the latest build and recycle its supervisor — running captures keep capturing (re-adopted), remote control is briefly unavailable while it reconnects.devices:edit · confirm-gated

Custom browser profiles (4)

CRUD over the browser_profiles table of custom Chromium-family launch profiles authored in the dashboard (Settings → CDP) and synced to the bmc CLI. The five built-ins (chrome / brave / edge / godbrowser / chromium) live in the CLI code — they're reserved slugs and never appear here.

ToolWhat it doesGating
list_browser_profilesList custom browser profiles (slug, display name, binaries, default flags, flag catalog, CDP notes).devices:view
get_browser_profileGet one custom profile by slug or id — full detail.devices:view
upsert_browser_profileCreate or update a custom profile (matched by slug); reserved built-in slugs are rejected.devices:edit · confirm-gated
delete_browser_profileDelete a custom profile by slug or id.devices:edit · confirm-gated

Android farm (28)

The Android farm (#148) pairs one HOST device per Mac Mini (platform: android-host) and models each connected phone as its own UUID-keyed child android device row, parented to the host (parent_device_id). The Edge function can't run ADB, so every farm control tool dispatches a farm-command to the host over its private device:<uuid> Realtime channel and awaits farm-result — the same host-routed pattern as the CDP daemon tools, gated by the host's cdpControlEnabled opt-in. Identify the host with device_uuid/deviceName; target specific phones with child_uuid/child_uuids (the route-key uuid, never the volatile ADB serial), or omit to target all online phones. The raw executors carry arbitrary device control (browser_cdp-tier) — they're admin-gated, iOS-refused, and never offered to the BusyBro chat LLM.

ToolWhat it doesGating
provision_farm_phoneCreate / update / remove a child android phone row via the farm_provision_child DEFINER RPC (UUID-keyed, parented to the host).devices:edit · confirm-gated
list_farm_devicesList the farm fleet (hosts + their child phones) from the devices table (no host dispatch).devices:view
farm_list_phonesLive adb view of the phones on a host (serial / state / model / Android / battery).devices:view · opt-in ON
farm_capture_statusRead how farm capture is wired (the shared hardened proxy-server path).devices:view · opt-in ON
farm_screenshotPNG screenshot of ONE phone (by child_uuid).devices:view · opt-in ON
farm_dump_uiOn-screen UI hierarchy (interactable nodes) of the targeted phone(s).devices:view · opt-in ON
farm_list_automationsList the host's available automation scripts.devices:view · opt-in ON
farm_list_recordingsList the host's saved input recordings.devices:view · opt-in ON
farm_list_schedulesList the host's active scheduled jobs.devices:view · opt-in ON
farm_find_and_tapFind a UI element by text / resource-id and tap it on the targeted phone(s).devices:edit · opt-in ON · confirm-gated
farm_set_settingsettings put (system | secure | global) on the targeted phone(s).devices:edit · opt-in ON · confirm-gated
farm_set_wifiEnable / disable WiFi on the targeted phone(s).devices:edit · opt-in ON · confirm-gated
farm_app_lifecycleStart | stop | clear an app on the targeted phone(s).devices:edit · opt-in ON · confirm-gated
farm_grant_permissionGrant a runtime permission to an app on the targeted phone(s).devices:edit · opt-in ON · confirm-gated
farm_uninstall_appUninstall a package from the targeted phone(s).devices:edit · opt-in ON · confirm-gated
farm_pull_filePull a file from the targeted phone(s) to the host.devices:edit · opt-in ON · confirm-gated
farm_run_automationRun an automation script (by id) on the targeted phone(s).devices:edit · opt-in ON · confirm-gated
farm_replay_recordingReplay a saved recording on the targeted phone(s).devices:edit · opt-in ON · confirm-gated
farm_scheduleSchedule an automation / recording on an interval.devices:edit · opt-in ON · confirm-gated
farm_remove_scheduleRemove a scheduled job by id.devices:edit · opt-in ON · confirm-gated
farm_run_shellADMIN — run an arbitrary adb shell command on the targeted phone(s).devices:edit · admin · opt-in ON · confirm-gated
farm_run_adbADMIN — run a raw adb subcommand on the targeted phone(s).devices:edit · admin · opt-in ON · confirm-gated
farm_install_appADMIN — install an APK (host path) onto the targeted phone(s).devices:edit · admin · opt-in ON · confirm-gated
farm_inputADMIN — broadcast a tap / swipe / key / text input event (group control).devices:edit · admin · opt-in ON · confirm-gated
farm_set_proxyADMIN — set / clear the global HTTP proxy (egress redirect).devices:edit · admin · opt-in ON · confirm-gated
farm_set_airplaneADMIN — toggle airplane mode.devices:edit · admin · opt-in ON · confirm-gated
farm_rebootADMIN — reboot the targeted phone(s).devices:edit · admin · opt-in ON · confirm-gated
farm_push_fileADMIN — push a file from the host onto the targeted phone(s).devices:edit · admin · opt-in ON · confirm-gated

Entries (9)

Read, tag, search, and inspect captured request / response pairs. summarize_device_traffic is the one to reach for first on a busy device — a bounded, index-only profile of which hosts/endpoints dominate, without scanning raw rows. inspect_requests is the deep one — full headers and bodies for reverse-engineering an API. delete_entries is the precise, targeted counterpart to the whole-device wipe_entries.

ToolWhat it doesGating
search_entriesSearch captured entries (host, status, method, date).devices:view
list_entriesNewest captured entries as slim feed rows (no bodies) — the main live feed's MCP-parity read; device/exact-host/ts filters + a since_id live-tail append cursor. Owner-scoped, newest-first, capped 100. The live-traffic widget's output tool.devices:view
get_entry_countCount entries matching a filter.devices:view
summarize_device_trafficBounded, index-only traffic profile for ONE device — top hosts by request count, or (with host) the top path-bases on that host with per-path count + last-seen. Never scans or returns raw rows; fast on 17k+ rows. The first tool to call to find the busy/flooding host.devices:view
inspect_requestsDeep-inspect FULL request + response headers and bodies for ONE host (requires a full hostname with a dot).devices:view
export_harExport matching entries as a HAR 1.2 log (scope by device / host / date).devices:view
tag_entryAdd a tag to an entry.tags:edit
untag_entryRemove a tag from an entry.tags:edit
wipe_entriesDelete captured entries (per-device, or every device with all: true). Requires confirm: true (irreversible).devices:edit
delete_entriesTargeted filter-then-delete on ONE device (host / path_contains / method / time range; at least one filter required). Optional keep_latest_n keeps the N newest matching rows and deletes the rest — trim a flooding endpoint while keeping recent samples. Destructive + irreversible.devices:edit + admin + confirm

inspect_requests and export_har return real captured headers and bodies — treat any tokens, cookies, or credentials in them as secrets.

Service groups (5)

A service group can link one or more BusyBro specialist agents from the busybro_agents registry, with exactly one primary (the service's lens + default run_task target) and an explicit order. list_service_groups / get_service_group return each group's primary_agent plus its ordered agents[].

ToolWhat it doesGating
list_service_groupsList service groups, each with its primary_agent + ordered linked agents[].services:view
get_service_groupFetch one service group, with its primary_agent + ordered linked agents[].services:view
upsert_service_groupCreate or update a service group.services:edit
delete_service_groupDelete a service group.services:edit
set_service_group_agentsFull-replace the agents linked to a group: pass the complete desired [{agent_id, is_primary?, position?}] set (exactly one primary; an empty set clears all links).services:edit + confirm

The legacy service_groups.ai_agent jsonb (the old single inline {enabled, name, instructions} per-service agent) and the deprecated service_groups.agent_id FK have been dropped — link agents with set_service_group_agents instead (the service_group_agents join is the single source of truth). upsert_service_group still accepts an ai_agent arg for back-compat but ignores it.

Tags (3)

ToolWhat it doesGating
list_tagsList defined tags.tags:view
upsert_tagCreate or update a tag.tags:edit
delete_tagDelete a tag.tags:edit

Settings & environment (16)

Effective settings (global / per-user / per-service / per-device), environment variables, connection types, and breakpoint patterns. Env values are masked on read and never echoed on write; reference them later as {{KEY}} in resend_request and browser_eval. The env tools gate dynamically by scopeglobal checks global:*, device checks devices:*.

ToolWhat it doesGating
get_global_settingsRead settings_global.data.global:view
get_device_settingsRead a device's settings row.devices:view
set_device_settingsPatch a device's settings_device.data.devices:edit
clear_device_settingsDelete a per-device override row.devices:edit
get_env_globalList the GLOBAL env vars (values masked).global:view
get_env_deviceList ONE device's env vars (values masked).devices:view · owner-scoped
set_env_var_globalSet one GLOBAL env var (value never echoed).global:edit
set_env_var_deviceSet one env var on ONE device (value never echoed).devices:edit · owner-scoped
delete_env_var_globalRemove one env var from the GLOBAL store.global:edit
delete_env_var_deviceRemove one env var from ONE device's store.devices:edit · owner-scoped
import_env_globalBulk-import vars from .env text into the GLOBAL store (merge or replace).global:edit
import_env_deviceBulk-import vars from .env text into ONE device's store (merge or replace).devices:edit · owner-scoped

#965 — one tool per scope. These were once four tools taking a scope: 'global'|'device' argument. That shape could not be owner-scoped: an ownership tag authorizes the caller against an owned device, but the handler picked its resource from scope, so {scope:'global', device_uuid:<a device you own>} would have passed the ownership check and been served the ownerless settings_global singleton. Splitting per scope makes the gate and the dispatch agree by construction — each tool addresses exactly one store. | set_breakpoint_patterns_global | Set the global breakpoint patterns per direction — requestPatterns (outbound) / responsePatterns (inbound); patterns is a legacy alias for the request direction. | global:edit | | set_breakpoint_patterns_device | Set a device's breakpoint patterns per direction — requestPatterns / responsePatterns; patterns is a legacy alias for the request direction. | devices:edit | | set_breakpoint_patterns_user | Set a USER's breakpoint patterns per direction (the middle tier global → user → device). Effective per device = global ++ user ++ device. | users:edit · confirm-gated | | set_breakpoint_patterns_service | Set a SERVICE GROUP's breakpoint patterns per direction (the SERVICE tier global → user → service → device); applies to every device that has applied the group. Effective per device = global ++ service ++ user ++ device. | services:edit · confirm-gated | | set_global_connection_type | Set the global default connection type. | global:edit | | set_user_connection_type | Set the per-user connection type. | users:edit | | set_my_display_name | Change YOUR OWN account display name (profiles.display_name for the calling account). Self-scoped — writes only the caller's own row (cannot name another user; '' clears it). | own-data (any signed-in user) | | get_my_account | YOUR account at a glance — one self-scoped read: profile (name/email/role/providers/user_id/created_at), per-user connection type (own + global default + effective), linked Telegram accounts, owned devices, subscription status, callable endpoints. Takes no target args — cannot read another user's account. | own-data (any signed-in user) | | delete_my_account | PERMANENTLY delete YOUR OWN account — the App Store 5.1.1(v) self-service deletion over MCP (profile + owned devices + captured traffic + API tokens + auth user). Self-only (no target args) + HUMAN-only (a device/service caller is refused). A protected reviewer/demo account is preserved ({ protected: true }). BusyBro-denylisted. | own-data · confirm-gated | | list_issue_reports | List issue reports from the one-tap reporter — your own by default, every reporter's with all:true (audit operators). Slim rows: title, status, occurrences, GitHub issue link, route + build. | own-data (audit:view for all:true) |

Control flows (3)

Realtime control directed at the proxy-server / device handling a paused request.

ToolWhat it doesGating
resend_requestReplay a captured request (resolves {{VAR}} env refs server-side).devices:edit · confirm-gated
breakpoint_continueRelease a request paused at a breakpoint.devices:edit · confirm-gated
list_breakpoint_eventsList HELD (paused) breakpoint exchanges — your own devices' by default, every device with all:true (operators). Slim rows with the device name; feed request_id into breakpoint_continue.devices:view (own-data by default)

Pauses (2)

ToolWhat it doesGating
get_paused_domainsRead the global paused-domains list — the dedicated, confirm-free read twin.pauses:view
set_paused_domainsRead (omit domains) or replace the global paused-domains list.pauses:view / pauses:edit

Block rules (5)

Auto-block requests matching a method + host/path wildcard, before they reach upstream. The rule action is one of three variants: block returns a synthetic error response (status default 403, body, contentType); drop tears the connection down; mock returns a synthetic SUCCESS response (status default 200, optional string→string headers map, body, contentType). Stored in settings_{global,device}.data.blockRules; effective per device = global ++ device (de-duped by id).

Each rule also accepts an optional maxRuns integer — a run-count cap. Omit it (or pass a non-positive value) for unlimited (the default); maxRuns: 1 makes the rule fire once then auto-disable. The cap is set at creation right here on the rule object and applies to any action type. The count is tracked per device and persisted (it survives reconnect/restart — "once ever"), and a global rule that hits its cap is suppressed only on the device that reached it, never fleet-wide. See Block rules for the full semantics.

Example mock rule (force a JSON 200):

json
{ "id": "33333333-3333-3333-3333-333333333333", "enabled": true, "method": "GET",
  "pattern": "api.doordash.com/v3/feature_flags",
  "action": { "type": "mock", "status": 200, "headers": { "x-mocked-by": "busymate" },
    "contentType": "application/json", "body": "{\"flags\":{\"new_ui\":true}}" } }

Example one-shot mock rule (maxRuns: 1 — fire a single synthetic 401 to force a token refresh, then auto-disable):

json
{ "id": "44444444-4444-4444-4444-444444444444", "enabled": true, "method": "GET",
  "pattern": "api.example.com/v1/me",
  "action": { "type": "mock", "status": 401, "contentType": "application/json",
    "body": "{\"error\":\"token_expired\"}" },
  "maxRuns": 1 }
ToolWhat it doesGating
get_block_rules_globalRead the GLOBAL block rules — the fleet-wide tier that applies to every device.global:view
get_block_rules_deviceRead what ONE device ENFORCES (device_uuid/deviceName required) — the effective 4-tier union (global ++ service ++ user ++ device) plus the service, owner-user and per-device tiers. A rule shadowed here is correctly absent.devices:view (owner-scoped)
set_block_rules_globalReplace the global block rules (full list, each rule may carry maxRuns); merged into settings_global.data without clobbering other keys.global:edit
set_block_rules_userReplace a USER's block rules (the middle tier); additive (effective = global ++ user ++ device). A {type:'script'} action stays privilege-gated (scripts:edit + admin + confirm).users:edit · confirm-gated
set_block_rules_serviceReplace a SERVICE GROUP's block rules (the SERVICE tier); applies to every device that has applied the group. Additive (effective = global ++ service ++ user ++ device, device wins then user then service then global). A {type:'script'} action stays privilege-gated (scripts:edit + admin + confirm).services:edit · confirm-gated
set_block_rules_deviceReplace a device's per-device block rules (full list, each rule may carry maxRuns); additive on top of the global ++ user lists.devices:edit

Scripting engine (6)

Scripts are sandboxed JavaScript hooks (onRequest / onResponse) the proxy-server, cdp-connector, and iOS VPN run inline to mutate or synthesize matching requests/responses — the grown-up evolution of a Mock block rule. They live in settings_{global,user,device}.data.scripts; effective per device = global ++ user ++ device (de-duped by id, device wins then user then global), the same model as block rules. Writing a script is arbitrary-code power (browser_cdp-tier): the write tools need scripts:edit + admin + confirm: true at EVERY tier (the user tier does not lower the bar), enforced at the database layer (settings_{global,user,device}_scripts_gate) so no surface can smuggle a script in via a blocks write or a self-write.

A script object is { id, enabled, name, pattern, method?, phase: "request" | "response" | "both", code, version?, note? }.

ToolWhat it doesGating
get_scripts_globalRead the GLOBAL scripts — the fleet-wide tier — plus engine_enabled (the master kill-switch).scripts:view
get_scripts_deviceRead what ONE device RUNS (device_uuid/deviceName required) — the effective 4-tier union plus the service, owner-user and per-device tiers, with engine_enabled. A script shadowed here is correctly absent.scripts:view (owner-scoped)
set_scripts_globalReplace the global scripts (full list); merged into settings_global.data without clobbering other keys.scripts:edit · admin-only · confirm-gated
set_scripts_userReplace a USER's scripts (the middle tier); additive (effective = global ++ user ++ device). IDENTICAL bar to the global/device writers — the user tier does NOT lower it.scripts:edit · admin-only · confirm-gated
set_scripts_serviceReplace a SERVICE GROUP's scripts (the SERVICE tier); applies to every device that has applied the group. Additive (effective = global ++ service ++ user ++ device). IDENTICAL bar — the service tier does NOT lower it (services:edit alone is not enough; the DB service_groups_scripts_gate enforces it).scripts:edit · admin-only · confirm-gated
set_scripts_deviceReplace a device's per-device scripts (full list); additive on top of the global ++ user lists.scripts:edit · admin-only · confirm-gated
dry_run_scriptStatically check a candidate script before saving — parse-only compile + contract check (no write, no live execution). Full semantic dry-run runs in the live sandbox / dashboard, not the Edge function.scripts:view

Workspaces (6)

ToolWhat it doesGating
list_workspacesList workspaces.global:view
get_workspaceFetch one workspace.global:view
create_workspaceCreate a workspace.global:edit
rename_workspaceRename a workspace.global:edit
delete_workspaceDelete a workspace.global:edit · confirm-gated
set_workspace_retentionSet a workspace's retention window.global:edit

Tabs (6)

ToolWhat it doesGating
list_tabsList tabs.global:view
create_tabCreate a tab.global:edit
rename_tabRename a tab.global:edit
delete_tabDelete a tab.global:edit
set_tab_filtersSet a tab's filters.global:edit
set_tab_selected_entrySet a tab's selected entry.global:edit

Snapshots (3)

ToolWhat it doesGating
create_snapshotCreate a snapshot of captured state.snapshots:edit
list_snapshotsList snapshots.snapshots:view
download_snapshotDownload a snapshot's contents.snapshots:view

Push (2)

ToolWhat it doesGating
list_push_tokensList registered APNs push tokens.push:view
send_pushSend a push notification via APNs.push:edit · confirm-gated

Roles & RBAC (7)

Manage capability-based roles. All mutators are confirm-gated.

ToolWhat it doesGating
list_rolesList roles and their capabilities.users:view
create_roleCreate a custom role.users:edit · confirm-gated
update_roleUpdate a role's capabilities.users:edit · confirm-gated
delete_roleDelete a custom role.users:edit · confirm-gated
set_user_roleAssign a role to a user.users:edit · confirm-gated
list_usersAdmin roster of platform users — email, display name, role, providers, login source (the dashboard /users directory projection). Optional q searches the whole roster server-side (literal — LIKE wildcards escaped — before the page limit); total reports the full matching count.users:view
get_userLook up one user by email (exact, case-insensitive) — the direct answer for "is X an admin?". Returns the /users directory projection; found:false (not an error) when no account matches.users:view

Stats & status (2)

ToolWhat it doesGating
get_statsLive capture / usage stats.stats:view
get_statusInfrastructure / service health.status:view

Tester (2)

The architecture-prove verdict board — read the latest test run + trigger a new one.

ToolWhat it doesGating
get_test_statusRead the latest tester run (the prove verdict + per-phase / per-suite results + recent history) or one run by id.tester:view
run_test_suiteTrigger a tester run (a tier / component); records a requested run that CI runs + reconciles. Confirm-gated.tester:run + confirm

Telegram linking (5)

Link a Busymate account to a Telegram identity for BusyBro chat.

ToolWhat it doesGating
get_telegram_linkGet your Telegram link.users:view
list_telegram_linksList Telegram links.users:view
link_telegramLink a Telegram account.users:edit
unlink_telegramUnlink your Telegram account.users:edit · confirm-gated
admin_unlink_telegramAdmin: unlink any account's Telegram link.users:edit · confirm-gated

TestFlight beta admin (13)

Manage TestFlight groups, testers, and invitations via the testflight-admin Edge Function. Reads need testflight:view; every write needs testflight:edit and is confirm-gated.

ToolWhat it doesGating
list_testflight_groupsList beta groups.testflight:view
list_testflight_testersList testers.testflight:view
get_testflight_testerGet one tester.testflight:view
list_testflight_invitationsList tester invitations.testflight:view
list_testflight_usersList App Store Connect users.testflight:view
list_testflight_user_invitationsList user invitations.testflight:view
invite_testflight_testerInvite a beta tester.testflight:edit · confirm-gated
delete_testflight_testerRemove a tester.testflight:edit · confirm-gated
add_testflight_tester_to_groupAdd a tester to a group.testflight:edit · confirm-gated
remove_testflight_tester_from_groupRemove a tester from a group.testflight:edit · confirm-gated
send_testflight_invitationSend a tester invitation.testflight:edit · confirm-gated
invite_testflight_userInvite an App Store Connect user.testflight:edit · confirm-gated
cancel_testflight_user_invitationCancel a user invitation.testflight:edit · confirm-gated

BusyBro memory & shares (4)

BusyBro's long-term memory and shared-conversation reader. The memory trio is owner-scoped — you only ever see and touch your own account's memories, the same store the dashboard and Telegram BusyBro read and write.

ToolWhat it doesGating
list_memoriesList or semantically search your own durable memories (facts / preferences / corrections / episodes).users:view
save_memorySave one durable memory about you / your work; near-duplicates merge, a correction overwrites.users:edit
forget_memoryDelete your memories — by id, by best semantic query match, or all.users:edit · confirm-gated
get_busybro_shareRead a shared BusyBro conversation by its /busybro/share/<id> id — title, context, full transcript — so you can continue it.public (by id)
delete_busybro_shareREVOKE one of YOUR OWN shared BusyBro conversations by id — the /busybro/share/<id> link stops resolving. Owner-scoped no-op on a foreign/stale id.users:edit · confirm-gated

BusyBro sessions (5)

Multi-session chat management — a "session" is one busybro_threads row (a resumable conversation), shared across the dashboard, iOS, and the bmc CLI. All five are owner-scoped — you only ever list / load / rename / delete your own sessions. context_key is the dashboard nav-binding find-or-create key (UUID-keyed, e.g. device:<uuid>); last_active_at is the sidebar ordering anchor.

ToolWhat it doesGating
list_busybro_sessionsList your chat sessions, newest-active first — {thread_id, title, context_key, updated_at, last_active_at, turns}.users:view
get_busybro_sessionLoad one of your sessions by id — title, context_key, and ordered turns. A session you don't own returns not-found.users:view
create_busybro_sessionCreate a new empty session; optionally seed a title + nav-binding context_key. Find-or-create: a colliding context_key returns the existing session.users:edit · confirm-gated
rename_busybro_sessionRename one of your sessions (owner-gated no-op on a foreign id).users:edit · confirm-gated
delete_busybro_sessionPermanently delete one of your sessions (owner-gated no-op on a foreign id).users:edit · confirm-gated

BusyBro attachments (1)

The read leg of the BusyBro attachments program (files / photos / videos uploaded to BusyBro chats — the durable rows in public.busybro_attachments, bytes in the private busybro-attachments bucket). Owner-scoped — you only ever see your own uploads, and there is no fleet arm.

ToolWhat it doesGating
list_busybro_attachmentsList your attachments, newest first — names + metadata only by default (id / kind / mime / size_bytes / filename / status / thread_id / created_at; the storage path and bytes are never returned). Filter by thread_id / kind / status. with_url:true adds a short-TTL (600 s) signed download url per ready row.users:view

BusyBro global (team) memory governance (10)

The shared, non-personal team-knowledge store and its review queue — see Global (team) memory and the shareable Connect to team memory page. The shared store has no user_id and is leak-proof on the recall path; contributor identity surfaces only through list_memory_contributors, never in what an LLM recalls. Proposals land pending (not recallable) until an operator approves them.

ToolWhat it doesGating
list_global_memoriesOperator browse of the team store across all statuses (pending / approved / rejected); filter by status / kind / origin / query. Returns each row's origin + contributor_count — never contributor ids.users:view
get_memory_statsMemory dashboard counters: personal vs global totals, the global pending / approved / rejected split, and distinct_contributors (count only).users:view
list_memory_contributorsOperator attribution lookup for ONE team fact — who proposed it (joined to email / display name from the leak-proof busybro_global_contributions ledger) + who approved it (approved_by). Strictly off the recall path.users:view
propose_global_memoryPropose one candidate team fact — third-person, subject-less, ≤ 600 chars, no PII / secrets. Writes a pending row (not recallable) + records you as a contributor.users:edit · confirm-gated
approve_global_memoryPromote a pending team fact to approved (recallable); stamps approved_by = you.users:edit · confirm-gated
reject_global_memoryReject a candidate (kept for audit / dedup, never recalled).users:edit · confirm-gated
update_global_memoryEdit a team fact's content / kind / importance; editing content flags it for re-embedding.users:edit · confirm-gated
admin_list_user_memoriesAdmin / support drill-down — read ONE user's personal memories by user_id (never feeds another user's recall).users:view
admin_forget_user_memoryAdmin / support — delete ONE of a user's personal memories by id (a correction, not the full GDPR wipe).users:edit · confirm-gated
gdpr_forget_userAdmin GDPR erasure — wipe ALL of a user's personal memory + drop their global contributions; the recompute trigger then deletes any team fact that loses its last contributor.users:edit · admin-only · confirm-gated

The recall store (busybro_global_memories) carries no identitymatch_global_memories returns no user_id. Per-person provenance lives only in the busybro_global_contributions side-table, read only by list_memory_contributors (operator-gated), for dedup, corroboration, stats, and erasure — never on the recall path. The dashboard review queue shows a candidate's contributor count, never identities.

External MCP servers & personal connectors (13)

BusyBro consumes other MCP servers as a client — a GLOBAL, admin-managed registry (busybro_mcp_servers, rows with owner_user_id IS NULL) plus personal connectors (#830): the same table with owner_user_id set, self-service for any signed-in user, owner-scoped end-to-end. Credentials are value-blind everywhere — a Bearer token is written to Vault and never read back; an OAuth connector's tokens (#899) are acquired by the server-side consent flow and never pass through any tool argument or response.

ToolWhat it doesGating
list_mcp_serversThe GLOBAL admin registry (metadata only; auth_secret_ref is a Vault NAME, never a value). Personal connectors never appear here.users:view
upsert_mcp_serverCreate / update a global server; mint_token:true mints a Bearer token value-blind into Vault and returns it exactly once.users:edit · admin-only · confirm-gated
delete_mcp_serverRemove a global server from the registry.users:edit · admin-only · confirm-gated
set_mcp_server_enabledThe global kill-switch — a disabled server is not advertised to BusyBro.users:edit · admin-only · confirm-gated
inspect_mcp_serverProbe ONE registered server by id — initialize + tools/list exactly as an LLM sees it (loopback for the system self-row). Read-only, fail-soft.users:view
list_my_mcp_connectorsYOUR OWN personal connectors — value-blind rows incl. conn_status (draft / connecting / authorizing / ready / needs_reauth / error).users:view
upsert_my_mcp_connectorCreate / update your own connector — auth_typenone / bearer / oauth (#899); URL SSRF-vetted; owner pinned server-side.users:edit · confirm-gated
delete_my_mcp_connectorRemove your own connector + its Vault credential.users:edit · confirm-gated
set_my_mcp_connector_enabledYour per-connector kill-switch.users:edit · confirm-gated
set_my_mcp_connector_secretSet the Bearer credential — written value-blind to Vault under a server-derived name, never read back.users:edit · confirm-gated
probe_mcp_connectorPaste-a-URL preview — SSRF-guarded initialize + tools/list handshake; nothing stored.users:view
connect_my_mcp_connectorStart (or restart) the OAuth consent flow for your own oauth connector (#899) — RFC 9728/8414 discovery → DCR where offered → PKCE S256 mandatory, every endpoint SSRF-vetted; returns a single-use authorize_url to open in a browser. Also the reconnect path when conn_status = needs_reauth.users:edit · confirm-gated
disconnect_my_mcp_connectorWipe your OAuth connector's stored tokens from Vault and flip it back to draft (the row + client registration are kept, so reconnect skips re-registering).users:edit · confirm-gated

An OAuth connector's access / refresh tokens live only in Vault under server-derived names — no tool, REST read, or log ever returns one. A dead grant (revoked / expired refresh) flips the connector to needs_reauth and BusyBro says so honestly at turn start ("needs to be reconnected") instead of silently advertising zero tools.

Stripe billing & admin (9)

Subscription + metered (captured_entries) billing (Phase 1 = Stripe TEST mode). The owner-scoped reads filter on the caller's identity; operators pass all_users:true for the fleet. The admin reads back the /billing-admin operator surface — all value-blind (get_stripe_config derives test/live mode from the publishable-key prefix and NEVER returns the secret key or webhook signing secret).

ToolWhat it doesGating
get_subscriptionThe caller's own Stripe subscription(s); operators pass all_users:true for the fleet.billing:view
list_invoicesThe caller's own invoices (amounts / hosted URL / period); all_users:true for the fleet.billing:view
get_usageThe caller's own metered usage rollup (captured_entries) by period; all_users:true for the fleet.billing:view
create_checkout_sessionOpen a Checkout (subscribe) or Customer Portal (manage) session; customer derived server-side from the caller.billing:view · confirm-gated
get_stripe_configValue-blind connection status: { mode, publishable_key } only (mode derived from the pub-key prefix; secret/whsec_ never read).billing:view
list_pricesThe Stripe Products' prices (value-blind projection: amounts, recurring/metered, lookup_key).billing:view
list_customersThe stripe_customers ↔ users mapping (fleet — the local mapping table, not the Stripe API).billing:view
get_webhook_eventsThe stripe_webhook_events idempotency ledger (fleet) — event_id / type / received.billing:view
get_billing_settingsThe billing_settings singleton (default price, quota/overage, dunning, mode, …).billing:view

Directory catalogue (7)

The BusyBro Directory — the operator-curated catalogue that merchandises skills, connectors, and plugins to the consumer BusyBro app. ONE model (busybro_directory_listings) backs all three collections; the item tables stay about function, the listing owns presentation. install_count is real installs only (RPC-incremented, never operator-editable — a fresh catalogue renders no counts); the Community and New badges derive from author_kind / published_at, so the stored badge taxonomy is exactly {verified, trending}.

ToolWhat it doesGating
list_directoryThe consumer read — PUBLISHED listings only, joined to each item's slug/label/description.users:view
list_directory_listingsThe operator read — every status incl. the pending moderation queue (empty in v1).directory:view
upsert_directory_listingCreate/update a listing's presentation (status, attribution, badges, rank, POPULAR-FOR featured, category).directory:edit · admin · confirm-gated
set_directory_listing_statusPublish / unpublish / moderate one listing; first publish stamps published_at.directory:edit · admin · confirm-gated
delete_directory_listingRemove a listing (the underlying item is untouched).directory:edit · admin · confirm-gated
install_skillInstall a PUBLISHED Directory skill into YOUR OWN set (sub-pinned own-data; the honest count bumps only on a genuinely new install).users:edit · confirm-gated
uninstall_skillRemove a Directory skill from YOUR OWN set — a DEFAULT-installed skill keeps an opt-out so it never silently returns (#1066).users:edit · confirm-gated
list_install_defaultsThe operator read of the default-installed configuration — platform tier + per-tenant overrides in one shape (#1066).directory:view
set_install_defaultSet/clear a default-installed row (platform or tenant tier); refuses runtime-unhonored collections + unpublished items (#1066).directory:edit · admin · confirm-gated

Legacy aliases (4)

Older names kept for backward compatibility. Prefer the generic db_* tools or the typed reads / writes above for new work.

ToolWhat it doesGating
list_entriesPaginated entries query.devices:view
get_entryFetch one entry by id / request_id.devices:view
get_settingsEffective settings for a device.devices:view
set_global_settingsPatch settings_global.data.global:edit

Total: 409 tools.