Remove User (admin)
Requires admin-scoped API key
This tool is only available when authenticated with an admin-scoped
Phoenix API key. User-scoped keys never see it in tools/list and
receive 403 forbidden_admin_scope if they try to call it directly.
See Admin operations overview for details.
Destructive
Removes the user from the org and revokes all of their API keys and OAuth tokens for this org. This cannot be undone — the user must be re-invited if they're added back.
Hard-deletes the user's team memberships in the calling org and revokes
their access. The user's public.users record is preserved so historical
attribution (audit log targets, conversation creators, etc.) stays intact.
Tool key: admin_remove_user
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
user_id | UUID | Yes | ID of the user to remove. Snake_case to match MCP convention. |
Required Integrations
None.
How It Works
The org slug is derived from the API key. Then:
- Self-removal guard. If
user_idmatches the calling user, the tool returnscannot_remove_self. - Membership pre-flight. If the user has no active membership in
this org, the tool returns
user_not_found. (Also returned for cross-orguser_idvalues, so cross-org probes are indistinguishable from "user does not exist.") - Owner protection. If the user is the org owner, the tool returns
cannot_remove_owner. - Tenant transaction with advisory lock. Inside a tenant
transaction, a Postgres advisory lock keyed on the org slug
serializes concurrent removals. Distinct admin user_ids are counted;
removing this user must leave at least one other admin in the org or
the tool returns
last_admin. - Tenant deletes.
team_membershipsand tenantapiKeysrows for this user are deleted inside the transaction. - Public deletes.
webapp_api_keys_registryrows for(userId, organizationSlug)are deleted (this is what actually invalidates the key —validate()is a single public-schema join), followed byoauth_tokensrows for the same(userId, organizationSlug). - Cache invalidation. Org-access cache and MCP org-context cache
are flushed so a stale
tools/listfor the removed user's keys doesn't keep serving from cache. - An audit row is written with action
remove_user, target_typeuser, target_id =userId, metadata ={ removedMembershipsCount }.
Use Cases
- Offboarding workflow: HR system fires when an employee leaves; a Power Automate flow calls this tool to revoke Phoenix access in lockstep.
- AI-assisted admin: "Remove bob@acme.com from Phoenix" via Claude
Desktop with an admin-scoped MCP key (after a
admin_get_consumptioncall to look up the user_id).
Example Usage
MCP JSON-RPC
{
"jsonrpc": "2.0",
"id": "1",
"method": "tools/call",
"params": {
"name": "admin_remove_user",
"arguments": {
"user_id": "9a3a9b40-3a6f-4f0a-9f8e-1b7f0b2c0d10"
}
}
}
Response
{
"userId": "9a3a9b40-3a6f-4f0a-9f8e-1b7f0b2c0d10",
"removedAt": "2026-04-29T16:42:11.000Z",
"removedMembershipsCount": 1
}
Error codes
| Code | Trigger |
|---|---|
invalid_user_id | user_id is not a UUID. |
cannot_remove_self | user_id matches the calling user. |
cannot_remove_owner | user_id is the org owner. Transfer ownership first. |
last_admin | Removing this user would leave the org with zero active admins. |
user_not_found | No active membership for that user_id in this org. |
forbidden_admin_scope | Key is user-scoped or the user is no longer an org admin. |