delete_roles_by_id

Changes data · you confirm first Idempotent

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

ArgumentTypeDescription
idpathstring (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.

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "delete_roles_by_id",
    "arguments": {
      "id": "11111111-1111-4111-8111-111111111111"
    }
  }
}
Confirmation
The client shows the person the exact request and waits. Nothing runs until they tick Make this change. See Reading and changing.

Result

On success (HTTP 200) the tool returns one text item holding the API's JSON, pretty-printed.

Archival confirmation, in the success envelope.

json
{
  "data": {
    "id": "11111111-1111-4111-8111-111111111111",
    "status": "ARCHIVED"
  },
  "message": "Role archived successfully",
  "success": true
}

Fields

FieldTypeDescription
dataobject
data.idstring (uuid)
data.status"ARCHIVED"
message"Role archived successfully"
successtrue

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.

400

id is not a UUID, with an ARRAY-shaped details; or the DAL's validation refused the archiving save, carrying the DAL's sentence.

403

Missing execute:DeleteRoleCommand, the role is a system role (code: SYSTEM_ROLE_PROTECTION), or the DAL refused the caller (no code).

404

No such role — Role not found with code: ROLE_NOT_FOUND — or a DAL NOT_FOUND refusal, which carries the DAL sentence and no code.

409

The role is still assigned to groups — details is 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.

json
{
  "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
  }
}