Skip to content

Access

$ access · 6 min read · updated 2026-05-05

capsol treats every install as hosted mode. MCP URLs are addresses, not credentials. Identity comes from the authenticated credential subject.

CredentialScopeStored at rest
Operator bootstrap keyRegistry setup and dashboard loginplaintext only in ~/.capsol/admin.key when generated; dashboard cookie stores sha256(key)
OAuth access tokenOne MCP client install/session/grantsha256(token) in credentials.json; issued through OAuth
Enrollment tokenPending agent signup, then enrollment-scoped MCP credential after approvalsha256(token)

Set CAPSOL_SECRET_KEY or CAPSOL_SECRET_KEY_FILE for hosted deployments. Keep it outside CAPSOL_DATA_DIR.

Every capsule has a stable MCP URL:

https://capsol.example.com/mcp/<capsule-id>

OAuth-capable clients should connect to that URL and let the client discover auth:

/.well-known/oauth-protected-resource/mcp/<capsule-id>
/.well-known/oauth-authorization-server
/.well-known/openid-configuration
/oauth/register

The client registers dynamically, runs authorization-code + PKCE S256, and receives a connection credential for that one client install/session. plain PKCE is not accepted.

The registry-level /mcp URL is allowed for OAuth when exactly one capsule exists. If there are multiple capsules and a client starts from /mcp, the authorization page asks the operator to choose the capsule before issuing the credential.

Manually copied MCP bearer credentials are disabled by default. OAuth access tokens are still transported with Authorization: Bearer <access-token> because that is the OAuth protected-resource mechanism, but capsol does not expose copy-paste connection tokens as the normal product path.

?token=... URLs return a migration error. Revoke a connection when a credential is lost or exposed.

Connections are whitelist-based:

ScopeEffect
capsule:readlist, search, read allowed entries
capsule:appendcreate new entries
capsule:writecreate, replace, and patch entries
capsule:manageoperator-level capsule management in dashboard/REST/CLI surfaces
signal:sendbroadcast capsol_signal messages
registry:manageexposes the capsol_manage tool — agent-as-operator inside policy ceilings
registry:approvelets the designated supervisor principal decide the approvals queue

Roles map to scopes for convenience: reader, appender, writer, owner. The two registry:* scopes are never part of a role, an enrollment request, or an OAuth scope set — only a human operator grants them (dashboard share creation, REST, or capsol init --grant-operator).

Humans get OIDC-backed operator identities with roles instead of sharing one root key:

RoleCan
adminEverything
approverDecide grants, enrollments, and proposals; read everything
auditorRead everything (logs included); mutate nothing
memberFull control over capsules they own; read-only on team-visible capsules; create capsules

OIDC logins map email → operator. Unknown emails on the allow-list auto-provision with oidc.default_operator_role (default member). Every authorization decision flows through one chokepoint (canAct(actor, action, resource)); every approval and mutation records its actor (operator:<id> or break-glass).

The admin key is break-glass: it still works everywhere, acts as a virtual admin, is logged loudly once real operators exist, and the dashboard shows a persistent banner while you use it. Prefer your operator account.

Invite teammates from Operators (or POST /v1/operators/invites): a single-use signed link, mailed when SMTP is configured and always displayed in the dashboard. Accepting binds the invited email through OIDC — password login does not exist; access is OIDC or break-glass only.

Capsule visibility and the org library (0.19)

Section titled “Capsule visibility and the org library (0.19)”

Capsules are private by default. Owners can publish them: team (every operator sees them in the dashboard Library and can request access; members get read-only content access) or discoverable (additionally listed — names and descriptions only — to authenticated agents via capsol_capsules(action="discover")). Access requests are standard grant requests routed to the capsule owner and approvers.

A principal holding registry:manage sees the capsol_manage tool: create_capsule, list_capsules, update_capsule, archive_capsule (soft — hard delete stays human-only), create_share (never above the agent’s own role or the max_share_role ceiling), and request_grant_for (files a normal request; a human approves). Every action becomes a proposal: within policy it applies instantly; a hard-ceiling breach is vetoed with a machine-readable reason the agent can adapt to; everything else queues for approval in the dashboard Proposals view.

Ceilings live in Settings → Approval policy: manage_enabled (off by default), max_capsules_per_principal, capsule_name_pattern, max_share_role, allowed_manage_actions, and manage_rate_per_hour. Bootstrap in one command:

Terminal window
capsol init --grant-operator my-agent

