# Connect an AI assistant to Superdocu (MCP)

Superdocu exposes an **MCP** (Model Context Protocol) server that lets an AI
assistant (Claude, ChatGPT, etc.) act on a consumer account: list/validate
documents, chase contacts… through the same access controls as the app.

Client-side integration is **a single URL**: everything else (OAuth, client
registration, consent) is automatic.

## For a client (production)

MCP server URL: `https://app.superdocu.com/mcp`

### Claude (Desktop or claude.ai)
1. Settings → **Connectors** → **Add custom connector**.
2. Paste `https://app.superdocu.com/mcp`.
3. A window opens: sign in to Superdocu and **authorize** the requested
   accesses (shown in clear).
4. Connected. The assistant can call the Superdocu tools.

### ChatGPT
Settings → **Connectors** → add an MCP connector with the same URL.

### Any other MCP client
Point the client at `https://app.superdocu.com/mcp`. It discovers the
authorization server via the standard endpoints
(`/.well-known/oauth-protected-resource`,
`/.well-known/oauth-authorization-server`), registers itself (DCR, RFC 7591)
and runs the OAuth 2.1 + PKCE flow.

No config file, no API key to copy: that's by design.

## What happens behind the scenes (OAuth 2.1)

```
client → GET /.well-known/...                discovery
       → POST /oauth/register                registration (DCR, public client)
       → /oauth/authorize (browser)          consumer login + consent screen (PKCE S256)
       → POST /oauth/token                   exchange code → JWT (aud = .../mcp, 1h, refresh)
       → POST /mcp (Bearer <JWT>)            MCP session
```

