Skip to content

MCP tokens

The token an agent uses to talk to RootPilot is a PAT — a personal access token. It grants read access to your entire infrastructure, through the Agent running inside it. It is a first-class credential, and this page is what you need in order to issue one without regretting it.

The token belongs to a person, not to the organization

Section titled “The token belongs to a person, not to the organization”

That has a consequence which precedes any scope decision: a token with no owner is always read-only. Tokens issued outside a user — by the operations CLI, or inherited from before tokens were personal — have no identity to attribute, so the write gate fails closed and they never write. If what you want is an agent that opens tickets, the token has to belong to someone.

Writing passes two independent checks, and passing one is not passing the other:

  1. The token scope — read or write, chosen at issue time.
  2. The owner’s role — the mcp:write permission, which belongs to owner and admin.

Scope is an additional restriction, never a promotion:

Token scope Owner’s role Result
read owner / admin Read-only
read member Read-only
write owner / admin Read plus the five write tools
write member Read-only
any no owner (CLI/legacy) Read-only

The role door is the one that fails closed: an inactive user, a role that does not resolve, a lookup error — all of them deny the write rather than allow it. The scope door only knows how to block, which is why it is an extra restriction and never the only one.

So why would anyone pick write? For one concrete reason: that person wants their agent to open a Jira ticket or post to Slack during an investigation, without leaving the flow. Otherwise read is the right answer — and it is the issuing form’s default, on purpose. What exactly a write token unlocks is in what the agent writes.

At creation time the raw token value appears exactly once. What persists in our database is only its sha256.

There is no recovery. There is no “show the token again” screen, and no support path that can extract it — we literally do not have it. If it is lost, the path is revoke and issue another.

A member does not have to become an admin to get MCP access. They request, someone authorizes, and they generate it themselves:

State What has happened What is missing
pending The requester asked (name, scope, reason) An owner/admin to review
approved An owner/admin authorized the name and scope The requester still has to generate the token
claimed The requester generated it — and saw the value, once Nothing; the token exists
denied An owner/admin refused Nothing; the request is closed

The confusing state is approved, and it deserves to be spelled out: approved is not having a token. Approval authorizes; the token only comes into existence when the requester generates it. Until then, no secret has been created at all.

Where each side acts: whoever requests and later generates sees their requests in their profile; whoever reviews sees the queue under Governance.

Generating twice from the same request cannot happen: the approved → claimed transition is atomic, so two simultaneous attempts produce exactly one token.

Revocation is soft — the token is marked revoked, and the row stays for the sake of the trail. It is scoped to the organization (you cannot revoke another org’s token) and it becomes an audit event.

The effect is immediate in practice: token identity is resolved on every request, not just when the session opens. An in-flight MCP session using a revoked token dies on the next call, with 401. Nothing has to expire first.

Two metadata columns exist exactly for this, and both are what separates “forgotten token” from “token someone is using”:

  • Last used. Updated when the token authenticates (with a one-minute window, so we are not writing on every request). A token nobody has used in months is a revocation candidate — and it is the cheapest hygiene list available here.
  • Observed origin. The network address that token last reached us from — it is how a use from somewhere nobody expected becomes visible, and it is where you start when configuring the network origin allowlist, instead of guessing the block. We keep only the last address, it is erased along with the token on revoke, and it disappears on its own after 90 days without recurring; anyone who does not want the record can turn it off, on the allowlist screen.

These are not hypotheticals; they are the usual three:

  • A committed .mcp.json. The MCP client’s config file lives in the project directory. If the literal token is inside, it goes into the repository — and stays valid in history after being “removed”.
  • CI logs. An echo of variables, a --verbose command, an environment dump from a failed step.
  • Laptop backups. Project directories syncing to personal cloud storage.

On suspicion, revoke. It is the only answer that closes the hole. The network origin allowlist narrows the window — a leaked token stops being enough, because being on your network is also required — but it does not replace rotation, and anyone with both the token and access to the allowed network still gets through.

Issuing, revoking and every step of the request flow become events in your organization’s audit trail, with the actor. The writes made with the token are a separate trail, attributed per user — see what the agent writes.