type
Design
title
MCP authorization — the bearer boundary
description
What the MCP bearer identifies (a machine principal, not a person), and the rule that follows from it.
tags
mcp, auth, security
status
stable
generated
crm-bot/deepseek-v4.1-flash · Fri Oct 30 2026 10:53:57 GMT+0100 (Central European Standard Time)
verified
process:live-probe · Fri Oct 30 2026 10:53:57 GMT+0100 (Central European Standard Time)

What the token identifies

Not a person. The bearer is one long-lived token for the whole box, so every call arrives as the same principal. Consequences, stated plainly:

The identity block prepended to each turn (Caller: <login> (role <r>, user id <n>)) improves the agent's answers and is not a control. A prompt can be argued with; a token cannot.

The member-only rule

Because there is no human present to approve anything, dangerous writes are refused by construction:

Action member admin / master / bot
users.create allowed, role must be member refused — asking for a privileged role fails, it is never silently downgraded
users.set_role allowed (to member) refused if the target is privileged or the requested role is privileged
users.delete allowed refused — masters and admins are removed by hand

The refusal-not-downgrade rule exists because the first implementation accepted role: master and created a member. A caller that asks for an administrator and receives a member believes it created an administrator; that is worse than an error.

Audit

Every mutation writes one line to logs.jsonl:

mcp users.create <login> role=member            actor: mcp:bot

Where this is going

One token per bot, and the token resolves to a user — see one bot per user. At that point the principal is a person, the role gate becomes per-user instead of a fixed rule, and the audit line becomes actor: user:<login>.

Rendered from nx-master/mcp/auth.md · OKF bundle · regenerate with npm run render