> ## Documentation Index
> Fetch the complete documentation index at: https://docs.haloagents.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Scopes & Permissions

> The MCP scope grammar, the three-layer gating model, and how Halo binds tokens to customers.

## The scope grammar

Every Halo MCP token carries a list of **scopes** the user approved at consent time. Scopes are space-separated strings with these shapes:

| Scope                            | Grants                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `actions:*`                      | Every non-destructive action on every connected integration. Also implies `docs:read`, `setup:read`, and `data:read`. Does NOT imply write/destructive scopes.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `actions:<integration>:*`        | Every non-destructive action on one integration (e.g. `actions:hubspot:*`).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `actions:<integration>:<action>` | One specific (non-destructive) action (e.g. `actions:hubspot:create_deal`).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `actions:destructive`            | Destructive-flagged integration actions: `stripe.billing` (refunds / credits / cancellations) and `slack.post_message`. Opt-in; NOT unlocked by `actions:*`. The token must ALSO carry the matching action scope (e.g. `actions:stripe:billing` or `actions:*`) — this scope only lifts the destructive block.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `docs:read`                      | The proxied `search_docs` and `read_doc` tools that hit the public Halo docs.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `setup:read`                     | The read-only setup helpers `setup_get_install_snippet` and `setup_get_jwt_sample`. Lets a connected client (Cursor, Claude Desktop) walk the customer through installing the widget.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `data:read`                      | All read-only workspace-data tools. **Records:** `data_find_user`, `data_search_users`, `data_search_leads`, `data_find_company`, `data_search_companies`, `data_search_tickets`, `data_get_ticket`, `data_search_transcripts`, `data_get_transcript`, `data_list_negative_feedback`. **Product-insight tools:** `data_search_events` (SDK behaviour search), `data_top_pages_before_chat`, `data_top_unresolved_questions`, `data_user_journey`, `data_low_sentiment_conversations`. **Ask-AI-parity retrieval + analytics:** `data_search_knowledge` (Voyage embed + Postgres `match_knowledge` hybrid + Voyage rerank, the same pipeline that powers Ask AI thinking mode), `data_query_integration` (recency cuts over synced integration data), `data_query_metrics` (KPI snapshots), `data_query_activity_time_series` (bucketed DAU / new users / conversations / tickets), `data_get_hubspot_pipeline_stages`, `data_query_hubspot_deals`, `data_query_hubspot_engagements`, `data_query_stripe`, `data_lookup_stripe_customer`, `data_list_automations`, `data_get_automation_performance`, `data_list_automation_recipients`, `data_query_email_engagement_overview`, `data_web_search`, `data_web_fetch`. **Audience + identity helpers:** `data_list_segments` (saved segments for outreach audiences), `data_list_email_subscriptions` (subscription lists), `data_list_alias_users` (named sender identities like "Bella" that the inbox write tools can reply as, resolving a name to its `alias_user_id`), `data_list_inboxes` (inbox views / custom inboxes, resolving a name like "Billing" to the `inbox_id` that `inbox_move_ticket` takes). The MCP client can answer "who is this customer", "what tickets are open", "what did we tell Acme about onboarding last quarter", and "how has churn changed in the last 30 days" without touching the dashboard. |
| `data:write`                     | Workspace-data mutation tools: `data_update_user` (name, email, phone, company link, lead status/source, custom fields) and `data_update_company` (name, domain, industry, plan, employee count, custom fields). No deletes. Opt-in; NOT unlocked by `data:read` or `actions:*`. The grantor must also hold `contacts:edit` (users) / `companies:edit` (companies) permission.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `inbox:write`                    | Inbox / customer-communication mutation tools: `inbox_reply_ticket_chat`, `inbox_reply_ticket_email`, `inbox_add_note`, `inbox_set_ticket_status`, `inbox_assign_ticket`, `inbox_move_ticket` (route a ticket into an inbox view, or clear its routing with `null`), `inbox_snooze_ticket`, `inbox_create_ticket`, `inbox_message_customer` (proactive outreach). Replies and outreach can send AS a named alias by passing `alias_user_id` (resolve the name via the `data_list_alias_users` read tool). Opt-in; NOT unlocked by `actions:*`. The grantor must also hold `inbox:reply` permission.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `automations:write`              | Outreach / campaign mutation tools across broadcast, series, in\_app\_message, banner: `automation_create`, `automation_update`, `automation_set_audience`, `automation_upsert_step`, `automation_delete_step`, `automation_set_flow` (series entry/exit/goal), `automation_update_settings`, `automation_readiness` (preflight), `automation_preview_audience` (count), `automation_send_test` (teammate preview), `automation_activate`, `automation_publish`, `automation_pause`. Opt-in; NOT unlocked by `actions:*`. The grantor must also hold `automation:edit` / `automation:send`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `sales:read`                     | Read-only Sales Suite tools: `sales_list_pipelines`, `sales_list_deals`, `sales_get_deal`. Only surface when the org has the **Sales Suite** (`sales_suite`) enabled. Grantor must hold `sales:view`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `sales:write`                    | Sales Suite mutation tools: `sales_create_deal`, `sales_update_deal`, `sales_move_deal_stage` (records stage history, playbook tasks, score recalc, workflow triggers), `sales_add_deal_note`. Opt-in; NOT unlocked by `actions:*` or `sales:read`. Implies `sales:read`. Grantor must also hold `sales:edit`. Needs `sales_suite` enabled.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `cs:read`                        | Read-only CS Suite tools: `cs_list_accounts` (the Customers/accounts list), `cs_list_pipelines`, `cs_list_deals`, `cs_get_deal`, `cs_list_issues`, `cs_get_issue`. Only surface when the org has the **CS Suite** (`cs_suite`) enabled. Grantor must hold `cs:view`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `cs:write`                       | CS Suite mutation tools: onboarding-deal writes (`cs_create_deal`, `cs_update_deal`, `cs_move_deal_stage`, `cs_add_deal_note`) plus issue writes (`cs_create_issue`, `cs_update_issue`, `cs_add_issue_comment`). Opt-in; NOT unlocked by `actions:*` or `cs:read`. Implies `cs:read`. Grantor must also hold `cs:edit`. Needs `cs_suite` enabled.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `workflows:read`                 | Read-only Workflow tools: `workflow_list`, `workflow_get` (with draft steps), `workflow_list_enrollments`. Surface when EITHER suite (`cs_suite` OR `sales_suite`) is enabled. Grantor must hold `workflows:view`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `workflows:write`                | Workflow mutation tools: `workflow_create`, `workflow_activate`, `workflow_pause`, `workflow_resume`, `workflow_enroll_records`, `workflow_cancel_enrollment`. **Activating a workflow or enrolling records can send email.** Opt-in; NOT unlocked by `actions:*` or `workflows:read`. Implies `workflows:read`. Grantor must also hold `workflows:edit`. Needs a suite enabled.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |

