Authentication & RBAC¶
Every MCP connection authenticates with a bearer token — an
application_key minted via the admin API. The
key is project-scoped: one key serves exactly one Compass project, and
the server can't be tricked into talking to another.
Authorization: Bearer <application_key>
What auth resolves into¶
When the server accepts a connection, it runs the bearer token through
MCPAuthenticator.resolve() and produces an AuthInfo that every
tool call sees:
{
"project_id": "<the_only_project_this_key_can_touch>",
"source": "application_key",
"app_name": "Acme — production CRM",
"access_scope": {
"is_supervisor": True, # service-account default
"roles": ["Admin"], # for role-gated tools
"allowed_agents": [], # empty == full project
"require_mapping": False,
}
}
project_idis injected into every tool call. The client cannot override it — it's read from the key document, never from the request.access_scopeis the RBAC envelope: which agents can the caller see, which role-gated tools can it invoke.
Three common key shapes¶
The same code path serves admin, supervisor, and individual-agent use cases — only the key document's RBAC fields differ.
Admin / service-account key (the default)¶
{
"is_supervisor": true,
"roles": ["Admin"],
"allowed_agents": []
}
Sees every call in the project. Default for any key minted without custom RBAC fields. Ideal for backend integrations.
Supervisor key¶
{
"is_supervisor": false,
"roles": ["Supervisor"],
"allowed_agents": ["Alpha Agent", "Beta Agent"],
"require_mapping": true
}
Sees only the listed agents' data — across every tool that touches
agent-level data (search_calls, get_call_detail, compare_calls,
get_project_summary, get_agent_performance, get_project_context,
query_interactions, detect_changes). Catalog tools (get_signals,
search_guidance) and query_knowledge_base remain project-wide.
The require_mapping: true flag means "fail closed if the allowlist
goes empty" — a guard against accidentally upgrading a supervisor key
to full-project access by editing the doc.
Single-agent (read-only style) key¶
{
"is_supervisor": false,
"roles": [],
"allowed_agents": ["Alpha Agent"],
"require_mapping": true
}
Sees only "Alpha Agent" data. The empty roles excludes them from
admin-gated tools like query_user_activity.
RBAC narrowing across tools¶
| Tool | Narrowed by allowed_agents? |
Role-gated? |
|---|---|---|
search_calls |
yes | no |
get_call_detail |
yes (404 on cross-agent reads) | no |
compare_calls |
yes (both sessions must be in scope) | no |
get_project_summary |
yes (all aggregations) | no |
get_agent_performance |
yes | no |
get_project_context |
yes (roster + interaction aggregations) | no |
query_interactions |
yes (pipeline match-injection) | no |
detect_changes |
yes | no |
query_user_activity |
n/a (admin tool) | yes — Admin / SuperAdmin |
get_signals |
no (global catalog) | no |
search_guidance |
no (global catalog) | no |
query_knowledge_base |
no (global per-project KB) | no |
"Not found" vs "denied"¶
Cross-agent reads on get_call_detail (and compare_calls) return the
same 404-shaped error as a genuinely non-existent session:
{ "error": "Call not found: <session_id>" }
Intentional — it prevents callers from enumerating which sessions belong to which agents.
Minting scoped keys¶
See Admin API → mint.
All four shapes (admin / supervisor / single-agent / custom) are minted
through the same POST /projects/{project_id}/mcp-keys endpoint with
different body fields.
Revoking access¶
DELETE /projects/{project_id}/mcp-keys/{key_id} flips active=false
on the key document. Subsequent auth attempts fail with
"Invalid or inactive API key". The doc isn't deleted so the audit
trail is preserved.
What the server logs¶
On successful auth:
MCP auth via application_key: project_id=<id> app=<name>
The raw bearer token is never logged.