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

# MCP Scopes, Limits and Audit Trail

> What an AI assistant is allowed to do in your Notifizz organisation: the three permission scopes, how a credential is bounded in time and reach, and which actions are recorded.

# Scopes and audit

Connecting an AI assistant to Notifizz over **MCP** — the *Model Context Protocol*, the open standard an assistant uses to call outside tools — hands software the ability to change your configuration. This page is the answer to the reasonable follow-up question: *bounded by what, exactly?*

**Written for the Dev and for Product/Ops** — the two roles who have to be able to answer that question. Nothing here needs to be configured to be true; it is enforced on every call.

## TL;DR

* **Three permissions**: `read:data` (plain reads), `write:setup` (configuration writes **and** access to environment secrets), `write:campaign` (the campaign journey).
* **A credential from the browser consent carries all three.** A credential can be narrowed to a subset; a tool outside it is refused with a payload that names the missing permission.
* **A credential belongs to one person and one organisation.** The organisation is resolved from the credential itself, never from a tool argument — there is no parameter through which an assistant could reach another organisation.
* **Time-bounded**: access 7 days with silent refresh, refresh chain 90 days, an authorisation code 10 minutes and single-use. Revocation takes effect on the next call.
* **Every write is recorded** — who, which credential, which tool, which campaign, and whether it succeeded, was refused or errored. Plain reads are not, on volume grounds. The record is kept for **one year**.
* **Payloads are never recorded.** The trail says *what was called*, not what was in it.

## The three permissions

| Permission       | Covers                                                                                                                                                                              | Rationale                                                                                                                                                                           |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `read:data`      | Status, implementation tasks, test activity, library listing, the verification and diagnosis tools, template analysis                                                               | Reading tells you what is happening; it changes nothing                                                                                                                             |
| `write:setup`    | Vocabulary, link routes, environment variables, discovery, channel identity, Notification Center auth, web push setup, library assets and components — **and `sandbox_get_config`** | The data contract and the delivery configuration. Handing out a non-production environment's keys is filed here on purpose: **access to a secret is a setup privilege, not a read** |
| `write:campaign` | Creating a campaign, answering its questions, approving a flow, promoting to implementation and to review, sending a test event, archiving                                          | Everything that moves a campaign along its lifecycle                                                                                                                                |

Two tools sit outside the model entirely and need no permission: `quickstart` and `email_templates_migration`. Both are read-only entry points that hand back a plan — and the plan gates every write inside it behind your explicit confirmation.

### Tool by permission

<AccordionGroup>
  <Accordion title="read:data — 8 tools">
    `campaign_get_status` · `campaign_list_tasks` · `campaign_get_test_activity` · `sandbox_verify_tracking` · `sandbox_verify_discovery` · `channels_webpush_verify_setup` · `library_list` · `email_templates_analyze`
  </Accordion>

  <Accordion title="write:setup — 10 tools">
    `vocabulary_upsert` · `link_route_upsert` · `env_variable_upsert` · `sandbox_get_config` · `sandbox_run_discovery` · `channels_upsert_identity` · `channels_notification_center_upsert_auth` · `channels_webpush_setup` · `library_upload_asset` · `library_upsert_component`
  </Accordion>

  <Accordion title="write:campaign — 7 tools">
    `campaign_create` · `campaign_answer` · `campaign_approve` · `campaign_implement` · `campaign_send_to_review` · `campaign_send_test_event` · `campaign_archive`
  </Accordion>

  <Accordion title="No permission required — 2 tools">
    `quickstart` · `email_templates_migration` — the two guided plans. They read nothing of consequence and write nothing at all.
  </Accordion>
</AccordionGroup>

## What a narrowed credential looks like in practice

A credential obtained through the [browser consent](/docs/ai/connect-your-ai-tool) requests one umbrella permission, which maps to all three. A credential deliberately restricted to a subset behaves differently: the tools it does not cover are **not hidden** — they are refused, and the refusal is legible:

```json theme={null}
{
  "error": "insufficient_scope",
  "required_scope": "write:campaign",
  "granted_scopes": ["read:data"],
  "message": "This MCP credential lacks the 'write:campaign' scope needed for campaign_create. Regenerate the key with that scope, or ask the org owner."
}
```

An assistant that gets this can tell you exactly what to change, which is the whole point of naming the missing permission rather than returning a bare *forbidden*. The refusal happens **before** the tool runs — nothing is half-applied — and it is recorded as a denial.

## Limits that are not permissions

Permissions decide *which tools*. Four other boundaries decide *how far*, and none of them can be widened by a scope.

**One organisation.** The organisation is bound to the credential at consent time and resolved server-side on every call. No tool takes an organisation argument. An assistant holding a credential for organisation A cannot address organisation B, regardless of what it is asked to do.

**One person, one credential per organisation.** Credentials are per user × per organisation. Issuing a new one replaces the previous one for that pair, so a person never accumulates live credentials behind their own back.

**Production is not a dev toy.** `sandbox_get_config` returns non-production environments only. There is no path through MCP to a production environment's keys.

**Publishing Live has no tool.** Not a permission that is off by default — an absence. A campaign goes Live from the dashboard, by a person. Two other actions keep a human in the loop by design: approving a proposed flow, and confirming an archive (which returns a confirmation prompt on the first call and only acts on the second).

## Credential lifetime