A client that requests scopes Halo doesn't recognise has them silently dropped at consent time, so a malicious client can't trick the user into approving a meaningless string and then claiming that meant something.

The Sales Suite, CS Suite, and Workflow tool groups carry an extra org-level gate on top of scopes: the org must have the matching **feature flag** (`sales_suite` / `cs_suite`) enabled. If the suite is off, the tools never appear in `tools/list` and a direct `tools/call` is refused with an `integration_disabled` audit row — even if the token carries the scope. Deals are shared objects: `sales_*` tools only touch `sales`-pipeline deals and `cs_*` tools only touch `cs_onboarding` deals, mirroring the dashboard's per-pipeline suite ownership.

## Destructive and write actions

Halo's action registry flags destructive operations (refunds, deletes, irreversible writes) with `destructive: true`. Those tools are gated behind a dedicated `actions:destructive` scope. `actions:*` does NOT imply `actions:destructive`, so a token that was granted the broad action surface does not silently gain destructive power; the destructive scope has to be granted on its own.

The consent UI groups permissions with all Read scopes first and all Write scopes below, each row tagged with a Read / Write badge. Every scope is checked by default; the operator unticks anything they don't want to grant. On the server, every write tool additionally runs a grantor-permission check (see below) so an MCP token can never exceed the dashboard rights of the operator who granted it.

