safe-mcp sign in

Who may do what.

Access is a rule about a person or a group, down to the values a tool may be called with. An agent has no permissions of its own. Think of a temp working on a colleague's badge: it opens the doors that badge opens and none other, at 03:00 exactly as at noon.

who may do what
whoserverpreset
user dana@acme.coadsoneAccount
group reportingadsread-only
group reportingcrmcontactsOnly

dana sees ads and nothing else. reporting sees ads read-only and two crm tools. nobody else sees either server.

Example, not real data.

One preset: which tools, which keys, which values.

A preset is a named rule over one downstream server: which tools exist in the catalog (the rest are absent, not disabled), which argument keys may be sent, which keys are pinned to a value that is injected into every call and recorded as injected, and a JSON schema overlay checked by the same engine as the tool's own.

Several presets on one server intersect. A preset that would constrain nothing is refused when the project loads.

"presets": {
  "contactsOnly": {
    "tools": [
      "crm_get_contact",
      "crm_search_contacts"
    ],
    "allowedArgumentKeys": [
      "contactId", "query", "limit"
    ]
  },
  "oneAccount": {
    "pinnedKeys": { "customerId": ["1234567890"] }
  }
}

Example, not real data. Shape from the project file format.

An assignment is one line: who, which server, which presets.

A person's surface is the union of what they and their groups are assigned. A server with no assignment for you is not greyed out for you. It is not there.

Three roles exist. A gateway admin operates the service and sees every project. An account owner manages one account: invites, roles, projects, servers, presets. A member works inside it. The last admin cannot be demoted or removed.

Tokens are personal, shown once, revocable in one click.

A personal access token is shown once at creation and stored only as a hash. It is scoped to projects in the holder's own accounts. Tokens issued through OAuth expire after an hour and are refreshed silently; a refresh token is rotated on every use and dies after thirty idle days. Every token appears on the person's card and can be revoked there.

When a downstream server needs OAuth, each person authorizes it with their own identity. An issue created in Linear through the gateway carries the caller's name, not a shared robot's.

a person's tokens
smcp_…9f21personal · acme · created 2026-08-30
oauth · Claudeacme · expires in 41 min
oauth · Cursoracme · revoked 2026-09-01
downstream, as this person
githubauthorized
linearauthorize →

Example, not real data.

Rehearse with writes switched off.

Testing mode blocks every tool the downstream server does not declare read-only, before it runs, and still writes the attempt to the log. Reads proceed as normal. Which tools count as read-only comes from the server's own declaration, and an admin can add names the server forgot. Until someone does, a server that marks nothing is treated as all writes, which is the safe side to err on. The same declaration decides which tools may measure a goal.

The whole policy is one file you can diff.

One project is one JSON file: its downstream servers and its presets. It can be reviewed, diffed and kept in version control. Saving servers or presets in the app rebuilds that project in place; sessions already running finish on the configuration they started with. Deleting a project is queued until the gateway next restarts, and the app keeps saying so until it lands.

Next: what the record guarantees, and what fails how.