Rollout provides a Model Context Protocol (MCP) server that lets AI assistants like Claude Code work inside your workspace. An assistant connected over MCP can read and manage tasks, projects, objectives, documents, workflows, and more — always acting as you, inside one workspace.
Quick setup for Claude Code
1. Add the MCP server
Add Rollout to your Claude Code MCP configuration — ~/.claude.json for all projects, or .claude/mcp.json inside a project:
{
"mcpServers": {
"rollout": {
"type": "http",
"url": "https://your-rollout-instance.com/mcp"
}
}
}
Replace your-rollout-instance.com with your Rollout URL (or localhost:4000 for local development).
2. Authenticate
Run /mcp in Claude Code and pick the Rollout server to start authentication. Claude Code:
- Registers itself with Rollout automatically
- Opens your browser to Rollout's Authorize Application page, which shows the application name, the permissions it requested, and the workspace access will be granted in
- Waits for you to click Authorize (or Deny)
After you authorize, the browser redirects back to Claude Code and the connection is ready.
Note: access is granted for the workspace you are signed into when you approve. Switch workspaces before authorizing if you need a different one.
3. Start using it
Ask Claude Code in plain language:
List my open tasks
Show the Website Redesign project
Create a task to review the PR
Authentication
Rollout uses OAuth 2.1 with PKCE. This means:
- No passwords stored in your Claude Code config
- Access tokens expire after 1 hour and are refreshed automatically; refresh tokens expire after 30 days
- Scopes limit what the assistant can do
- Everything runs as you — an MCP client can never see or change more than your own membership allows
OAuth scopes
When authorizing, you see which scopes are requested:
| Scope | Description |
|---|---|
read |
View tasks, projects, documents, workflows, and other workspace data. The default when a client requests no scopes. |
write |
Create and update tasks, projects, documents, workflows, records, and other resources |
admin |
Team/member administration and workspace-wide dashboard sharing/assignment, on top of write. Domain actions also require your current workspace role or team authority. |
Revoking access
There is no in-app page for managing authorized MCP clients yet. To stop an assistant's access:
- Remove the Rollout server from the client's MCP configuration — without a refreshed token, access ends when the current access token expires (at most 1 hour)
- MCP clients can revoke their own tokens at the standard
/oauth/revokeendpoint
Available tools
Reading and discovery
These tools work with the read scope and never change data:
| Tool | Description |
|---|---|
query |
Precise, filtered reads over any data source: Task, Project, Objective, KeyResult, Milestone, Workflow, WorkflowRun, WorkflowStepRun, Document, Record, Metric, Team, Activity, ResourceRef, ResourceLink, Connection, Attachment, Dashboard, SavedView, Cycle, CycleSchedule, Label, LabelGroup, Channel (messaging channels you can see; direct messages are never exposed), and Secret (names and lifecycle metadata of the secrets you can use, never a value; there is no tool that creates, rotates, or deletes one). Channel, Secret, Cycle, CycleSchedule, Dashboard and SavedView take plain key:value filters without sorting or grouping. Supports filters, sorting, grouping, and pagination. WorkflowRun error and WorkflowStepRun inputs/outputs are list-mode opt-ins through preloads. |
search |
Semantic + text search across tasks, projects, documents, objectives, records, and attachments |
workspace_context |
Your identity plus the workspace vocabulary: task statuses and types, projects, teams, custom record schemas, and the per-source query grammar |
node_types |
Paginated workflow-node catalog; filter by category, palette group, vendor, or exact node IDs |
workflow_inspect |
One workflow's effective Draft and settings, immutable releases, authoring branches, a bounded exact-source inspection with range reads, and one run's results |
attachment_url |
Short-lived download URL and metadata for an attachment |
guide |
Manuals for the tools on this page: query grammar, per-source upsert fields, authoring contracts and lifecycle rules. Call it with no topic for the index; tool descriptions and error messages name the topic to read next |
Querying Record by a schema's own fields: the filter key is the bare field name (company:acme, not data.company), and those keys are only in scope when the same filter pins exactly one object with a positive object: or object_id: term. workspace_context(include:["query_sources"]) lists only the static Record filters; read the per-schema field names, types, position and display_config from include:["objects"].
text, number, date, boolean, select and user_ref fields are filterable out of the box. rich_text and formula fields are filterable only where display_config.filterable was turned on — their default is false — and a formula must return a number. datetime, json and list fields expose no filter key at all, even though display_config reports filterable: true for all three. Filtering on one of those names rejects the entire query in either strict setting.
Rich text reads as Markdown: a description, a Document's content, an Activity's body and a record's rich-text values in data. Pass format: "json" for the editor's document JSON instead. A list row carries a plain-text summary (at most 160 characters) in place of the body; name the body in fields, or read one record by ref, to get it. Writes take the same Markdown back: a string is always Markdown and a map is document JSON, so you can read, edit and write back without converting.
Custom values come back inside the record's data object, not as top-level keys. A fields name may be a dotted path, so fields:["data.company"] returns that one value and drops its siblings, while fields:["data"] returns all of them. A shared field whose name matches one of the record's own serialized keys (id, ref, slug, title, number, primary_status, primary_date, object_id, object, data, created_at, updated_at, display) is shadowed at the top level, and which of those a read emits varies (object and display need a read that pins one object, and a schema-pinned list read drops ref and slug), so name the custom value as data.<field_name> to reach it. A requested name that resolves in no returned row is dropped: a list read reports it in warnings, a ref read hands back the record alone and cannot.
Shared write tools
These tools work across resources. Each lists the sources it supports in its source field, and each source keeps its own authority rules.
| Tool | Description |
|---|---|
upsert |
Create or sparsely patch a record through its owning command. ref updates an exact record, upsert_key matches or creates, no selector creates. expected carries the optimistic guard a read returned, and dry_run validates without writing; both are refused on sources that cannot honour them. Per-source fields: guide(topic:"upsert.sources") |
archive |
Archive a resource, or restore it with restore:true. Recoverable: the row leaves default reads and keeps its history. Accepts ref or up to 50 refs |
purge |
Permanently delete a resource and what cascades from it. Its description states each source's precondition (for example, a workflow must be archived first) |
access |
Read or change who may see or use a resource: grant/revoke a team or workspace audience, and for dashboards and saved views assign/unassign a default or required placement. Rules per source: guide(topic:"access.rules") |
Tasks and planning
Write tools require the write scope:
| Tool | Description |
|---|---|
upsert |
Create or sparsely patch a Task, Project, Objective, Milestone, or Key Result using canonical fields and ISO dates; exact ref updates and opaque upsert_key matches or creates |
archive with source: "Task" |
Archive (soft-delete) or restore tasks, with batch support |
task_planning |
Plan a Task into its Team's backlog, Current, Next, or an exact Cycle; move a Task, or a parent with its whole subtree (preview, then apply the reviewed digest), to another Team; add a missing contributing Team to a Project while moving the Task to it |
cycle_schedule |
Activate, reconfigure, or deactivate one Team's Cycle Schedule at its safe boundary, with a dry_run impact preview. Applying takes expected (the Schedule's lock_version, plus the previewed impact_digest for deactivate). Requires the admin scope plus schedule-governor authority |
Cycles and Cycle Schedules belong to exactly one Team, so query on Cycle or CycleSchedule needs a team: filter; there is no workspace-wide current Cycle. Cycle takes state:current (the default: opening, open, or finalizing), state:next (the Team's earliest scheduled Cycle), or state:completed; a ref read returns the same row and adds the Team-lane progress report with preloads:["report"]. Only members of the Team can read its Cycles. A CycleSchedule row carries the lock_version, effective cadence, and the activation/deactivation previews cycle_schedule works from.
Workflows
| Tool | Description |
|---|---|
upsert with source: "Workflow" |
Create a Paused workflow without a graph, or update its name, slug, description, labels, owner, team and execution settings (runtime, env, services, volumes, defaults). Its run identity (runs_as with run_as_agent, an agent id or @handle) is written alone on an existing workflow and needs manage access |
workflow_edit |
Edit the main Draft or a branch Draft graph under the observed-source guard, or cut an authoring branch |
workflow_release |
Publish a Draft as the Current release, restore an earlier release, pause or start production; one transition per call |
workflow_run |
Start a production run (optionally waiting up to 120 seconds for the result), cancel or retry runs, and preview and admit exact-source node tests |
archive / purge with source: "Workflow" |
Archive (disarms triggers, keeps runs and releases) or restore; permanently delete an archived workflow, or discard a never-published pending Draft |
Each workflow tool's description names a guide topic that carries its full contract:
workflow.settings, workflow.edit, workflow.inspect, workflow.release and workflow.run.
A new workflow is two calls: upsert creates it with no graph, then workflow_edit gives it one.
A workflow without a graph needs no guard for its first edit. For a whole graph, send one
replace_flow operation so the complete nodes-and-edges document is validated and written under
one optimistic lock. Any edit that changes the graph's structure ends with a full layout of the
Draft; nodes locked with locked: true (or data.locked) keep their positions and the rest is laid
out around them. A node or edge the
canonical shape would have to drop is refused by name rather than silently repaired. update_node
supports merge or replacement modes for both config and execution settings, plus explicit
top-level key removal. set_schedule updates a schedule's cron, timezone, and description without
rebuilding the graph. workflow_inspect and node_types accept read-scoped tokens and survive
read-only mode; every other workflow tool requires write.
workflow_inspect tells a caller what a workflow takes and returns before it starts one.
action: "status" (the Current release) and action: "release" (the release asked for) return
contract: {entry_node_id, inputs, outputs, digest}. inputs is a JSON Schema of the inputs
the Manual start declares (required lists what must be sent, default what an absent key
becomes, enum the allowed values, and any other key is refused), or null when it declares
none and takes any object. outputs is a JSON Schema of what the workflow's return steps
declare, or null when they declare nothing. digest changes whenever either does. Build
workflow_run start's input_data from contract.inputs: a start missing a required input or
sending a key no input declares is refused with every field named, and no run is created. A
workflow the caller cannot read returns not found and no contract. A Tool on Run workflow
declares the same inputs as typed arguments. It starts its workflow only when an AI agent step
calls it inside a workflow run, so invoke refuses it and says so; start the workflow with
workflow_run.
workflow_inspect with action: "branches" names this workflow's live authoring branches as
identity only — id, name, revision (the branch's lock version), has_draft, timestamps — plus
main_draft_revision for the main Draft, which is the workflow row and is never listed as a branch.
It is how a branch id is obtained without opening the editor: action: "releases" names only
branches that already published something. The graphs are neither returned nor read. Read one exact
source with action: "source".
create_branch cuts a new branch from the source its selector names, using the same grammar as
a source inspection's selector ({"kind":"release","id"|"name"} with "current" accepted as the name,
{"kind":"branch","id"}, or {"kind":"main_draft"}, which is the default). It is the only
operation in its call. A release is named by id and re-resolved server-side, so the branch's
baseline is that release exactly as published. Nothing else moves: no existing Draft, no other
branch, no published pin. It switches nothing and runs nothing.
The response's source is the RESOLVED selector, not the one that was sent: ask for
{"kind":"release","name":"current"} and it comes back as that release's exact id, because Current
is an alias that moves on the next publish. source_revision carries the baseline's lock version
(null for a release). Sending source_revision pins the cut: a Draft that moved since the
revision you inspected is refused with stale_source rather than seeding a graph you never read.
Graph edits carry expected: the expected_source object of the exact Draft the caller inspected.
It also decides which Draft the batch writes:
{"source": {"kind": "main_draft"}, "source_revision": 7, "source_digest": "sha256:..."}
{"source": {"kind": "branch", "id": "<branch id>"}, "source_revision": 3, "source_digest": "sha256:..."}
The first writes the main Draft, the second that branch's Draft; nothing else in the call can
point the batch somewhere else. The main Draft needs a guard once the workflow has a graph, and a
branch edit always carries one, because the guard is what names the branch. It is compared against
that Draft's canonical row inside the write transaction, not against a fresh read the tool takes
for itself. A moved revision or digest is refused with stale_source and nothing is written.
source_revision is that row's lock_version (the workflow's for the main Draft, the branch's for
a branch): it advances on every write, so an edit that restores a graph to earlier bytes is still
detected even though its digest is unchanged. Unknown keys in the guard — and in any operation
object — are refused rather than ignored.
Copy the whole expected_source object a read hands back into expected. workflow_inspect returns one for
action: "flow" (the main Draft) and for a main_draft or branch source inspection (whose source
key is a fuller identity object, not a guard, and is refused as one), and every successful edit
returns the guard the next edit of the same Draft needs, so a chain of coupled batches costs one
read. action: "branches" lists the branch ids. A branch that does not exist, is archived or
belongs to another workflow is refused as not found and nothing is written. A branch edit reaches
production only when workflow_release(action: "publish", branch_id) publishes it. A guard naming
a release is refused: releases are immutable. When the stored graph cannot be digested at all,
action: "flow" returns expected_source_unavailable instead of a guard, and the graph is repaired
by saving it in the editor.
workflow_release publish, restore and start check every connection, secret and device the
release uses with the checks Start applies. A refusal names each one that is not available and
where it is used, in the sentences the editor shows ("Secret API_KEY is missing (used by
Deploy)."), for a caller who can write the workflow. A connection or device that caller cannot
use stays nameless; anyone else gets the undifferentiated refusal.
An edit returns a bounded changes summary (the nodes that actually moved and the paths within
them, with long values previewed and secret material shown as markers) alongside the resulting
expected_source. At most 16 moved nodes with at most 64 changed paths each are reported, under a
fixed byte budget; an entry past that budget is reported as its node id plus detail_omitted. The
whole updated graph is returned when the response fits the 64 KiB bound; otherwise draft_omitted
is set and the response names the source inspection that reads it in bounded pieces.
One guarded edit is one transaction over one Draft row: the workflow row for the main Draft, the branch row for a branch Draft. A change that also writes a Document, a tool binding, or anything in another domain is a separate commit with its own recovery.
Tools, parameters and actions are closed: a parameter the chosen action does not read is refused
rather than ignored, so a misspelled option (for example inert? on a node test) can never read as
applied.
Node config is strict at save and publish time. Keys must be declared by that node's manifest (apart
from the documented platform-owned keys), and execution settings belong at
node.data.execution_settings. Unknown or misplaced keys are errors rather than silently ignored
configuration.
Apps and governed tools
| Tool | Purpose |
|---|---|
app |
Create, update, edit, read, configure, undo, deploy and validate Apps. |
tool |
Configure actions owned by an App, Agent profile or Workflow node; inspect readiness and target consent; follow or cancel reviews. |
invoke |
Prepare one direct native or remote call, follow its status, cancel undispatched work and download its result. |
Read an App with query(source:"App",ref:"<id or slug>"). Use app
action:"read" for source text by path. update replaces the source bundle;
edit accepts put, delete, rename and entry operations with the observed file
checks. update, edit, configure and undo require expected_version
from the lock_version in your latest read. Read and reconcile a stale write
before submitting another change.
For native Apps, Save validates and builds before replacing the live frontend.
A failed or superseded build preserves the accepted frontend. Explicit action
restrictions can still take effect: save_failed with
restriction_applied:true includes the refreshed App version and diagnostics.
There is no separate native Publish step.
Native Apps retain the live build and one previous accepted build.
app(action:"undo",ref:"<app>",expected_version:...) restores the previous
source and settings through current validation and permissions. Undo never
restores revoked consent or replays calls. Rebuilding unchanged source does
not consume Undo.
Git Apps separate settings Save from source Deploy. Save action settings with
app action:"update" and runtime settings with app action:"configure";
these changes do not rebuild or restart the image. app action:"deploy"
requests a source build. Only successful deployment installs its commit and
image; accepting the request is not deployment success.
Workflow action edits remain in the Workflow Draft. Publish the Workflow to use those edits for new runs; existing admitted runs retain their captured configuration. Agent default edits likewise preserve admitted runs. Explicit revocation still stops affected undispatched calls.
Use access(source:"App",...) for placement and exposure, and
archive(source:"App",...) to retire an App. Manuals include
app.lifecycle, app.components, app.tools and app.constraints.
Consumer-owned actions
Actions belong to their App, Agent profile or Workflow node and have local
aliases. Discover native recipes with guide(topic:"tool.templates"), then
guide(topic:"tool.template",args:{"node_type":"<id>"}). For authorized
remote names and schemas, use:
guide(topic:"tool.templates",args:{"connection_id":"<uuid>"})
guide(topic:"tool.template",args:{"connection_id":"<uuid>","remote_tool":"<name>"})
Read the complete editable list and its write guards:
tool(action:"read",consumer:{"consumer_kind":"app","consumer_id":"<uuid>"})
consumer_kind is app, agent or workflow; a Workflow selector also
requires node_id. tool action:"configure" replaces the complete tools
list using the returned expected and expected_version values. Recipes
contain a local name and label, plus either node_type and settings, or
connection_id, remote_tool and settings.
tool action:"remove" takes those same guards and an action_ref containing
id, name and path. To repair an unavailable action, edit its recipe and
Save the complete owning list. Healthy siblings remain callable. Local and
nested actions exist only for rollout.ai with tool_mode:"replace"; under
inherit or none the list must be [], and a non-empty list is refused.
Switching a node out of replace clears its list.
Save validates configuration and target consent together. MCP-authored
configuration using per-call never requires an exact human review under
workspace policy. Pending replacements remain unavailable until approval.
tool action:"readiness" reports draft validation, not a promise that a
later dispatch will succeed.
tool action:"grants" inspects an exact attachment address and
attachment_id. delegate additionally takes the observed action digest as
expected and a stable request_key; it requests human consent rather than
granting access immediately. review_status and review_cancel take
approval_id. revoke_delegation takes the exact delegation UUID.
Revocation closes affected undispatched calls and their pending reviews;
running, unknown and completed evidence remains intact.
Direct calls and large payloads
invoke action:"run" selects exactly one target:
attachment:{consumer_kind,consumer_id,node_id?,path?,name};node_typewithsettings;connection_idwith the discoveredremote_tool;app: an App id or slug for a source update.
An attachment selector requires configuration access—App/Agent management or Workflow authoring write—plus invoke permission. It selects App live, Workflow published or Agent default configuration and executes as the current authenticated caller. It does not run that consumer or borrow its grants, accounts or installations. A caller-selected run ID cannot supply execution authority. Actual App and admitted Workflow execution use their own server-owned consumer context.
Every new call requires a stable idempotency_key. Selecting an exact,
accepted consumer attachment preserves its configured per-call policy:
always requires a human decision; never can run without a fresh ask.
The caller must independently retain configuration access, invoke permission
and current target and resource rights. Selecting configuration never transfers
the consumer's authority, identity, grants or installations.
Raw one-off node_type, connection_id/remote_tool and App-source requests
require one exact human review, including read-only recipes. Configuration,
target and call review are combined into that decision. No saved action or
reusable target grant is created. An Agent caller remains an Agent.
For example:
invoke(action:"run",
node_type:"rollout.query",
settings:{"presets":{"source":"Team"},"slots":{"query":{}}},
arguments:{"query":"name:Operations"},
idempotency_key:"operations-query-001")
Reuse the key only for the exact same selector, settings and arguments.
Changed requests conflict. An intentional new business call uses a new key.
An outcome_unknown call requires reconciliation; do not submit it again
under a new key.
For the App source shortcut, arguments is
{"source":{"entry":"index.tsx","files":{...}},"expected_version":...}.
Keep the version you observed. An approved successful native source update
goes through Save and becomes live without a separate Publish step.
Results up to 16 KiB are returned inline. Larger results expose
result_bytes; retrieve them with invoke action:"result".
For a large request:
- Write the exact JSON object bytes to
body.jsonand compute their SHA-256, including whitespace and key order. - Call
invoke action:"run"with the target,idempotency_key,presign:trueandbody_sha256:"sha256:<64 lowercase hex>". Omitarguments. - Use the returned
request.curlto POST those bytes. The reply includesinvocation_id;202means approval is pending or execution continues. When review is required, match it using the returnedbinding_code.
status, result and cancel take that existing invocation_id.
status reports state, approval details and bounded results. cancel
withdraws your undispatched call. After a transport timeout, inspect the
existing call before retrying.
result returns a single-use GET receipt and download command for
/api/tenants/<tenant_id>/tool-results. It reads the immutable succeeded
result. Detaching the original configuration does not erase that history.
Current principal and original source authorization remain required. Use the
same API key, or a current OAuth token in the original family; another API key
owned by the same user is a different source.
Admission and result bearers expire within ten minutes and are single-use.
Accepted calls and human reviews have their own lifetime. Bearer expiry does
not erase an accepted call: follow that admitted call with its invocation_id. A consumed admission bearer cannot be reused. If a result
bearer expires or has been consumed, invoke action:"result" can
issue a fresh receipt while the original source remains authorized.
run and cancel require MCP write; status and result require read.
Private transport accepts at most 2 MiB of request bytes and 4 MiB of result
bytes. App/model execution keeps its separate 200,000-byte result ceiling and
App source constraints. Outbound MCP responses retain their 2,000,000-byte
cap. An uncertain external effect is recorded as outcome_unknown, never
silently replayed.
See guide(topic:"tool.lifecycle") and
guide(topic:"invoke.transport") for the current contracts.
Documents and records
| Tool | Description |
|---|---|
upsert |
Create or sparsely patch Tasks, Projects, Objectives, Milestones, Key Results, custom records, Documents, and authored comments or notes. ref updates an exact record; an opaque upsert_key matches or creates within the tenant, source, and custom schema; no selector creates. Custom-record insert-only batches accept up to 50 items. Existing Document body replacements require the digest returned by query; edits change passages of an existing Document's text without it. Only custom records accept a request idempotency_key |
object |
Define custom objects and their fields: create and update a type, and create, update, archive, or restore a field. Archive a whole type with archive |
Collaboration and organization
| Tool | Description |
|---|---|
upsert with source: Activity |
Add an authored comment or note to a resource; comment edits require the existing Activity ref and note edits are unsupported. On a Document, on (a quote of its text) with an optional occurrence anchors a comment thread or an ask on that passage; an ambiguous quote writes nothing and lists the occurrences to pick from. on only starts a thread: combined with upsert_key or ref it is refused and nothing is written. query with anchored:true status:open lists a document's threads with their anchor (quote, anchored or detached, section) and replies. An ask with review: true on a Document puts it up for review (Approve or Changes requested unless you give options); the comments the person writes on it while the review is open belong to it, and reading the ask lists them as ask.review_comments (passage, thread, author, body) beside its answer |
link |
Link or unlink internal records, external resources, and URLs. A contributes_to link from a milestone or project to an objective carries a contribution weight |
label |
Attach, detach, or replace the labels on one resource. Label and label-group definitions are read with query (sources Label, LabelGroup) and written with upsert, archive, and purge |
upsert / archive / access with source: SavedView |
Create, revise (guarded by expected = lock_version, with dry_run validation), archive, and share query-only saved views. A saved view's ref is always its UUID (slugs repeat across contexts). guide(topic:"views.query") lists index contexts and query shapes |
task_config |
Administer the workspace's task statuses and types: create, update, reorder, permanent delete with task reassignment, the default status, and per-project status sets. Deactivate or reactivate one with archive (source: TaskStatus or TaskType) |
Dashboards
Dashboards are Pages with immutable applied widget revisions. Saved Views are reusable query presentations that a Table widget may reference; they are not dashboard layouts.
| Tool | Description |
|---|---|
dashboard |
create a private dashboard with its first widget revision, update title/settings, move its owning context or Document target, and edit widgets (add, update, move, duplicate, remove) as one atomic revision. update/move guard with expected = lock_version; edit guards with expected = current_revision_id. dry_run validates a create or edit without saving |
query with source: Dashboard |
List visible dashboards (filters archived, project, team; preloads:["widgets"]), or read one with ref including its widgets. archived:true lists only your own archived dashboards |
archive with source: Dashboard |
Archive, or restore with restore:true; both require expected = lock_version |
access with source: Dashboard |
Share with a team/workspace and set or unset default/required dashboard assignments. Team actions require write plus team authority; workspace actions require admin plus workspace-admin authority. |
Recommended flow: guide(topic:"dashboard.authoring") for the widget catalog, guide(topic:"dashboard.viz") for chart and stat widgets, dashboard(action:"create", dry_run:true), then dashboard(action:"create"). Re-read with query(source:"Dashboard", ref) before a guarded update or edit.
For a Metric chart, select a metric_definitions entry from guide(topic:"dashboard.viz") and persist its recommended_bucket_fn; workspace_context(include:["query_sources"]) also exposes tenant-scoped Metric name values. For custom-record aggregates, copy the selected Record source's canonical required_query so the executor loads that schema's shared fields.
Dashboard replies no longer carry policy.can_read (a dashboard you can read is one you were returned), the list-level policy.can_create and owner_id_for_new_dashboard, or next_offset (page with limit/offset and has_more). Widget catalog entries no longer carry catalog_zones, page_zones or picker_enabled (use pickable; every Page widget lives in the main zone). Whether you may create a dashboard, and the owner id a new one gets, are in guide(topic:"dashboard.authoring") under caller.
MCP can create, revise, share, assign, archive, and restore dashboards. Publishing a Page to a public URL remains an owner/admin action in the web UI because public data/form bindings require a separate security review. Dashboard authoring is capped at 100 widgets and a 1 MiB encoded composition document.
Administration
These require the admin scope:
| Tool | Description |
|---|---|
team |
Create and update teams; add, update, and remove team members. Delete a team with purge (source: Team, admin token) |
member |
Invite, update roles, deactivate, reactivate, and remove workspace members |
agent |
Create an agent, owned by you and placed in your Private space. The caller must be an active human workspace member. Move or expose it to a Team with access before that Team's workflows run as it |
Configuration
Read-only mode
For safer AI access, self-hosted deployments can enable read-only mode, which removes all write tools from the server:
export ROLLOUT_MCP_READ_ONLY=true
The value is read when the application starts, including from a prebuilt
release, so changing it requires a restart but not an image rebuild. Accepted
true values are true, 1, yes, and on; accepted false values are
false, 0, no, and off. Any other value stops startup instead of
silently exposing write tools.
query(source:"Secret") survives read-only mode. It returns metadata and decrypts
nothing, and a read-only deployment is where an agent reading a workflow most
needs to know which secret names resolve for it.
Read-only mode removes write tools from MCP discovery and dispatch. OAuth
authorization remains an independent boundary: writable deployments still
require each write tool's write or admin scope and domain authorization.
Rate limits
| Limit | Default |
|---|---|
| MCP requests | 100 per minute per user |
Client registration (/oauth/register) |
10 per minute per IP |
Token requests (/oauth/token) |
30 per 15 minutes per IP |
Token revocation (/oauth/revoke) |
30 per 15 minutes per IP |
Requests over a limit receive 429 Too Many Requests with a Retry-After header. MCP responses include x-ratelimit-limit and x-ratelimit-remaining headers.
Troubleshooting
"Authentication successful, but reconnection failed"
This usually means Claude Code has stale credentials. Try:
- Remove any hardcoded
Authorizationheaders from your MCP config - Restart Claude Code
- Run
/mcpagain to re-authenticate
"Invalid or expired token"
Your access token has expired and couldn't be refreshed. Run /mcp to re-authenticate.
"Unauthorized" errors
Make sure:
- You've authorized the MCP client in your browser
- Your token has the required scope for the operation (e.g.
writefor creating tasks) - You're an active member of the workspace you authorized
"Session not found"
After a Rollout server restart, clients holding an old session get a 404 and must reinitialize. Most clients do this automatically; if yours doesn't, restart it.
"Too many requests"
You hit a rate limit. Wait the number of seconds in the Retry-After header and try again. A
retried read is free; a retried write is not, so see the next section before resending one.
A write whose reply never arrived
A connection reset, a timeout, or upstream connect error or disconnect/reset before headers
tells you the request failed, not that the write failed. The server may have committed and lost
the reply on the way back.
For custom records, send idempotency_key on the original upsert call: use a value unique to one
logical request, such as a UUID. Retrying that exact request returns the stored result without a
second write. Reusing it with changed data, selector, or match policy is refused. This request key
is separate from upsert_key, which identifies the durable record. Other sources do not accept a
request idempotency_key.
For any source, an exact ref is update-only and fails if the target is gone. An upsert_key
atomically binds one record under the tenant, source, and schema and can be reused to update it;
the key never comes from hidden matching on a custom record's business fields. With neither
selector, a repeat is a fresh create. Read the Document with query before replacing its body and
send its content_digest as expected; a stale digest refuses the replacement. The replacement
merges into open editors without reloading them.
To change part of a Document, send edits in data instead of a new body:
[{"find": "the old sentence", "replace": "The **new** sentence.", "occurrence": 2}]. find
quotes the Document's visible text (words in order; line breaks and Markdown syntax do not
matter), replace is Markdown, and occurrence picks one of several matches. Text found within
one block is replaced in place and keeps its formatting; a replacement with blocks (paragraphs, a
heading, a list) needs find to cover whole blocks. "replace": "" deletes. Edits apply in order,
all or nothing: a quote that is missing or ambiguous writes nothing, and the error lists the
matches to pick from. Edits need no expected, never go with content, and merge into open
editors like a collaborator's typing. A comment thread whose passage an edit changed is detached;
the others stay anchored.
For other MCP clients
Rollout implements standard OAuth 2.1 with these discovery endpoints:
| Endpoint | Purpose |
|---|---|
/.well-known/oauth-protected-resource |
RFC 9728 resource metadata |
/.well-known/oauth-protected-resource/mcp |
Same document, path-aware form (RFC 9728 §3.1) |
/.well-known/oauth-authorization-server |
RFC 8414 authorization server metadata |
/oauth/register |
RFC 7591 dynamic client registration |
/oauth/authorize |
Authorization endpoint |
/oauth/token |
Token endpoint |
/oauth/revoke |
Token revocation endpoint |
The server supports the authorization_code and refresh_token grant types, PKCE with S256, and public clients (no client secret). Any MCP client that supports OAuth 2.1 with dynamic client registration should work automatically.
Redirect URIs may be HTTPS, a loopback callback (http://127.0.0.1:PORT/…, http://localhost:PORT/…), or a private-use scheme owned by a desktop client (com.raycast-x:/oauth, vscode://…). Schemes that name a code-execution target — javascript, data, file, vbscript — are rejected.
Device settings: query(source:"Device") reads authorized devices and their
max_agent_turns (default 4). upsert(source:"Device", ref:<persisted UUID>, data:{max_agent_turns:6}) changes only that setting, with current owner/exact
Manager authority. Device creation and other fields are rejected.
Workflow execution-path advisories
Successful workflow_edit edits/restores, workflow_inspect graph reads and
workflow_release publish/restore responses include advisories and
advisories_omitted. Detail is bounded; the omitted count explicitly reports
warnings that did not fit. Warnings identify the trigger, unscheduled source,
consumer, wire and missing contributor, without including input or config data.
They permit publication. A batch-data source outside the selected plan, such
as a disconnected document read, needs a path from each intended trigger:
task._done -> role._trigger. Streaming members share a contracted execution
unit: a producer with no incoming edge can still be planned when its consumer
is reachable. That producer, and a scheduled source skipped by a branch, do not
receive this advisory. Run inspection also shows the consumer's persisted step
warnings, recorded before it executes.