---
title: "Assistant and tools"
description: "The tools the assistant and an MCP client call, each run with the permissions of whoever calls it."
order: 11
---

The tools the assistant and an MCP client call, each run with the permissions of whoever calls it.

## `GET /api/v1/assistant/status`

Whether the assistant is set up, and when it is not, the sentence that says why.

| Status | Means | Body |
| --- | --- | --- |
| 200 | Done | [AssistantStatusResponse](#assistantstatusresponse) |
| 401 | Bad token |  |

## `GET /api/v1/assistant/threads`

This operator's threads, newest first, with their messages and proposals.

| Status | Means | Body |
| --- | --- | --- |
| 200 | Done | array of [ThreadResponse](#threadresponse) |
| 401 | Bad token |  |

## `POST /api/v1/assistant/threads`

Open a thread. The project and the environment are the panel's own scope, and they are what fills in a tool argument the model leaves out, so a thread opened on staging never silently acts on production.

**Body:** [OpenThreadBody](#openthreadbody)

| Status | Means | Body |
| --- | --- | --- |
| 200 | Done | [ThreadResponse](#threadresponse) |
| 401 | Bad token |  |
| 404 | No such project |  |

## `GET /api/v1/assistant/threads/{id}`

One conversation with its messages and proposals.

| Parameter | In | Type | About |
| --- | --- | --- | --- |
| `id` | path | string (uuid) |  |

| Status | Means | Body |
| --- | --- | --- |
| 200 | Done | [ThreadResponse](#threadresponse) |
| 401 | Bad token |  |
| 404 | No such thread |  |

## `DELETE /api/v1/assistant/threads/{id}`

Delete a thread, and forget every secret value parked for it.

| Parameter | In | Type | About |
| --- | --- | --- | --- |
| `id` | path | string (uuid) |  |

| Status | Means | Body |
| --- | --- | --- |
| 204 | Deleted |  |
| 401 | Bad token |  |
| 404 | No such thread |  |

## `POST /api/v1/assistant/threads/{id}/messages`

Send a message and get the answer, with any changes the assistant proposes. Refused while a proposal still waits for a decision.

| Parameter | In | Type | About |
| --- | --- | --- | --- |
| `id` | path | string (uuid) |  |

**Body:** [PostMessageBody](#postmessagebody)

| Status | Means | Body |
| --- | --- | --- |
| 200 | Done | [ThreadResponse](#threadresponse) |
| 401 | Bad token |  |
| 404 | No such thread |  |
| 409 | A proposal is still waiting for a decision |  |
| 422 | Empty or oversized text |  |
| 429 | Too many assistant messages from this operator |  |
| 503 | No model is configured, or the provider did not answer |  |

## `POST /api/v1/assistant/threads/{id}/proposals/accept-all`

Accept every waiting proposal of the newest answer, in order, stopping at the first one that fails. The rest stay waiting.

| Parameter | In | Type | About |
| --- | --- | --- | --- |
| `id` | path | string (uuid) |  |

| Status | Means | Body |
| --- | --- | --- |
| 200 | Done | [ThreadResponse](#threadresponse) |
| 401 | Bad token |  |
| 404 | No such thread |  |

## `POST /api/v1/assistant/threads/{id}/proposals/{proposal_id}/accept`

Accept one proposal, which carries out the change with your permissions.

| Parameter | In | Type | About |
| --- | --- | --- | --- |
| `id` | path | string (uuid) |  |
| `proposal_id` | path | string (uuid) |  |

| Status | Means | Body |
| --- | --- | --- |
| 200 | Done | [ThreadResponse](#threadresponse) |
| 401 | Bad token |  |
| 404 | No such thread or proposal |  |
| 409 | Already decided, or no longer executable |  |

## `POST /api/v1/assistant/threads/{id}/proposals/{proposal_id}/reject`

Reject one proposal. Nothing changes.

| Parameter | In | Type | About |
| --- | --- | --- | --- |
| `id` | path | string (uuid) |  |
| `proposal_id` | path | string (uuid) |  |

| Status | Means | Body |
| --- | --- | --- |
| 200 | Done | [ThreadResponse](#threadresponse) |
| 401 | Bad token |  |
| 404 | No such thread or proposal |  |
| 409 | Already decided |  |

## `GET /api/v1/assistant/tools`

Every tool, with the permission it costs and whether this caller could run it where the query points.

| Parameter | In | Type | About |
| --- | --- | --- | --- |
| `project` (optional) | query | string or null |  |
| `environment` (optional) | query | string or null |  |

| Status | Means | Body |
| --- | --- | --- |
| 200 | Done | [ToolsResponse](#toolsresponse) |
| 401 | Bad token |  |

## `POST /api/v1/assistant/tools/{name}`

Run one tool AS THE CALLER. The body IS the tool input, verbatim.

| Parameter | In | Type | About |
| --- | --- | --- | --- |
| `name` | path | string |  |

**Body:** object

| Status | Means | Body |
| --- | --- | --- |
| 200 | Done | [ToolCallResponse](#toolcallresponse) |
| 401 | Bad token |  |
| 404 | No such tool |  |
| 422 | The input does not match the tool's schema |  |

## Types

### AssistantStatusResponse

| Field | Type | About |
| --- | --- | --- |
| `configured` | boolean |  |
| `model` (optional) | string or null | `anthropic` or `fake`; null when nothing is configured. |
| `sentence` | string | The sentence the panel prints when `configured` is false, `""` otherwise. |

### ThreadResponse

| Field | Type | About |
| --- | --- | --- |
| `created_at` | string |  |
| `environment` | string |  |
| `id` | string (uuid) |  |
| `messages` | array of [ThreadMessage](#threadmessage) |  |
| `page` | string |  |
| `project` (optional) | string or null |  |
| `proposals` | array of [ProposalResponse](#proposalresponse) |  |
| `role` | string | The caller's role name in this thread's project, which is what the change set footer's chip prints. |
| `state` | string | `idle` (nothing pending), `waiting` (one or more pending proposals) or `refused` (the last turn stopped on a refusal). |
| `title` | string |  |
| `updated_at` | string |  |

### OpenThreadBody

| Field | Type | About |
| --- | --- | --- |
| `environment` (optional) | string or null |  |
| `page` (optional) | string or null |  |
| `project` (optional) | string or null |  |

### PostMessageBody

| Field | Type | About |
| --- | --- | --- |
| `text` | string | What the operator typed. 1 to 8000 characters. |

### ToolsResponse

Everything the caller may see, whether or not they may run it.

| Field | Type | About |
| --- | --- | --- |
| `tools` | array of [ToolDescriptor](#tooldescriptor) |  |

### ToolCallResponse

The answer to one tool call. It is a 200 even when the tool refused or failed, which is what lets `ops mcp` copy `is_error` into MCP's `isError` inside a RESULT rather than inventing one out of a 403 body.

| Field | Type | About |
| --- | --- | --- |
| `is_error` | boolean | `true` when the tool refused or failed; the MCP proxy copies it into `isError` and the assistant loop into `is_error`. |
| `result` | object | The tool's own answer. On an error, `{"error": "<sentence>"}`. |
| `tool` | string |  |

### ProposalResponse

| Field | Type | About |
| --- | --- | --- |
| `decided_at` (optional) | string or null |  |
| `environment` | string |  |
| `id` | string (uuid) |  |
| `message_id` | integer |  |
| `permission` | string |  |
| `project` (optional) | string or null |  |
| `result` | object | Present once decided. `{"error": "…"}` on a rejection or a failure. |
| `rows` | array of [ProposalRow](#proposalrow) |  |
| `status` | string | `pending`, `accepted`, `rejected` or `failed`. |
| `tag` | string | `read` or `write`, the same tag `GET /assistant/tools` reports. |
| `title` | string |  |
| `tool` | string |  |

### ThreadMessage

| Field | Type | About |
| --- | --- | --- |
| `at` | string |  |
| `id` | integer |  |
| `role` | string | `user` or `assistant`. |
| `stop_reason` (optional) | string or null |  |
| `text` | string | Every `text` block of the turn, joined with a blank line. The console renders this; the raw blocks stay in the database. |

### ToolDescriptor

| Field | Type | About |
| --- | --- | --- |
| `allowed` | boolean | Would this caller be allowed to run it, in the project and environment the query named? ADVISORY: the executor checks again, so a stale `true` here costs a refusal and never an action. |
| `description` | string |  |
| `input_schema` | object | JSON Schema of the input. |
| `name` | string |  |
| `permission` (optional) | string or null |  |
| `tag` | string | `read` or `write`. Drives ONLY the console's Accept gate. |

### ProposalRow

| Field | Type | About |
| --- | --- | --- |
| `k` | string |  |
| `v` | string |  |