If the policy ever changes, it flips in `lib/integrations/mcp-oauth/scopes.ts` — there's a single chokepoint, not a scattered set of checks.

## Grantor-permission gate

Write tools (`inbox:write`, `automations:write`, `data:write`, `sales:write`, `cs:write`, `workflows:write`) run an extra server-side check: the OAuth token's grantor (the operator who approved the consent) must hold the matching dashboard permission. The suite read tools check the corresponding `:view` permission too:

| Tool surface                         | Required permission |
| ------------------------------------ | ------------------- |
| `inbox:write` tools                  | `inbox:reply`       |
| `automations:write` edit tools       | `automation:edit`   |
| `automations:write` activate / pause | `automation:send`   |
| `data:write` (update user)           | `contacts:edit`     |
| `data:write` (update company)        | `companies:edit`    |
| `sales:read` tools                   | `sales:view`        |
| `sales:write` tools                  | `sales:edit`        |
| `cs:read` tools                      | `cs:view`           |
| `cs:write` tools                     | `cs:edit`           |
| `workflows:read` tools               | `workflows:view`    |
| `workflows:write` tools              | `workflows:edit`    |

A refusal here writes an `action_executions` row with `reason: scope_denied` and the missing permission as detail, so you can see "the token had the scope but the operator didn't have the dashboard right" in the audit log.

Destructive integration actions (`actions:destructive`) rely on the same gating every integration action has always had: the integration's Actions mode, the per-agent action toggle, and the action scope itself, plus the dedicated `actions:destructive` grant at consent.

## Campaign-launch safeguards

`automations:write` can activate real email sends, so `automation_activate` is double-gated beyond scopes and permissions:

<Steps>
  <Step title="Validation">
    The campaign must pass the same publish validation the dashboard enforces: every email step needs a subject and content, segment audiences need at least one filter, event-triggered series need an event name, enabled goals need goal filters. `automation_readiness` runs the same checks as a read-only preflight so the client can fix gaps before launching.
  </Step>

  <Step title="Audience confirmation handshake">
    For sends that resolve an audience at activation (broadcasts, manual and segment-match series), the client must first call `automation_preview_audience` and then pass the returned `users_count` as `expected_recipient_count` to `automation_activate`. The server re-resolves the audience through the same pipeline that enqueues recipients and refuses on any mismatch, so a campaign can never launch against an unconfirmed or silently-changed audience. Widgets and forward-trigger series (`user_created` / `event`) don't resolve an audience at activation and skip the handshake.
  </Step>
</Steps>

Ad-hoc audience filters passed to `automation_set_audience` are validated against a known operator allowlist; unknown operators are refused. Prefer saved segments (`data_list_segments`) or subscription lists (`data_list_email_subscriptions`) so the audience is one a human already vetted.

## The three-layer gate

A non-destructive integration tool call has to clear three independent checks before it runs. Each layer is enforced server-side every call (no caching, no client-supplied claims):

<Steps>
  <Step title="Workspace integration mode">
    The integration's **Actions** mode must be on (toggled at the top of the integration's detail page). If you flip it off, every tool from that integration disappears from MCP `tools/list` immediately.
  </Step>

  <Step title="Per-agent action toggle">
    The action must be enabled on the org's Ask AI agent (the same agent the dashboard's Ask AI surface uses). Same setting that gates the action when called from a chat conversation.
  </Step>

  <Step title="Token scope">
    The token's scopes must include the matching `actions:<integration>:<action>` (or a wildcard).
  </Step>
</Steps>

This is defense in depth on purpose. Disabling the integration in **Integrations** kills MCP access for that integration even if older tokens were scoped to it. Disabling the action on Ask AI kills it even if the integration mode is on. Removing a scope from a token kills it even if both are on.

