A lone tree on a small island, mirrored in a still lake

Tool Sets

Rooted in
your stack.

Connect the systems your business runs on. Choose what agents can do, what needs approval, and what stays in your hands.

Connect an MCP server and discover its tools. Start from a ready-made integration, or bring your own server and decide which tools are available.

Tool
set

Search

Read

Update

Create

Turn an OpenAPI specification into tools. Point to a URL or upload JSON or YAML, then filter the operations your agent can use.

OpenAPI connection

Specification
orders.openapi.yaml
GET /orders
listOrders
GET /orders/{id}
getOrder
POST /orders
Filtered out

Define HTTP tools with a shared base URL, headers, and templated paths or request bodies. Give the model a simple schema; shape the request yourself.

HTTP tool / createTicket

Request
POST /tickets
Model fills in
{ subject, description }
Request body
{ "subject": "{{ arguments.subject }}" }
Authorization
Bearer {{ secrets.API_TOKEN }}

Define Bare tools your application answers. Read the current page, display a card, or ask a visitor a question. The objective waits for your result.

Auto mode / Approve calls

Applies to
createTicket
Question
Did the customer ask for a ticket?
Threshold
Score above 0.80
When denied
Skip the call, tell the agent why

Human
in the loop.

Tool approvals work out of the box.
Get a webhook when one is waiting.

A great tree on a floating island, its roots spilling over the edge
import Cadenya from '@cadenya/cadenya';

const cadenya = new Cadenya();

// On objective_event.tool_approval_requested
await cadenya.objectives.approveToolCall(
  objectiveId,
  toolCallId,
);

Make any
API
an agent

Connect an MCP server

await cadenya.toolSets.create({
  metadata: { name: "Support" },
  spec: { adapter: { type: "mcp",
    mcp: { url: "https://api.example.com/mcp" }
  } }
});

Import only what you need

await cadenya.toolSets.create({
  metadata: { name: "Orders" },
  spec: { adapter: { type: "openapi", openapi: {
    type: "url",
    url: "https://api.example.com/orders.openapi.yaml",
    includeTools: {
      operator: "OPERATOR_OR",
      filters: ["listOrders", "getOrder"].map((exact) => ({
        attribute: "ATTRIBUTE_TITLE",
        matcher: { type: "exact", exact },
      })),
    },
  } } },
});

Use overlays to remove parameters, set fixed values, or pin them to trusted objective context. Hide customer IDs from the model while every call gets the right value.

Overlay / Customer context

Applies to
listOrders, getOrder
Parameter path
customerId
Action
Pin → customerId
When not pinned
Fail the call

Require approval for every tool, or only matching tools. Add Auto mode questions and confidence thresholds to an overlay for more specific approval decisions.

Approval policy

Read tools
No approval required
Matching tools
createTicket
Approval
Required
Auto mode question
Is this change requested by the user?

Transform a tool’s text result with a Liquid template before the model sees it. Keep the fields that matter and retain the raw response in the debug log.

Result transform

Raw response
Orders + metadata + pagination
Liquid template
{{ result.json.orders | json }}
Model receives
[{ "id": "1234", "status": "shipped" }]
On transform error
Keep raw result or fail

Discover MCP tools when each objective starts, using its resolved secrets. Keep credentials scoped to the tool set and choose whether discovery failures stop the objective.

Just-in-time discovery

Load tools
At objective start
Headers
Bearer {{ secrets.API_TOKEN }}
Secrets
Tool set overrides workspace
On discovery failure
Fail objective · optional

Know what
your tools are doing.

01 / Analytics

See what gets used.

Track tool calls over time and see which tools do the most work. Follow usage for a whole set or inspect a single tool.

02 / Sync events

Keep up with change.

See when discovery starts, completes, or fails. MCP and URL-based OpenAPI sources can sync ahead of the next objective.

03 / Debugger

Get to the source.

Inspect recent tool-call diagnostics. Result transforms keep the raw response in the debug log, so the original is still there.

A few things
to know.

Can I connect an API without an MCP server?

Yes. Import an OpenAPI specification from a URL or file, or define HTTP tools with templated requests.

Where do Bare tools run?

Your application supplies their results. Objectives wait for that content, unless a tool has an immediate fixed result.

Can I assign just one tool?

Yes. Assign individual tools or an entire tool set to an agent variation. The Used By views show where each is assigned.

A tree on a floating cliff, roots hanging from the rock

Put your tools
to work.

Connect your stack. Set the boundaries. Let agents get on with it.