|                                          | Lifetime                   | Notes                                                                                                                            |
| ---------------------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Authorisation request (the consent page) | 10 minutes                 | Expires if you leave the tab; restart from your AI tool                                                                          |
| Authorisation code                       | Single use, 10 minutes     | Bound to the requesting client by PKCE — an intercepted code is useless on its own                                               |
| Access token                             | 7 days                     | Refreshed silently by your tool before it lapses                                                                                 |
| Refresh token                            | 90 days, reset on each use | **Rotating and single-use**: each refresh mints a fresh pair and burns the old one, so a leaked refresh token works at most once |
| Revocation                               | Immediate                  | A revoked token is refused on the very next call. No grace window                                                                |

Two more properties of how credentials are held:

* **Only a one-way fingerprint is stored** for authentication. The credential itself is not kept in a form that could be read back out and replayed.
* **Logs and the audit trail identify a credential by a masked handle** — its first twelve and last four characters — never by its value.

The public authorisation endpoints are rate-limited per caller, because dynamic client registration is unauthenticated by protocol design and an open write path deserves a ceiling.

### The one short-lived exception

An email-template migration has to submit a whole corpus of HTML, which cannot travel through an assistant's context window. The migration plan therefore embeds a **single-purpose ticket**: valid for one hour, carrying `read:data` and nothing else, accepted by the corpus-analysis endpoint and by no other route. It is deliberately enumerated rather than derived, so a permission added to the product tomorrow does not quietly fall to it. Like every other credential, only its fingerprint is stored.

## What gets recorded

Every **write** — which by the definition above includes the secret-returning `sandbox_get_config` — appends one entry:

| Field            | Example                                                              |
| ---------------- | -------------------------------------------------------------------- |
| When             | Timestamp of the call                                                |
| Who              | The person the credential was issued to                              |
| Which credential | The masked handle                                                    |
| How              | Which connection the call came in on                                 |
| What             | The tool name                                                        |
| On what          | The campaign id, when the tool targeted one                          |
| Outcome          | `ok`, `error`, or `denied` (a call refused for a missing permission) |

Three things this trail deliberately does **not** contain:

* **No payloads.** The vocabulary you pushed, the campaign brief, the template HTML — none of it is copied into the record. It says a write happened, by whom, on what.
* **No plain reads.** Reads are high-volume and change nothing; recording them would bury the writes that matter.
* **No end-customer data.** Notifizz holds none to begin with — see [privacy friendly](/docs/concepts/privacy-friendly).

**Retention is one year** — deliberately longer than Notifizz's operational retentions, because this is the record of AI-driven change and accountability outranks volume.

**A failed recording never breaks the call it describes.** Auditing is appended alongside the work, not in front of it; an assistant's write does not fail because the trail could not be written.

<Note>
  The trail is recorded against your organisation and kept for a year. There is no self-service viewer on the *Settings → AI tools* screen today — if you need the record, ask your Notifizz contact.
</Note>

## FAQ

<AccordionGroup>
  <Accordion title="Can I give an assistant read-only access?">
    Yes — that is exactly what a credential narrowed to `read:data` does. Every write tool then answers `insufficient_scope` while status, tasks, test activity and the diagnosis tools keep working. It is a sensible setup for an assistant you want to observe with, not act with.
  </Accordion>

  <Accordion title="Why is fetching sandbox keys classed as a write?">
    Because the risk it carries is a write's risk, not a read's. Filing it under `read:data` would mean that the least privileged credential you can issue also hands out environment secrets — which would make the whole distinction decorative. Reading a secret is a setup privilege.
  </Accordion>

  <Accordion title="Someone left the team. What do I do?">
    Their credential is theirs alone — per person, per organisation — so revoking it removes exactly their access and nobody else's. Their past actions stay in the trail, attributed to them, for the full year.
  </Accordion>

  <Accordion title="Can an assistant reach another organisation I belong to?">
    No. The organisation is resolved from the credential, and no tool accepts one as an argument. Working on a second organisation means a second consent, and therefore a second credential.
  </Accordion>

  <Accordion title="Could something in a campaign brief make the assistant do something I did not ask for?">
    That is precisely why content coming from your own organisation — briefs, campaign names, questions raised by the copilot or the orchestrator — is returned to the assistant explicitly marked as content to relay or display, never as instructions to follow, whatever it happens to say. Combined with the human gates (approve, confirm an archive, publish Live), the destructive end of the surface is not reachable by text alone.
  </Accordion>

  <Accordion title="What happens if my token expires mid-session?">
    Your tool refreshes it and carries on; you see nothing. If the whole chain has lapsed — 90 days idle — the next call fails cleanly and your tool walks you through the same one-time consent again.
  </Accordion>
</AccordionGroup>

## See also

<CardGroup cols={2}>
  <Card title="Connect your AI tool" icon="plug" href="/docs/ai/connect-your-ai-tool">
    The one-time consent that issues the credential.
  </Card>

  <Card title="MCP tools" icon="screwdriver-wrench" href="/docs/ai/mcp-tools">
    What each tool actually does.
  </Card>

  <Card title="API keys" icon="key" href="/docs/environments/api-keys">
    The other Notifizz secrets, and where each one belongs.
  </Card>

  <Card title="Privacy friendly" icon="lock" href="/docs/concepts/privacy-friendly">
    Why there is no customer data to leak in the first place.
  </Card>
</CardGroup>
