> ## Documentation Index
> Fetch the complete documentation index at: https://docs.minidesk.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Tools

> The seven tools, what they take, and what they return.

Seven tools. Six read, one writes a draft. Clients discover them through the
standard `tools/list`, so nothing here needs a custom integration.

Every summary carries `as_of`. A queue changes while an agent is reading a
recap of it, and a figure with no timestamp is a figure someone quotes in a
meeting an hour later.

## get\_support\_summary

How the queue looks right now.

**Input:** none.

```json theme={null}
{
  "as_of": "2026-08-28T14:22:10Z",
  "open_conversations": 59,
  "by_status": { "new": 12, "open": 38, "pending": 9, "resolved": 104 },
  "oldest_waiting_hours": 32
}
```

`open_conversations` counts `new`, `open`, and `pending` together. `resolved`
and `closed` have left the queue, so they appear in `by_status` but not in the
total.

## list\_oldest\_unanswered

Conversations with no reply since the customer's last message, oldest first.

**Input:** `limit`, 1 to 50, default 10.

```json theme={null}
{
  "as_of": "2026-08-28T14:22:10Z",
  "data": [
    {
      "id": "0195e2c1-...",
      "reference": "ACME-1042",
      "preview": "Clicking export does nothing.",
      "priority": "high",
      "waiting_since": "2026-08-27T06:12:00Z",
      "requester": "sam@customer.com"
    }
  ]
}
```

<Note>
  "Unanswered" is not the same as `status = "new"`. A ticket someone opened,
  read, and left is unanswered in every sense a customer cares about, and its
  status is `open`. This checks whether there has been a public reply since
  the requester's last message.
</Note>

## get\_agent\_workload

How many open conversations each active member is assigned.

**Input:** none.

```json theme={null}
{
  "as_of": "2026-08-28T14:22:10Z",
  "data": [
    { "name": "Priya", "open_assigned": 14 },
    { "name": "Sam", "open_assigned": 3 }
  ]
}
```

Active members only. A deactivated colleague keeps their message history but
does not count as capacity.

## get\_ticket

One conversation and its **public** messages.

**Input:** `ticket_id`, required.

```json theme={null}
{
  "as_of": "2026-08-28T14:22:10Z",
  "id": "0195e2c1-...",
  "reference": "ACME-1042",
  "status": "open",
  "priority": "high",
  "category": "billing",
  "language": "en",
  "messages": [
    {
      "author_type": "requester",
      "body": "Clicking export does nothing.",
      "created_at": "2026-08-27T06:12:00Z"
    }
  ]
}
```

Internal notes are not filtered out of the result; they are never fetched in
the first place. An MCP client is an AI agent whose output a person may paste
anywhere, and an internal note reaching one is the same leak as it reaching a
customer, one step removed.

An unknown or cross-workspace id returns `{ "error": "not_found" }`.

## search\_knowledge

Find the workspace's own reference documents by topic.

**Input:** `query` (an empty query lists everything), `limit` 1 to 25, default
10\.

```json theme={null}
{
  "query": "refund policy",
  "documents": [
    {
      "document_id": "0195dd40-...",
      "title": "Refunds and cancellations",
      "language": "en",
      "tokens": 1840
    }
  ]
}
```

Titles and sizes only, not the text. A search that returned full documents
would spend the context window on the four the model did not want. `tokens` is
there so it can tell a one-line rule from a handbook before asking for it.

## read\_document

The full text of one reference document.

**Input:** `document_id`, required. Get it from `search_knowledge` first.

```json theme={null}
{
  "document_id": "0195dd40-...",
  "title": "Refunds and cancellations",
  "language": "en",
  "complete": true,
  "content": "Refunds are available within 14 days..."
}
```

Documents are read whole, up to 80,000 characters. Past that, `complete` is
`false` and a `note` says how much was returned:

```json theme={null}
{
  "complete": false,
  "content": "...",
  "note": "This document is 240000 characters and you are reading the first 80000. Say what you could not check rather than assuming the rest agrees."
}
```

The cut is announced rather than silent, because a silent cut reads as the
complete text and the reply then states a policy that the unread half
qualifies.

Passing something that is not a document id returns a message telling the model
to search first, rather than a database error. Models otherwise tend to guess a
filename from a title.

## create\_draft\_reply

The only write. It writes a draft.

**Input:** `ticket_id`, required.

```json theme={null}
{
  "draft_id": "0195e3a0-...",
  "body": "Thanks for flagging this. It was a permissions bug and it is now fixed.",
  "confidence": 0.82,
  "grounding_score": 0.91,
  "delivered": false,
  "note": "This is a draft. It reaches nobody until a person sends it."
}
```

`delivered: false` and the note are returned every single time, on purpose, so
a connected agent cannot tell its user that a reply was sent.

The draft is stored for review in the dashboard, with the calling model
recorded and an audit log row written in the same transaction.

Possible errors:

| `error`              | Meaning                                |
| -------------------- | -------------------------------------- |
| `not_found`          | Unknown ticket, or another workspace's |
| `ai_disabled`        | AI is switched off for this workspace  |
| `no_draft_available` | The model produced nothing usable      |

## Tools that do not exist

There is no `send_reply`, `update_ticket`, `assign_ticket`, or
`resolve_ticket`.

Their absence is the security model, not an oversight.
[The reasoning is here](/mcp/safety).
