delete_roles_by_id
Calls DELETE /api/roles/{id} as the signed-in person · REST reference
Archive a role (soft delete)
Requires execute:DeleteRoleCommand; platform staff bypass that gate. Nothing is destroyed: the role's status is set to ARCHIVED and saved through the DAL's UpdateRoleCommand, which drops it out of GET /api/roles while leaving it fetchable by id. The caller's own token is forwarded, so the DAL requires execute:UpdateRoleCommand in the role's own organization and refuses — 403 — a role of the platform organization or a role that belongs to no organization to anyone without platform authority. For such a caller, a role in an organization where they do not hold admin.roles.view is a 404. A system role is 403 SYSTEM_ROLE_PROTECTION. A role held by at least one group is 409 ROLE_IN_USE, whose details is an OBJECT { groupCount } carrying a number, not the canon's string field map. The in-use check runs TWICE: the controller checks the groupCount it loaded, then Role.archive() re-reads the count, so a role that gains a group between the two reads is also 409 ROLE_IN_USE — without the details count. A refusal the DAL's UpdateRoleCommand raises is answered by its code: 400 for its input validation (a stored name that is not 2-50 letters, digits and underscores), 404 for a role it cannot find, 409 for a system role — each with the DAL sentence.
Arguments
| Argument | Type | Description | |
|---|---|---|---|
idpath | string (uuid) | required |
Example call
A client sends this over the MCP session; Claude and other agents build it for you. The values are placeholders — the shape is real.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "delete_roles_by_id",
"arguments": {
"id": "11111111-1111-4111-8111-111111111111"
}
}
}Result
On success (HTTP 200) the tool returns one text item holding the API's JSON, pretty-printed.
Archival confirmation, in the success envelope.
{
"data": {
"id": "11111111-1111-4111-8111-111111111111",
"status": "ARCHIVED"
},
"message": "Role archived successfully",
"success": true
}Fields
| Field | Type | Description |
|---|---|---|
data | object | |
data.id | string (uuid) | |
data.status | "ARCHIVED" | |
message | "Role archived successfully" | |
success | true |
When it fails
A failed call returns isError: true with the API's message as text. A change the person declines, or lets time out, also comes back this way and nothing changes.
400idis not a UUID, with an ARRAY-shapeddetails; or the DAL's validation refused the archiving save, carrying the DAL's sentence.403Missing
execute:DeleteRoleCommand, the role is a system role (code: SYSTEM_ROLE_PROTECTION), or the DAL refused the caller (no code).404No such role —
Role not foundwithcode: ROLE_NOT_FOUND— or a DAL NOT_FOUND refusal, which carries the DAL sentence and no code.409The role is still assigned to groups —
detailsis an OBJECT carrying the count, not a string — or the DAL refused the archiving save as a conflict, carrying its sentence.
What the model is shown
This is the tool exactly as the server lists it in tools/list. The description starts with the REST call it makes.
{
"name": "delete_roles_by_id",
"description": "DELETE /api/roles/{id} — Requires `execute:DeleteRoleCommand`; platform staff bypass that gate. Nothing is destroyed: the role's status is set to ARCHIVED and saved through the DAL's `UpdateRoleCommand`, which drops it out of `GET /api/roles` while leaving it fetchable by id. The caller's own token is forwarded, so the DAL requires `execute:UpdateRoleCommand` in the role's own organization and refuses — 403 — a role of the platform organization or a role that belongs to no organization to anyone without platform authority. For such a caller, a role in an organization where they do not hold `admin.roles.view` is a 404. A system role is 403 `SYSTEM_ROLE_PROTECTION`. A role held by at least one group is 409 `ROLE_IN_USE`, whose `details` is an OBJECT `{ groupCount }` carrying a number, not the canon's string field map. The in-use check runs TWICE: the controller checks the `groupCount` it loaded, then `Role.archive()` re-reads the count, so a role that gains a group between the two reads is also 409 `ROLE_IN_USE` — without the `details` count. A refusal the DAL's `UpdateRoleCommand` raises is answered by its code: 400 for its input validation (a stored name that is not 2-50 letters, digits and underscores), 404 for a role it cannot find, 409 for a system role — each with the DAL sentence.\n\nThis changes data. The person is asked to confirm it before it runs, and nothing happens if they decline.",
"inputSchema": {
"type": "object",
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
]
},
"annotations": {
"readOnlyHint": false,
"destructiveHint": true,
"idempotentHint": true,
"openWorldHint": false
}
}