Skip to content

Tool Catalog

Copy page

A deployed assistant can do more than generate text. Divinci’s tool surface spans three independent subsystems, each with its own config and its own gate, and all three are off by default:

SubsystemWhat it doesConfigured viaGate
Skill/tool loop (RP1)In-chat tools the model calls during a send (search, fetch, RAG, email, SMS, calendar)Release.skillConfigskillConfig.enabled
MCP toolsThe platform’s full surface exposed to external MCP/agent clientsRelease.mcpConfigmcpConfig.enabled
Site ControlNavigate / submit forms on the embedded customer siteRelease.siteControlsiteControl.enabled (THE WALL)

What it is. When a chat turn shows tool intent, the send path hands the message to a tool-calling model that loops call-model → execute-tool → feed-result until the model answers tool-free or a safety net trips. Use it when you want an in-chat assistant that actually does things — searches the web, fetches a URL, retrieves from RAG, emails or texts the person it is talking to, or books a calendar appointment.

Tools reach the loop from three places, all merged per turn:

  • Catalog skills — Divinci-authored integrations, attached to the workspace as a WhitelabelSkill instance and then selected on the release.
  • MCP skills — external MCP servers you connect by OAuth or a static API key; each server’s tools become individually selectable.
  • User skills — instances owned by the person chatting, loaded from their own account at turn time rather than from the release.

Seven integrations are registered today. mutates is the property that decides whether the loop stops for confirmation before running an action.

Skill idActionsMutatesNotes
web-searchwebSearch
scrape-urlfetchUrl
rag-searchragSearchBacked by the release’s resolved RAG vector
google-calendargetAvailabilities
bookAppointment, cancelAppointmentConfirmation required
email-releasesendEmailSelf-directed — may only reach the verified chatting user
email-usersendEmailUser-owned only. May address the whole workspace org
sms-releasesendSmsSelf-directed

Image, video and diagram generation exist in the tree but are not registered in the catalog — each still needs owner-facing provider/key configuration before it can be enabled. Treat them as unavailable rather than opt-in.

One gate: skillConfig.enabled. There is no server env var any more.

await client.releases.updateInWorkspace(workspaceId, releaseId, {
skillConfig: {
enabled: true,
maxToolIterations: 5,
// keyed by WhitelabelSkill INSTANCE id — create the instance first
catalogSkills: { "6a67afca5599956295482dfc": ["sendEmail"] },
mcpSkills: { "6a72d8ae5c76b78e24589e85": [] }, // [] = all of that server's tools
toolCallingAssistant: { id: "@cf/moonshotai/kimi-k2.7-code" },
},
});

Or from the CLI:

Terminal window
divinci release update <releaseId> --skills-enabled \
--catalog-skills '{"6a67afca5599956295482dfc":["sendEmail"]}'
FieldTypeDefaultNotes
enabledbooleanfalseThe only gate. False = the loop never runs, whatever is attached
catalogSkillsRecord<instanceId, string[]>{}[] as the value = all of that skill’s actions
mcpSkillsRecord<serverId, string[]>{}[] as the value = all of that server’s active tools
toolCallingAssistant{ id }the release’s own assistantMust implement native tool calling
fallbackToolCallingAssistants{ id }[]Ordered retry chain; each must also be tool-capable
maxToolIterationsnumber ≥ 15Tool-call rounds allowed in one turn
businessDisplayNamestringSurfaced to the model as who its skills act for

skillConfig merges shallowly over the stored value, so sending only catalogSkills leaves enabled and toolCallingAssistant intact.

Any action that changes external state carries mutates: true, and the loop stops before executing it to ask the chat user. A confirmation is only accepted as an HMAC-signed token the server itself issued for that transcript, so a client cannot fabricate one — this closes a confirmation-bypass hole that a plain “confirmed: true” flag would leave open.

The one documented exception is selfDirected: an action whose target is resolved server-side from the current user’s verified identity and can never be model-chosen. Its blast radius is the person who asked, so it does not force a confirmation stop — which matters on surfaces that have no way to confirm, a phone call being the obvious one, where the loop would otherwise stall at pending-confirmation and the action would silently never run. mutates stays true, so an owner can still opt back into confirmation per instance.