Every refusal path writes an `action_executions` row with the rejection reason (`scope_denied`, `destructive_blocked`, `integration_disabled`, `agent_disabled`, etc.) so you can answer "why didn't this MCP client manage to do X" from the audit log instead of from server logs.

## Binding a customer to a session

Tokens are org-scoped. To act on behalf of a specific customer (look up their data, file a ticket on their conversation, etc.), the client passes the binding inline on each call via the JSON-RPC `_meta` envelope:

```json theme={null}
{
  "params": {
    "name": "linear.create_bug",
    "arguments": { "title": "Bug from Acme", "description": "..." },
    "_meta": {
      "bound_end_user_id": "u_abc123"
    }
  }
}
```

You can use `bound_email` instead of `bound_end_user_id` if your client only knows the email. Halo re-resolves the binding on every call against your org's customer table; the binding is never trusted across calls and never trusted across orgs.

## Audit trail

Every MCP call writes an `action_executions` row with:

* The acting actor (`mcp_client`) and the user who granted the token (`grantedByUserId`)
* The token id (so you can correlate every call from one token without dereferencing the token itself)
* The bound customer (when present), re-resolved server-side
* The full input args
* The outcome (success, validation failure, scope denial, rate limit, integration error)
* A timestamp + duration

You can filter the existing **Action Executions** view by actor kind to see only MCP traffic. Every refusal also writes a row so denied attempts are visible alongside successful runs.

## Token lifecycle

| Step             | Detail                                                                                                                                                                     |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Issue**        | At `/api/mcp/oauth/token` after PKCE-verified code exchange. Returns `access_token` (1 hour TTL) + `refresh_token` (long-lived, rotates on use).                           |
| **Refresh**      | Standard `grant_type=refresh_token`. Rotation: the old refresh row is revoked atomically as the new pair is issued. Refresh-token replay revokes the entire derived chain. |
| **Downscope**    | `refresh_token` requests can include `scope=` to drop scopes. The new scopes must be a subset of the current ones; you can never upscope on refresh.                       |
| **Revoke**       | `POST /api/mcp/oauth/revoke` with the access or refresh token. Idempotent and always returns 200 (per RFC 7009 §2.2 to prevent token-shape probing).                       |
| **Auto-cleanup** | Inactive clients (never issued a token within 30 days of registration) are auto-pruned by a nightly cron. Active clients are kept indefinitely.                            |

## Recommended scope sets

Pick the smallest set that covers your use case:

| Use case                                                                                    | Scopes                                                                                                                  |
| ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| Help a customer install the widget from inside Cursor / Claude Desktop                      | `setup:read docs:read`                                                                                                  |
| Read-only product-insight surface (search users, tickets, conversations, negative feedback) | `data:read docs:read`                                                                                                   |
| Look up customer + conversation data + take non-destructive actions                         | `actions:* data:read`                                                                                                   |
| Answer customer tickets and email customers from MCP                                        | `data:read inbox:write docs:read`                                                                                       |
| Create, edit, and launch email broadcasts / series / in-app / banners                       | `data:read automations:write docs:read`                                                                                 |
| Update contact / company records                                                            | `data:read data:write`                                                                                                  |
| Manage the Sales pipeline (deals, stages, notes)                                            | `sales:read sales:write`                                                                                                |
| Manage Customer Success (customers, onboarding, issues)                                     | `cs:read cs:write`                                                                                                      |
| Build and run workflows                                                                     | `workflows:read workflows:write`                                                                                        |
| Full read + write + destructive (refunds, Slack posts)                                      | `actions:* actions:destructive data:read data:write inbox:write automations:write sales:write cs:write workflows:write` |
| Documentation search only                                                                   | `docs:read`                                                                                                             |
| Restricted to a single integration                                                          | `actions:hubspot:*`                                                                                                     |
| Restricted to a single action                                                               | `actions:hubspot:create_deal`                                                                                           |
