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

# Tools

> A curated, growing set over the whole platform — how to get the authoritative list, and the two behaviours that surprise people first.

**Preview.** The tool set is curated by hand and is still growing. This page
describes the groups and the rules every tool follows. It deliberately does
**not** reprint the tool list: the registry (`mcpserver/tools/`) is the only
authoritative source, and a table copied out of it here is wrong the first time
somebody adds a tool.

## What the set is, and what it is not

Two sentences worth getting straight, because the shape of a tool list is easy to
misread as the shape of a product.

> **Every operation the REST API exposes is reachable.** The full surface is the
> [Runtime API](/v2/overview) — documents, extractions, reports, runs,
> conversations, jobs, knowledge, webhooks, logs and the rest, with an OpenAPI
> document generated from the running code.

> **The MCP set is the part chosen for a model to pick correctly.** It is a
> curated selection over that same surface, not a subset of what the platform can
> do.

That curation is the point rather than a limitation. One tool per endpoint would
mean dozens of near-identical descriptions, and a model's real difficulty is not
reaching an operation — it is telling `list_documents` from `search_knowledge`
from `search` at the moment it has to choose. Tools are added when a workspace
question cannot be answered without them, and each is written to be picked
correctly rather than to complete a matrix. If something you need is not a tool
yet, it is almost certainly an endpoint; the Runtime API tab has it, and the gap
is worth telling us about.

<Warning>
  **Do not hard-code a tool name in an unattended integration.** Preview means
  names and schemas can move between releases. Call `tools/list` at connection
  time. The transport guarantees on [Limits](/connect/limits) are steadier than
  the ones about tools, and that difference is deliberate.
</Warning>

## Getting the authoritative list

Two live documents answer this, and neither can go stale.

### `tools/list` — every tool, with its schema

```bash theme={null}
curl https://api.impellabs.tech/mcp \
  -H "Authorization: Bearer tgcc_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2025-06-18" \
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' \
  | jq -r '.result.tools[] | "\(.name)\t\(.title)"'
```

It is filtered by nothing — a key holding only `mcp:connect` sees the whole
catalogue — so this is the honest answer to *"what exists"*, and it is the same
list your client discovered when it connected.

### The metadata document — every scope the set can ever need

```bash theme={null}
curl -s https://api.impellabs.tech/.well-known/oauth-protected-resource \
  | jq '.scopes_supported'
```

No credential required. That array is computed as the union of every scope some
registered tool honours, intersected with the platform's own closed scope
vocabulary — so it is a live measure of the breadth of the set, and it is what
the consent screen is built from.

<Note>
  `tools/list` reports each tool's **name, title, description and input
  schema**. It does not report the scope, because a scope is checked against the
  caller's credential and is not a property a model needs in order to choose.
  The scope surface is the metadata document above; which scope a given call
  demanded is named in the 403 if it is missing, in full and in one challenge.
</Note>

## The groups

Eleven, and between them they cover configuring the platform, running it, and
reading what it produced.

| Group            | What it reaches                                                                                                                        |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **Agents**       | Listing, reading, creating, updating and publishing the assistants in your workspace                                                   |
| **Knowledge**    | Ingesting sources into the index, and asking the index a question                                                                      |
| **Documents**    | Uploading a file, reading its metadata, reading its parsed text                                                                        |
| **Intelligence** | Extractions against a schema, and generated reports                                                                                    |
| **Runtime**      | Running an agent, and listing and reading conversations                                                                                |
| **Catalog**      | The listings — documents, extractions, reports, knowledge sources, widgets, tools — so an id can be *found* rather than only followed  |
| **Business**     | Leads, appointments and calls: what the assistants actually produced                                                                   |
| **Webhooks**     | Endpoints, event types, deliveries, and replaying one                                                                                  |
| **Logs**         | Developer logs — every run this credential may see, and the steps behind one                                                           |
| **Operations**   | Polling and cancelling jobs, the credit balance, and where the credit went                                                             |
| **Research**     | `search` and `fetch`, the two fixed-schema tools ChatGPT's connector surface requires, mapped onto knowledge search and document fetch |