BoundValue
Tool-call rounds per turnmaxToolIterations, default 5
Per-tool-result size4000 chars
Confirmation for mutating toolsRequired unless selfDirected
Tool-intent signalAlways recomputed server-side
  • Instance ids, not catalog ids. catalogSkills is keyed by the WhitelabelSkill instance id you get after attaching a skill to the workspace — not by the catalog id (web-search, email-release, …). The CLI rejects a value that looks like a catalog id; the API rejects an instance that is not ready or belongs to another workspace. Creating an instance and connecting it is covered in Provider Keys (BYOK) & Skills.
  • Enabling the loop without a tool-capable model is rejected. If you don’t name a toolCallingAssistant, it defaults to the release’s own assistant, which must then support native tool calling or the save fails.
  • The loop never fails a message. Any error inside it — or a turn that simply doesn’t route — falls through to normal generation. A broken skill degrades the answer; it does not 500 the chat.
  • The client’s tool-intent signal is never trusted. It is always recomputed server-side, so a crafted request cannot force routing or name a tool.
  • A handoff outranks the loop. Routing is sequenced: cross-release handoff first, then the tool loop, then normal generation. A turn handed to another release makes its own tool decisions and does not carry this one’s.
  • Enabling the loop is what makes a skill real. Attaching skill instances while enabled is false leaves the assistant able to describe actions it cannot perform — the failure mode is a confident claim, not an error.

What it is. The MCP server (workers/mcp-server) exposes ~60+ named tools across ~25 categories — chat, RAG, config, fine-tune, QA, analytics, terms, trust, and more — to external MCP/agent clients. Use mcpConfig when you want to expose some of that surface to an MCP client rather than to the in-chat model.

Terminal window
# POST, not PATCH — there is no PATCH route on releases.
# /release/$RELEASE updates a DRAFT; a published release uses .../update
curl -X POST https://api.stage.divinci.app/white-label/$WL/release/$RELEASE \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"mcpConfig":{
"enabled":true,
"exposedTools":["send_message","search_knowledge","get_transcript"],
"allowAnonymousMcp":true,
"maxSpendPerTokenCents":500,
"mcpRateLimit":{"requestsPerMinute":30,"requestsPerDay":2000}
}}'
FieldTypeDefaultNotes
enabledbooleanfalseThe MCP gate
exposedToolsstring[]empty = all release toolsUnknown names are rejected by the API
allowedScopesstring[]Restricts callable scopes
mcpRateLimit.requestsPerMinutenumber60Per-minute cap
mcpRateLimit.requestsPerDaynumber10000Per-day cap
allowAnonymousMcpbooleanfalseRequires a positive maxSpendPerTokenCents
maxSpendPerTokenCentscents1000 ($10)Per-token spend cap
  • Unknown exposedTools are rejected. Listing a tool name the server doesn’t know fails validation (it would otherwise expose nothing).
  • Anonymous access needs a spend cap. allowAnonymousMcp: true requires a positive maxSpendPerTokenCents.

What it is. The crawler builds a SiteManifest of the embedded customer site; Site Control turns that map into executable tools — a navigate_site action plus per-form submit actions. Use it when you want the assistant to move around the embedded site (and, opt-in, fill and submit forms with runtime confirmation).

Terminal window
# Via the SDK:
# await client.releases.updateInWorkspace(wl, release, {
# siteControl: { enabled: true, allowedCategories: ["navigation"] },
# });
# Or over the API — note POST, not PATCH:
curl -X POST https://api.stage.divinci.app/white-label/$WL/release/$RELEASE \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"siteControl":{"enabled":true,"allowedCategories":["navigation"]}}'
# Add form submission (each submit action is confirmation-gated, always):
# -d '{"siteControl":{"enabled":true,"allowedCategories":["navigation","mutation"]}}'
FieldTypeDefaultNotes
enabledbooleanfalseTHE WALL gate
allowedCategories"navigation" | "query" | "mutation" | "utility"[]["navigation"]Which action categories are derived
allowListstring[]Strictly validated
blockListstring[]Strictly validated

Manifest-derived limits: navigation route enum capped at 60, max 20 form actions, action name length 48.

  • Form submissions always confirm. Site Control mutation / submit actions carry requiresConfirmation: true, which config cannot disable.
  • Sensitive fields are stripped. Password / hidden inputs and any name matching pass/pwd/card/cvv/ssn/secret/token/otp/pin/account-number/routing never become fillable params.
  • Cross-origin hrefs are dropped from navigation actions.
import { deriveReleaseSiteActions } from "@divinci-ai/models";
// Site Control: derived actions ([] unless siteControl.enabled)
const siteActions = deriveReleaseSiteActions(release);

For the skill loop there is no equivalent pure selector — which tools a release advertises is resolved per turn, because it merges the release’s catalogSkills and mcpSkills with the chatting user’s own skill instances and with live MCP tool discovery. Read skillConfig off the release to see what the release contributes; the rest only exists in the context of a specific turn and user.