# Tools

Cademí MCP offers 396 tools: 5 composite tools that answer common questions in one call, and 391 tools that each call one operation of the Cademí API v3, release 3.4.7. The full list, with the permissions and annotations of each tool, is in the [tool catalog](https://cademi.dev/mcp/catalog.md).

## Composite tools

| Tool | Answers |
|---|---|
| `student_context` | Who a student is, what they are enrolled in, and which products they can access. |
| `student_access_context` | Whether a student can access one product and why, with reason codes, evidence, and suggested actions. |
| `product_context` | What a product is, its top-level content, how it is sold, and its access schedules. |
| `product_structure` | The complete module and lesson tree of a product. |
| `instance_overview` | Which account the connection works on, its status and limits, and its API usage. |

All five are read-only. They never change data: when a fix exists, `student_access_context` suggests the tool to use, and the assistant calls it separately, with your approval.

### How students and products are found

Composite tools take a student as a public ID (`usr_...`), an e-mail address, or a name, and a product as a public ID (`prd_...`) or a name. You never need to look up an ID first.

- **Public ID.** The student or product is retrieved directly.
- **E-mail.** The tool searches the account's students and keeps the one whose e-mail matches exactly, ignoring case.
- **Name.** The tool searches by the name and compares it with up to 20 results. Results whose name matches exactly, ignoring case, are kept. If none matches exactly, all results are kept.

When exactly one student or product is left, the tool uses it. When none is left, the tool returns `RESOURCE_NOT_FOUND`. When several are left, it returns `AMBIGUOUS_REFERENCE` instead of guessing, with up to 10 candidates in `details.candidates`, each with its `id`, `name`, and, for students, `email`:

```json
{
  "error": {
    "code": "AMBIGUOUS_REFERENCE",
    "message": "2 students match \"Maria\". Ask the user which one they mean, then call again with its ID.",
    "retryable": false,
    "details": {
      "candidates": [
        { "id": "usr_01J8Z6", "name": "Maria Souza", "email": "maria.souza@example.com" },
        { "id": "usr_01J8Z7", "name": "Maria Lima", "email": "maria.lima@example.com" }
      ]
    }
  }
}
```

The assistant then asks you which one you mean and calls the tool again with its ID.

### Partial results

A composite tool reads several API operations. When an optional part cannot be read, for example because the administrator lacks the permission for it, the tool still answers: that part is `null`, and an entry in `warnings` explains what is missing, with the `error_code` and the API `request_id` when there is one. When a required part fails, the whole call fails with an error. Authorization and capacity errors always fail the whole call.

Lists that a composite tool reads in several pages have a `complete` field. `complete: false` means there was more data than the tool reads: use the corresponding list tool with filters to see the rest.

### `student_context`

Everything about one student, as the first step of a question about them.

| Input | Description |
|---|---|
| `student` | Required. A `usr_` ID, an e-mail address, or a name. |

| Output | Description |
|---|---|
| `student` | The profile: ID, name, e-mail, status, access, whether they are in the trash, external ID, creation date, and tags. |
| `enrollments` | All the student's enrollments, with status, origin, products, delivery, and end dates. |
| `products` | The student's effective access to each product: `has_access`, `denial_reason`, start and end dates, and sources. |
| `summary` | Enrollments by status, and how many products the student can and cannot access. |
| `warnings` | Parts that could not be read. |

Permissions: `users.read`. Enrollments and product access also need `enrollments.read`; without it, they come back `null` with a warning.

### `student_access_context`

Whether one student can access one product, and why. Use it for questions such as "why can't João access the Marketing course?" or "why doesn't Maria see module 3?".

| Input | Description |
|---|---|
| `student` | Required. A `usr_` ID, an e-mail address, or a name. |
| `product` | Required. A `prd_` ID or a name. |

| Output | Description |
|---|---|
| `student`, `product` | The student and the product, including their status and whether they are in the trash. |
| `access` | The API's verdict for this student and product: `has_access`, `denial_reason`, `starts_at`, `ends_at`, `sources`, and `overrides`. |
| `enrollments` | The student's enrollments that include this product. |
| `release` | The release calendar: how many modules and lessons are released, scheduled, hidden, or waiting for an exam, the next release date, and up to 20 entries that are not released yet. |
| `progress` | The student's progress in the product: percentage, completed and total lessons, and activity dates. |
| `diagnosis` | `can_access`, the `reasons` with a code, severity, message, and evidence, and the `suggested_actions`. |
| `warnings` | Parts that could not be read. |

The API decides whether the student has access: `diagnosis.can_access` is the API's `has_access`. The diagnosis explains that verdict with the reason codes below. Each reason has a severity: `blocking` explains why there is no access, `warning` points to something that needs attention, and `info` gives context. Each suggested action names the tool that fixes the problem and what it does, such as `users_enrollments_create` to grant a manual enrollment.

Permissions: `users.read` and `products.read` to find the student and the product, and `enrollments.read` for the access verdict. The enrollments and the release calendar also need `enrollments.read`, and progress needs `progress.read`; without them, those parts come back `null` with a warning.

#### Access reason codes

| Code | Meaning | Suggested action |
|---|---|---|
| `STUDENT_DELETED` | The student is in the trash. | `users_update` with `deleted` set to `false`. |
| `PRODUCT_DELETED` | The product is in the trash. | `products_update` with `deleted` set to `false`. |
| `PRODUCT_DRAFT` | The product is a draft and is not published to students. | `products_publications_create`. |
| `NO_ACCESS` | The student has no active source of access to the product. | `users_enrollments_create`. |
| `PRODUCT_HIDDEN` | The product is hidden for this student. | |
| `ACCESS_COMING_SOON` | The product is marked as coming soon and is not open yet. | |
| `ACCESS_NOT_STARTED` | Access starts at a future date. | `users_products_access_update` to adjust the student's access dates. |
| `ACCESS_ENDED` | Access ended at a past date. | `users_products_access_update` to adjust the student's access dates. |
| `EXAM_REQUIRED` | The student must pass a required exam first. | |
| `CONTENT_IN_EDIT` | The product content is being edited and is temporarily unavailable. | |
| `INSUFFICIENT_PROGRESS` | The student has not reached the progress that the release rules require. | |
| `NO_ENROLLMENT` | No enrollment includes the product. When the student has access anyway, it comes from another source and the severity is `info`. | `users_enrollments_create`. |
| `ENROLLMENT_REVOKED` | The enrollment for the product was revoked. | For a manual enrollment, `users_enrollments_update` to restore it. |
| `ENROLLMENT_SUSPENDED` | The enrollment for the product is suspended. | For a manual enrollment, `users_enrollments_update` to reactivate it. |
| `ENROLLMENT_EXPIRED` | The enrollment ended at its end date. | For a manual enrollment, `users_enrollments_update` to extend it. |
| `SUBSCRIPTION_ENDED` | The subscription behind the enrollment ended. Renewal happens on the payment gateway. | |
| `ENROLLMENT_ENDS_SOON` | An active enrollment for the product ends within 7 days. | |
| `ACCESS_OVERRIDE_ACTIVE` | The student has an individual access override for the product: a duration, an access schedule, or waived release rules. | |
| `CONTENT_PARTIALLY_RELEASED` | The student has access, but some modules or lessons are not released yet. | |

Enrollments that come from a sale or a subscription are managed by the payment gateway, so the suggested actions for revoked, suspended, and expired enrollments apply only to manual enrollments.

### `product_context`

An overview of a product, to understand it before answering questions about it or changing it.

| Input | Description |
|---|---|
| `product` | Required. A `prd_` ID or a name. |

| Output | Description |
|---|---|
| `product` | The product: ID, name, format, status, whether it is in the trash, showcase, module and lesson counts, external ID, and dates. |
| `content` | Module, lesson, and draft counts, and the top-level modules and lessons. |
| `deliveries` | The deliveries that grant the product, with their gateway, visibility, and enrollment and product counts. |
| `access_schedules` | The product's access schedules. |
| `warnings` | Parts that could not be read. |

Permissions: `products.read`. Deliveries also need `deliveries.read`, and access schedules need `access_schedules.read`; without them, those parts come back `null` with a warning.

### `product_structure`

The complete content tree of a product: every module and lesson, nested and in order, with its status and totals.

| Input | Description |
|---|---|
| `product` | Required. A `prd_` ID or a name. |
| `include_drafts` | Optional. Include draft modules and lessons. Defaults to `true`. |

| Output | Description |
|---|---|
| `product` | The product: ID, name, format, status, and module and lesson counts. |
| `tree` | The modules and lessons, each with `id`, `kind` (`module` or `lesson`), `name`, `status`, and `position`. Modules have `children` and `children_complete`. |
| `totals` | The number of modules, lessons, and drafts in the tree. |
| `complete` | `false` when part of the tree could not be read. |
| `warnings` | Parts that could not be read. |

The tree goes down four levels, and the tool expands up to 150 modules. A module that was not expanded has `children_complete: false`: read its content with `modules_content_list`.

Permissions: `products.read`, and `modules.read` to expand modules. Without `modules.read`, modules come back with `children_complete: false` and a warning.

### `instance_overview`

The account this connection works on. Use it to confirm the account before making changes, or for questions about the account's status and limits.

This tool takes no input.

| Output | Description |
|---|---|
| `connection` | The account ID (`instance_id`), the administrator the connection acts as (`administrator_id`), and the environment. |
| `account` | The account: ID, name, environment, billing and blocking status, student quota, replica and sandbox relationships, and creation date. |
| `usage` | API usage over the last 24 hours: requests, operations, and rate limits. |
| `warnings` | Parts that could not be read. |

Permissions: `account.read`. Usage also needs `usage.read`; without it, `usage` comes back `null` with a warning.

## Tools per operation

Every operation of the API v3 has a tool, generated from the API contract, except the four listed in [Operations without a tool](https://cademi.dev/mcp/tools.md#operations-without-a-tool). The tool name is the operation ID with dots replaced by underscores:

| Operation ID | Tool |
|---|---|
| `users.list` | `users_list` |
| `products.update` | `products_update` |
| `users.enrollments.create` | `users_enrollments_create` |

The tool title is the operation summary, and the description adds the operation's description, how to page, whether the tool changes or removes data, the body fields, and the permission it requires. Some descriptions point to a composite tool that answers the same question in one call. For the parameters and fields of each operation, see the [API reference](https://cademi.dev/api/reference.md).

### Input

| Field | Description |
|---|---|
| Path and query parameters | Top-level fields with the names the API uses, such as `user_id`, `limit`, and `cursor`. |
| `body` | The JSON request body, for operations that take one. |
| `if_match` | For operations that accept `If-Match`: the `revision` of the resource you read earlier. If the resource changed since then, the call fails with `CONFLICT`. |
| `idempotency_key` | For operations that accept `Idempotency-Key`. Optional: a new key is generated when you omit it. Reuse a key only to retry a call whose outcome was uncertain, so it is not applied twice. |

Fields outside the operation's schema are rejected.

### Output

| Operation returns | Tool returns |
|---|---|
| A list | `items` and `page`. Pass `page.next_cursor` as `cursor` to get the next page ([Pagination and filtering](https://cademi.dev/api/pagination-and-filtering.md)). |
| An object | The object. |
| No content | An empty object. |
| An asynchronous operation | The operation. Follow it with `operations_get` ([Asynchronous operations](https://cademi.dev/api/operations.md)). |

A list tool returns one page per call. Use the operation's filters to narrow the results instead of paging through a whole collection.

### Operations without a tool

The API release 3.4.7 has 395 operations. Four of them have no tool on purpose:

| Operation | Why | Instead |
|---|---|---|
| `credentials.create` | It returns a new credential secret, which would end up in the conversation. | Create credentials in the Cademí dashboard. |
| `credentials.secret_rotations.create` | It returns a new credential secret, for the same reason. | Rotate secrets in the Cademí dashboard. |
| `event_streams.events.get` | It is a continuous stream of events, not a request with a single response. | [Event streams](https://cademi.dev/api/event-streams.md), or [`cademi listen`](https://cademi.dev/cli/listen.md). |
| `openapi.get` | It returns the whole API contract, which is metadata about the API. Every operation is already a tool. | The [API reference](https://cademi.dev/api/reference.md). |

## Annotations

Every tool carries MCP annotations, so your client can tell reads from changes and ask for your approval before a change:

| Annotation | Set on |
|---|---|
| `readOnlyHint: true` | Tools that only read: the composite tools and every tool for a `GET` operation. |
| `destructiveHint: true` | Deletes, full replacements (`PUT`), and writes that remove, revoke, cancel, reset, suspend, or overwrite data. This includes `users_enrollments_update`, which can revoke an enrollment, and `operations_update`, which cancels an operation. |
| `idempotentHint: true` | Reads, updates, replacements, and deletes. Tools for `POST` operations are not idempotent. |
| `openWorldHint: true` | Writes that can send e-mails or notify external systems, such as the e-mail and webhook operations. |

The annotations describe the tool. The API still checks every call against the administrator's permissions ([Authorization and permissions](https://cademi.dev/mcp/authorization.md#approving-changes)).

Each tool also publishes metadata in `_meta`:

| Key | Value |
|---|---|
| `dev.cademi/tool_type` | `composite` or `primitive` (a tool per operation). |
| `dev.cademi/permissions` | The permissions the tool requires. |
| `dev.cademi/operation_id` | Tools per operation: the API operation ID. |
| `dev.cademi/http` | Tools per operation: the method and route of the operation. |
| `dev.cademi/conditional_permissions` | Tools per operation: permissions required only for some inputs, when there are any. |

## Results

A successful call returns the result as `structuredContent` and the same JSON as text. Composite tools declare an output schema.

When a result is larger than the response size limit, it is shortened and says so with `truncated: true` and a `truncation` object that explains what was omitted and how to get the rest. A failed call returns an error with a stable `code`. See [Errors and limits](https://cademi.dev/mcp/errors-and-limits.md).