The consent screen lists the requested scopes in clear (e.g. "See every
contact in your company", "Review, approve and reject documents") as
checkboxes — you can **uncheck any access you don't want to grant** before
authorizing.

## Available tools

The server only exposes to each assistant the tools covered by the scopes it
has authorized (and a tool also requires the matching consumer role
permission). The surface mirrors the REST API v2 one-to-one.

Always on:

| Tool | Required scope | Effect |
|---|---|---|
| `me_show` | `mcp` | Consumer identity + permissions + scopes |

`see_all_contacts` and/or `manage_contacts` (contacts surface):

| Tool | Required scope | Effect |
|---|---|---|
| `contact_list` / `contact_show` | `see_all_contacts` or `manage_contacts` | List / read contacts |
| `contact_workflow_list` / `contact_workflow_show` | `see_all_contacts` or `manage_contacts` | List / read assigned workflows |
| `workflow_list` / `workflow_show` | `see_all_contacts`, `manage_contacts` or `manage_workflows` | List / read workflow templates (`workflow_list` takes `include_disabled` for authoring). `workflow_show`'s `include_stats` completion aggregates need `see_all_contacts` or `manage_contacts` — a `manage_workflows`-only token gets the tree without them |
| `contact_tag_list` | `see_all_contacts` or `manage_contacts` | List company tags |
| `shared_document_list` / `shared_document_url` | `see_all_contacts` or `manage_contacts` | List / signed URL of shared documents |
| `contact_timeline_global` / `contact_timeline_contact` | `see_all_contacts` | Activity timelines |
| `contact_download` / `contact_workflow_download` / `download_show` | `see_all_contacts` or `manage_contacts` | Schedule and poll ZIP exports |
| `contact_create` / `contact_update` / `contact_delete` | `manage_contacts` | Create / update / delete a contact |
| `contact_invite` / `contact_enable` / `contact_disable` | `manage_contacts` | Invite / enable / disable a contact |
| `contact_remind` / `reminder_options` / `reminder_list` | `manage_contacts` | Send / inspect / list reminders |
| `contact_workflow_create` / `update` / `archive` / `unarchive` / `delete` | `manage_contacts` | Manage a contact's workflows |
| `contact_tag_create` / `contact_tag_delete` | `manage_contacts` | Create / delete a tag |
| `shared_document_update` / `update_position` / `delete` | `manage_contacts` | Manage shared documents |

`validate_documents` (validation surface):

| Tool | Required scope | Effect |
|---|---|---|
| `dashboard_show` | `see_all_contacts` + `validate_documents` | Triage stats + pending actions |
| `documents_group_show` / `step_request_show` | `validate_documents` | Read a document group / step request |
| `documents_group_approve` / `request` / `mark_not_applicable` / `approve_not_applicable` / `refuse_not_applicable` / `update_expiration` / `delete` | `validate_documents` | Validate a document group |
| `document_approve` / `reject` / `url` / `delete` | `validate_documents` | Validate a single document |
| `step_request_approve` / `reject` / `update` | `validate_documents` | Validate / correct a form answer |
| `custom_documents_group_create` | `validate_documents` | Add a custom document group to a state |

`manage_workflows` (workflow authoring — build and edit sequences):

| Tool | Required scope | Effect |
|---|---|---|
| `workflow_create` | `manage_workflows` | Create a sequence — just a name, or a whole blueprint (steps, modules, reminders) in one call |
| `workflow_update` / `enable` / `disable` / `duplicate` | `manage_workflows` | Edit / enable / disable / duplicate a sequence |
| `workflow_state_create` / `update` / `reposition` | `manage_workflows` | Add / edit / reorder a step |
| `step_input_add` / `attach` | `manage_workflows` | Add a module from the blueprint DSL, or attach a reusable catalogue item |
| `step_input_update` / `reposition` / `set_conditions` | `manage_workflows` | Edit a module, reorder it, set its display conditions |
| `workflow_update_reminders` | `manage_workflows` | Configure a sequence's automated reminders |
| `company_document_type_list` / `show` | `manage_workflows` | Browse the reusable document catalogue (ids for `step_input_attach`) |

The module/field grammar for `workflow_create` and `step_input_add` is published
as the MCP resource `superdocu://resources/workflow-blueprint` (read it with
`resources/read`). Editing a sequence only affects future assignments, never
contacts already in progress. Structural deletes (removing a step, a module or a
whole sequence) are **not** exposed yet — disable a sequence instead.

`manage_portals` (public self-enrolment portals):

| Tool | Required scope | Effect |
|---|---|---|
| `portal_list` / `portal_show` | `manage_portals` | List / read portals (with their `public_url`) |
| `portal_create` / `update` / `delete` | `manage_portals` | Create / edit / delete a portal |
| `portal_publish` / `unpublish` | `manage_portals` | Take a portal live (its workflow must be enabled) or offline |

File uploads (importing contacts, uploading documents) are not exposed over
MCP: the protocol is JSON-RPC with no multipart, so binary input stays on the
REST API. Outbound files are returned as short-lived signed URLs
(`*.url`, `*.download` + `download_show`).

These tools mirror the REST API v2: same organizers, same access controls, same
data shapes. For ids, payloads, error codes and the end-to-end validation
workflow, read the [API v2 tutorial](https://developers.superdocu.com/api-v2/tutorial).

## Errors

A failed call comes back as an MCP **tool error** (`isError: true`), not a
JSON-RPC protocol error: the result is a text block holding a JSON object with a
machine-readable `code`, the `resource`, and a human-readable `detail` (some
codes add fields). This is a different shape from the REST JSON:API error
envelope — handle it on `code`.

| `code` | Meaning |
|---|---|
| `insufficient_scope` | The token was never granted a scope this tool needs — re-authorize the connection (see below). |
| `permission_denied` | The scope is granted but the consumer's role lacks the permission — an account admin must grant it. |
| `not_found` | No record with that `id` is visible to this consumer. |
| `missing_required_attributes` | A required attribute is absent; the missing names are echoed in `missing`. |
| `validation_failed` | The record was rejected; reasons are in `detail`. |
| `rate_limited` | A per-token quota was hit (see Rate limits) — `limit` and `retry_after` say how long to wait. |
| `invalid_cursor` | A `list` got a malformed `after`/`before` cursor — drop it to restart from the first page. |
| `idempotency_in_progress` | An identical call is still running (see Idempotency & retries) — retry once it completes. |
| `idempotency_key_payload_mismatch` | An `idempotency_key` you supplied was reused with different arguments — use a fresh key. |
| a precondition reason (e.g. `not_rejectable`, `already_archived`, `active_contacts_limit_reached`) | The record isn't in a state that allows the action; read its `available_actions` first. |

## Rate limits

The tools that email a contact or schedule a file export are rate-limited **per
access token**, on the same budgets as the REST API v2 — and counted separately
from it (each token gets its own allowance):

| Tools | Limit |
|---|---|
| `contact_invite`, `contact_remind`, `document_reject`, `step_request_reject`, `documents_group_request` (anything that emails a contact) | 30 / min |
| `contact_download`, `contact_workflow_download` (ZIP exports) | 10 / min |

Over budget, the call returns a tool error with code `rate_limited`, a
human-readable `detail`, the applied `limit` and a `retry_after` in seconds —
wait that long, then retry. Every other tool (reads, generic writes,
`download_show` polling) is only bounded by a generous per-IP fallback.

## Idempotency & retries

Mutations and creates are **idempotent on retry**. If a call fails in transit and
you replay it with the same arguments, Superdocu does **not** run it twice: it
returns the original result instead of creating a duplicate contact/workflow or
sending a second email. A replayed result carries `"_idempotent_replay": true`
at the top level of its JSON — treat it as "already done", not as a new action.

- Deduplication is automatic, keyed per access token + tool + arguments, over a
  short window (a few minutes). Two genuinely different payloads are never
  merged; the same payload sent again within the window replays.
- Two identical calls **in parallel** return `idempotency_in_progress` for the
  second one while the first is still running — retry it once the first completes.
- For a strong, long-lived guarantee, pass an explicit `idempotency_key` (any
  stable string) in the arguments: reusing it replays for up to 48h, and reusing
  it with *different* arguments returns `idempotency_key_payload_mismatch`.

Reads are never cached this way; only mutations and creates are.

## Granting more access later (new scopes)

Scopes are **fixed when the connection is authorized** — they are baked into the
access token. A live connection never gains a scope retroactively, and a tool
gated by a scope you didn't grant simply won't appear in the tool list.

When Superdocu adds a new scope (or you want to grant one you skipped):

1. The new scope is advertised in the discovery metadata (`scopes_supported`),
   but your existing connection keeps its original scopes.
2. To obtain it, **re-authorize the connection**. In Claude/ChatGPT, remove and
   re-add the Superdocu connector: the client re-registers, and the consent
   screen lets you approve the additional scopes.
3. The new tools then appear on the next connection with the upgraded token.

The assistant is told this via the server instructions, so it can guide you when
a capability is missing. Note: even with the right scope, a tool also requires
the matching **role permission** on the consumer account — otherwise the call
returns `permission_denied`, which an account admin must resolve.
