Tools

A tool is a discrete capability an agent can invoke during a run: "search memory", "send a Discord message", "call a custom HTTP endpoint", "run a sandboxed script". The Catentio runtime exposes a registry of built-in tools; the /v1/tools API lets you list them, inspect what each one does, and (for custom tools) create / update / delete your own.

The tool object

List row:

{
  "slug": "memory_search",
  "description": "Semantic search across the workspace's RAG store.",
  "module": "app.tools.memory.search",
  "category": "memory",
  "sensitive": false,
  "param_names": ["query", "limit"],
  "param_count": 2,
  "is_builtin": true,
  "used_by": 6
}

A custom (DB-backed) row additionally carries kind, shape, access, and (list-only) owner_customer_id/version:

{
  "slug": "my_internal_search",
  "description": "Hit our internal docs search endpoint.",
  "module": "(db)",
  "category": "custom",
  "sensitive": false,
  "param_names": ["q"],
  "param_count": 1,
  "is_builtin": false,
  "kind": "webhook",
  "shape": "api",
  "access": "both",
  "owner_customer_id": "internal",
  "version": "1",
  "used_by": 0
}
Field Type Notes
slug string Unique tool handle.
description string What the tool does. There is no separate display name field — slug + description is the whole identity.
module string Python module path for built-ins; "(db)" for DB-backed custom tools. Redacted to "" in public-visibility mode for built-ins.
category string Derived from the module path for built-ins (e.g. app.tools.workspace.docxworkspace); always "custom" for DB-backed tools.
sensitive bool The real name for what other resources call a "dangerous" flag — true for a static denylist of slugs plus any tool that self-reports sensitive=True, and true-by-default for custom tools of kind script/command/container/miniapp.
param_names / param_count array / int Top-level property names from the tool's JSON Schema.
is_builtin bool false for anything created through POST /v1/tools.
kind enum Custom tools only. One of stub (metadata-only placeholder), webhook (runtime POSTs params to body.url), script (runs body.script in a sandboxed subprocess), command (installed CLI binary), container (sandboxed container image), miniapp (operator-authored service). Not http/function — those names aren't part of the shipped model.
shape enum Custom tools only. The operator-facing creation flow that produced the tool: cli, api, or miniapp.
access enum Custom tools only. Who may invoke it: agent (MCP surface only), human (portal run panel only, hidden from agents), both (default).
used_by int How many skills declare this tool via a uses_tool graph edge.

GET /v1/tools/{slug} detail adds id (the tool's graph-memory node id, for /v1/memory/entries/{id}/links), params_schema (the full JSON Schema — not a field named schema on the public shape), and recent_invocations (up to 50 recent tool_call events: {id, ts, run_id, agent, transport, params_preview}). For a custom tool, detail also returns the edit-form fields body (the kind-specific config — {url, method?, headers?} for webhook, {script, timeout_s?} for script), integration, schema (same content as params_schema, under the name the edit form expects), and version.

There is no name, bound_agents, handler, is_dangerous, created_at, or updated_at field, and no per-agent "tool budget." Older references to those are stale. The real dangerous-flag name is sensitive; there is no handler.kind of http/function, no $VARIABLE header templating (custom-tool headers use {param}-style Python str.format_map substitution, not a dollar-sign syntax); and tools aren't capped per-agent — the only cap is the workspace-wide custom_tools tier limit (see Errors below).

Endpoints

List tools

GET /v1/tools

Returns the full tool registry, redacted. Powers Dashboard → Tools. Meta: {"total", "builtin", "custom"}.

const { data } = await catentio.tools.list();
tools = catentio.tools.list()
curl 'https://catent.io/api/v1/cp/v1/tools' \
  -H "Cookie: catentio_session=<session cookie set at login>"

Retrieve a tool

GET /v1/tools/{slug}
const tool = await catentio.tools.get('memory_search');
curl 'https://catent.io/api/v1/cp/v1/tools/memory_search' \
  -H "Cookie: catentio_session=<session cookie set at login>"

Errors: 404 if the slug doesn't exist as either a registered tool or a DB row.

Create a custom tool

POST /v1/tools

Mint a custom tool. Body:

{
  "slug": "my_internal_search",
  "description": "Hit our internal docs search endpoint.",
  "kind": "webhook",
  "schema": { "type": "object", "properties": { "q": {"type":"string"} }, "required": ["q"] },
  "body": { "url": "https://internal.example.com/search", "method": "POST" }
}

A tier cap on custom_tools applies. Requires a scheduler/runtime restart before the tool becomes dispatchable to agents.

Update a tool

PATCH /v1/tools/{slug}

Partial update on custom tools. Built-in tools refuse with 400 — their schemas are owned by the runtime release.

Delete a tool

DELETE /v1/tools/{slug}

Hard-deletes a custom tool. Built-in tools refuse with 400.

Errors

Status When
400 Slug missing/too long; malformed schema (not a JSON object); attempted edit/delete of a builtin tool.
403 plan_limit_exceeded — the workspace hit its custom_tools tier cap on create.
404 Tool slug doesn't exist.
409 Slug collision on create.
502 CP couldn't reach the runtime.

There is no 422 invalid_schema, 409 builtin_tool, or 422 tool_budget_exceeded on this resource — the real codes are the ones above.

Events

Tool CRUD isn't currently emitted as outbox events — reserved for a later release. Per-invocation activity shows up as tool_call events on the parent run (see Runs); there is no tool_call_pending_approval event or in-line approval-modal workflow for sensitive tools today — treat sensitive as a UX/listing signal, not an enforcement gate.

Next

  • Agents — what binds a tool's capability to a persona.
  • Skills — playbooks; a higher-level abstraction than a single tool.
  • Integrations — where a custom tool's headers can resolve a credential from.