Every scope these draw on is a real member of the same registry `/api/v2/` uses
(`adminapi/services/developer.py::SCOPES`) — there is no MCP-only permission
vocabulary. See [Authentication and scopes](/v2/authentication) for the whole
list.

<Note>
  **Some absences are decisions, not gaps.** No tool deletes a customer's data,
  and no tool returns a credential — a webhook signing secret is returned by the
  REST API on create and rotate, and by no tool at all, ever. The Business group
  is read-only for the same kind of reason: writing a lead or booking an
  appointment fires a side effect at a real person outside the conversation, and
  nothing inside the conversation can undo it.
</Note>

## Rules every tool follows

<AccordionGroup>
  <Accordion title="Each tool checks its own scope, on every call">
    `mcp:connect` gets you `tools/list` and nothing else. The scope a tool needs
    is checked inside the dispatcher when it is called, not once per connection.
  </Accordion>

  <Accordion title="Handlers call the service layer, not our own HTTP API">
    And they reuse each app's existing serializer. That is why an MCP payload and
    a REST payload for the same resource cannot drift apart — there is one
    function producing both.
  </Accordion>

  <Accordion title="Every call is pinned to one workspace">
    Resolved from the credential by lookup, never from anything the caller
    asserts. A tool asked for a resource belonging to another workspace answers
    **not found**, not *forbidden* — a 403 would confirm the resource exists.
  </Accordion>

  <Accordion title="A tool that cannot answer returns something the model can say">
    Out of credit, not found, bad argument: HTTP **200**, a result marked
    `isError: true`, and readable text. Transport and auth failures are HTTP
    statuses; everything that happens inside a tool is not.
  </Accordion>

  <Accordion title="Every listing has a ceiling">
    One page limit for the whole set. A model that asks for a thousand rows wants
    the first page and does not know it — and a thousand-row result is also
    several thousand tokens of somebody else's context window.
  </Accordion>
</AccordionGroup>

## Two behaviours that surprise people

These are the first two things that will look like bugs and are not. Both are
described in the tool descriptions themselves, so a model reading them is told —
but you should know them too, because you will be reading the transcript.

### 1. Four operations answer with a job, never a result

**Extractions, reports, knowledge ingestions and jobs** are queued. Always. The
tool returns a job id and says to poll; it does not block waiting for the work,
because holding a worker open on a poll loop is how a queue becomes an outage.

```
  start_extraction  ──►  { "job_id": "job_…", "status": "queued" }
                                    │
                              get_job(job_id)
                                    │
        queued ──► running ──► completed | failed | cancelled
```

<Warning>
  A model that reports "done" straight after the first call has reported the
  **queue**, not the outcome. If a client tells you an extraction finished
  without ever mentioning a job, ask it to check the job id — the result may not
  exist yet, and it may have failed.
</Warning>

The five job states and the moves between them are the same ones the REST API
uses; [Jobs](/v2/jobs) documents them in full, including what happens when an
outcome is genuinely unknown.

### 2. `upload_document` succeeds before the document is readable

Upload returns **success while parsing continues in the background**. Reading
the document's text immediately afterwards returns **409
`document_not_processed`** — and it will keep doing so until parsing finishes.

<Warning>
  This is the one that produces a false failure report. Left to itself a model
  will call upload and then read, back to back, get the 409, and tell you the
  upload failed. It did not. Wait, or poll, and read again.
</Warning>

The same 409 is what `/api/v2/documents` returns for the same reason, and for
the same document; see [Documents](/v2/documents).

## What a call costs

A tool call costs whatever the operation behind it costs — nothing is priced
differently for arriving over MCP. Read tools are free of credit; anything that
uploads, ingests, extracts, generates or runs an agent is not.

<CardGroup cols={2}>
  <Card title="Credits" icon="coins" href="/connect/credits">
    How spend is metered, and what an empty wallet returns.
  </Card>

  <Card title="Runtime API" icon="code" href="/v2/overview">
    The full surface these tools are curated from.
  </Card>
</CardGroup>