With approval policy autonomous_mode: "supervisor" and a supervisor_principal_id, pending enrollments and proposals route to a queue that principal decides — a human session or an agent credential carrying registry:approve — via GET /v1/approvals/pending and POST /v1/approvals/:id/approve|deny. Agent supervisors are hard-blocked (escalation_forbidden) from approving anything that would grant registry:manage or registry:approve; only humans hand out registry-level scopes. Under autonomous_mode: "policy", queued proposals auto-apply and grant requests matching an access profile flagged auto_approve clear with no human.

Connections can be narrowed by:

  • allowed_schemes: ["docs", "skills"]
  • allowed_uris: ["docs://readme"]
  • allow_prefixes: ["docs://public/"]
  • deny_prefixes: ["docs://public/drafts/"]

Deny wins. Effective access is the intersection of principal scope, connection scope, and content scope.

Remote MCP clients can discover auth metadata:

/.well-known/oauth-protected-resource/mcp/<capsule-id>
/.well-known/oauth-authorization-server

Dynamic Client Registration is available at /oauth/register when enabled in Settings → OAuth clients. That settings panel also controls native redirect schemes, web redirect hosts, whether DCR clients need a client secret, CIMD support, and the localhost CIMD test override. Unauthenticated MCP requests return 401 with WWW-Authenticate, protected-resource metadata, and the recommended collaborator scope capsule:read capsule:append capsule:write signal:send. /.well-known/openid-configuration is available for clients that probe OIDC discovery before OAuth authorization server metadata.

When an unauthenticated user or agent reaches /oauth/authorize, capsol shows a request-access page instead of an admin-key prompt. The requester can choose scopes, schemes, exact entries, URI prefixes, label, and client type. That creates or updates a pending OAuth grant in the dashboard Grants queue. After an operator approves it, the MCP client should retry authorization; capsol recognizes the approved grant and returns the OAuth authorization code.

MCP transport requests also enforce hosted safety checks: unexpected browser Origin headers are rejected, POST requests must accept both application/json and text/event-stream, and malformed JSON-RPC payloads fail with HTTP 4xx before tool handlers run.

For hosted registries, configure operator login from Settings → Operator OIDC in the dashboard. The dashboard stores the client secret encrypted with CAPSOL_SECRET_KEY and only returns client_secret_set status to the browser.

Environment variables are still supported for bootstrapping:

Terminal window
CAPSOL_OIDC_ISSUER=https://issuer.example.com
CAPSOL_OIDC_CLIENT_ID=...
CAPSOL_OIDC_CLIENT_SECRET=...
CAPSOL_OIDC_ALLOWED_EMAILS=alice@example.com,bob@example.com
# or
CAPSOL_OIDC_ALLOWED_DOMAINS=example.com

The dashboard shows Continue with OIDC. The bootstrap admin key remains available for first setup and break-glass access.

Configure approval email from Settings → Enrollment email in the dashboard. The SMTP URL is write-only and encrypted with CAPSOL_SECRET_KEY. Use Send test after saving settings to verify the transport. When SMTP is enabled, POST /v1/agent-enrollments attempts to email the human approver and returns email_sent.

Agents can request access without receiving capsule data:

Terminal window
curl -X POST https://capsol.example.com/v1/agent-enrollments \
-H "Content-Type: application/json" \
-d '{
"client_id": "openclaw-worker-1",
"capsule_id": "<capsule-id>",
"agent_label": "OpenClaw worker 1",
"requested_role": "appender"
}'

The response includes pending_human_approval, pending_supervisor_approval, or approved depending on the approval policy, plus enrollment_id, grant_request_id, verification_uri, user_code, expiry, and a one-time enrollment token. Pending polls do not return MCP connection details. After dashboard or grant approval, that token becomes an enrollment-scoped MCP credential for the new connection.

Operators can review pending OAuth grants, approve OAuth or enrollment grants, deny, expire, or revoke approved grants from the dashboard Grants page. Enrollment grants can also be approved or denied from the CLI:

Terminal window
capsol grants list --registry https://capsol.example.com
capsol grants approve <grant-id> --registry https://capsol.example.com --scopes capsule:read
capsol grants deny <grant-id> --registry https://capsol.example.com --reason "not needed"

Approval is never a blind copy of the request. Approved scopes are intersected with the requested scopes and the registry approval-policy ceiling. The default policy is human approval with the Collaborator ceiling and no capsule:manage.