---
title: "List tools for one connection"
method: GET
path: "/connection/{id}/tools"
tags: ["Connections"]
---

# List tools for one connection

`GET /connection/{id}/tools`

## Request

- Base URL: `https://api.elaichi.ai`
- URL: `https://api.elaichi.ai/connection/{id}/tools`
- Auth: HTTP bearer

Lists what this authenticated account can run: the connector's tools, each flagged `restricted` and `restricted_by` for the caller rather than filtered out. This is where a partially restricted connection says so, since the connection row's own `restricted_by` asserts the whole connector is blocked. Contrast `GET /connector/{slug}/tools`, which is the catalog capability with no account behind it. A restricted connector answers 403. It resolves the same access as `GET /connection/{id}`: a connection the caller holds no grant on is `404`. `q` and `operation` are both applied before paging, and `operation_counts` describes the `q`-filtered set (never narrowed by `operation` itself), same as `GET /connector/{slug}/tools`. For a remote MCP connection ("bring your own") the rows are the tools this connection's own credentials listed, from per-connection discovery: `name`, `upstream_name`, `title`, the full `description` of this connection's definition, `status` (`active` or `disabled`, the connector-wide on/off), the `tier` (the server's label), `tier_source` (`server` or `default`), `operation` (the tier as `read`, `other` or `delete`) and `last_seen_at`, plus the same restriction flags. `q` and `status` are applied before paging. A caller who manages the connection may filter by either `status` and sees tools that are turned off; everyone else with access is shown `active` tools only, whatever `status` they send. When the connection's connector is gone from the catalog (Elaichi unpublished or deleted it) the answer is `409 connector_unavailable` with a message a person can read; the connection itself is kept.

## Path parameters

- `id` string, required

## Query parameters

- `limit` integer
- `cursor` string
- `q` string
- `operation` string

## Headers

- `X-Organization-Id` string

## Response `200`

OK

- object
  - `result` object[], required
    - `name` string: Exact tool name — what a toolbox entry's `tool_name` must contain.
    - `description` string
    - `resource` string
    - `method` string
    - `input_schema` object: JSON Schema for the tool arguments.
    - `title` string: The upstream server's human title for the tool. Present only on a remote MCP tool that has one.
    - `tier` 'read' | 'write' | 'destructive': Always present. How the approval gate and the MCP scope ladder classify this tool, so a badge shown to a person always matches the gate. For a remote MCP tool it is derived from the server's annotations (unannotated means `destructive`) and follows the server up or down on every refresh. For a platform catalog tool whose method documents MCP annotations, those decide the tier (an HTTP DELETE is always `destructive`); any other catalog tool, including every custom connector and fork tool, takes it from its method and HTTP verb. Never infer a remote MCP tool from it: read `kind`.
    - `kind` 'catalog' | 'remote_mcp': `remote_mcp` for a tool from a remote MCP connector (its `resource` is the constant `mcp`, its `method` the upstream name, and `title` may be set), `catalog` for every other tool.
    - `tier_source` 'server' | 'default': Why a remote MCP tool's `tier` is what it is: `server` (the MCP server's own annotations decided it) or `default` (the server labeled the tool neither way, so the MCP safe default `destructive` applies). Lets a client say "Not labeled" rather than show a tier nobody chose. Present only on a remote MCP tool.
    - `restricted` boolean: True when the caller's restrictions block THIS tool. Blocked tools are returned flagged, never omitted — a shorter list is no signal, because nobody knows the length it should have been. Presence is not permission: execution still refuses it. The connector-level 403 is a separate question and is unchanged.
    - `restricted_by` 'role' | 'user' | 'null', nullable: Which precedence layer's rule blocks this tool, null when none does. Same field, union and meaning as on connector and connection rows: adds *which* to `restricted`'s *whether* and nothing else — no rule id, author, reason or coverage. `restricted === (restricted_by !== null)` always.
    - `restricted_scope` 'connector' | 'tool' | 'null', nullable: `"connector"` when the tool is refused because its WHOLE connector is restricted for the caller, `"tool"` for a rule about the tool itself, null exactly when `restricted_by` is. Decides which ask can succeed: a tool request on a connector restricted whole is refused (`409 tool_request_connector_blocked`), so ask for the connector. On this listing it is only ever `"tool"` when set, since a connector restricted whole 403s the route; toolbox entries carry the same field and can say `"connector"`.
    - `operation` 'read' | 'create' | 'update' | 'delete' | 'other': The CRUD bucket this tool falls into, computed from its resolved HTTP verb. Filter with `?operation=`.
  - `next_cursor` string, nullable, required
  - `prev_cursor` string, nullable, required
  - `operation_counts` object, required: How many tools of each CRUD bucket the `q` filter alone leaves — never narrowed further by `operation` itself, so the count beside an unselected filter chip stays honest. Repeated on every page.
    - `read` integer, required
    - `create` integer, required
    - `update` integer, required
    - `delete` integer, required
    - `other` integer, required

## Other responses

- `400`: Bad request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `429`: Rate limited

---

[API](https://skmtc.dev/elaichi/apis/elaichi-api.md) · [All operations](https://skmtc.dev/elaichi/apis/elaichi-api/llms.txt) · [OpenAPI document](https://skmtc.dev/elaichi/apis/elaichi-api/revisions/b22cfb7b6d15?raw)
