Join the early access program
Browse documentation

Skill SDK Reference

Build a Botonom agent skill: a small MCP microservice that gives your agents new tools. Use @botonom/skill-sdk (0.3.0), or register an existing MCP server with no code.

9 min read0 viewsUpdated 2026-09-05
JuliaGuide Assistant

Overview

A skill is a capability you give a Botonom agent. At runtime it is a set of MCP tools (Model Context Protocol) the agent may call during a conversation, plus optional inbound events it reacts to. A skill is a small, self-contained network service: you declare the tools, permissions and handlers; Botonom handles routing, authentication, tenant/role context and delivery.

Two ways to build one:

  • Path A - build on the SDK. You own the logic. Write the tool handlers (wrap a database, a third-party API, your own product) and ship the skill as its own service. @botonom/skill-sdk gives you everything except the handlers.
  • Path B - register an existing MCP server. A standards-compliant MCP server already exists; point Botonom at its URL. No SDK, no code.
The Skill SDK is version 0.3.0. Contact us for the SDK repository, the OpenAPI contract, and the full Skill Development Kit.

Quick start (Path A)

mkdir botonom-skill-warehouse && cd botonom-skill-warehouse
npm init -y
npm install @botonom/skill-sdk

Create skill.js:

import { defineSkill, startSkill, z } from "@botonom/skill-sdk";

const skill = defineSkill({
  code: "warehouse",
  version: "1.0.0",
  defaultLocale: "en",
  locales: {
    en: { "location.found": "Item {sku} is stored at {location}." },
    tr: { "location.found": "{sku} kodlu ürün {location} konumunda bulunmaktadır." }
  },
  tools: {
    location: {
      description: "Find where a stock item is stored.",
      input: { sku: z.string() },
      handler: async ({ sku }, ctx) => ({
        sku,
        location: "A-12-3",
        summary: ctx.t("location.found", { sku, location: "A-12-3" })
      }),
    },
  },
});

startSkill(skill, { port: 3620 });

The service now serves POST /mcp, GET /manifest, POST /events, POST /test and GET /health. Register it in Botonom, install it on an agent, grant the capability, and the agent can call warehouse__location in a real chat.

The contract

The manifest is the contract. Any service that serves the same GET /manifest and POST /mcp shape is a valid Botonom skill, in any language - the Node SDK is just the reference implementation.

  • Each skill is its own service: one process, one port, one bearer. The provider reaches it over HTTP and speaks MCP (POST /mcp).
  • A tool action inside skill code is exposed to the model as code__action.
  • The provider passes a trusted per-call context (ctx) to your handler. On the installable hop those ids are UUIDs (never sequential auto-increment ids) plus X-Botonom-Turn-Token, a short-lived (120s) JWT. Trust only ctx. Call api.botonom with botonomApi(ctx, "skills/<code>/<method>", params). Do not send bot, company or user sequential ids in tool arguments.
import { botonomApi } from "@botonom/skill-sdk";
const data = await botonomApi(ctx, "skills/products/catalog_search", { q: "bolt" });

The HTTP contract is GET /health, GET /manifest, bearer-guarded POST /mcp and POST /events. Identity headers on this hop are UUIDs. Sequential auto-increment ids are dropped.

The Botonom internal key is never sent to a third-party skill. Empty SKILL_BEARER is development only; production requires a bearer. Do not log ctx.turnToken or decrypted config secrets.

Multi-language (i18n) & Locales

Botonom agents operate in 40+ languages. In @botonom/skill-sdk 0.3.0, skills declare their supported languages using Shopify App Store / VS Code style locales:

  • Declaration: In defineSkill, specify defaultLocale (e.g. "en") and either an inline locales: { en: {...}, tr: {...} } map or a disk path localesDir: path.join(__dirname, "locales").
  • Dynamic Context: In tool handlers, ctx.language carries the normalized conversation language (e.g. "tr", "en", "de"), forwarded via the X-Botonom-Language header.
  • Translator (ctx.t): Translate messages with ctx.t(key, vars?, fallback?). It uses a 4-tier transparent fallback hierarchy (target language -> default locale -> fallback param -> key name), ensuring missing translations never crash a tool.
  • Interpolation: Supports {var} and {{var}} interpolation and nested dot notation (errors.not_found).

Local unit testing with @botonom/skill-sdk/test

You can test your tools and RBAC handlers directly without starting a background HTTP server or mocking the live Botonom control plane:

import { test } from "node:test";
import assert from "node:assert/strict";
import { createMockContext, executeTool } from "@botonom/skill-sdk/test";
import skill from "./skill.js";

test("location tool returns stock", async () => {
  const result = await executeTool(skill, "location", { sku: "SKU-99" }, {
    roles: ["warehouse_viewer"],
    accountId: "acc_demo_123"
  });

  assert.equal(result.isError, undefined);
  assert.equal(result.location, "A-12-3");
});
  • createMockContext(overrides): Returns a fully initialized mock context with pre-bound ctx.t, mock callBotonomApi, and test role identifiers.
  • executeTool(skill, toolName, input, contextOverrides): Validates the Zod schema, checks permissions, and executes the handler directly.

Zero-Trust & SSRF protection

Botonom enforces strict multi-tenant isolation and network boundaries:

  • Zero-Trust Turn Token: Invocations carry short-lived (120s) HMAC-SHA256 tokens (X-Botonom-Turn-Token). The platform API strictly validates that the caller matches the bound account UUID (skillTurn.account), eliminating IDOR attacks. Administrative routes require the master system key and reject turn tokens outright.
  • Outgoing SSRF Protection: The provider blocks all attempts to connect to cloud instance metadata (169.254.169.254), private RFC1918 IPv4/IPv6 networks, or URLs with embedded credentials.
  • HTTPS in Production: External skill endpoints registered in production MUST be served over HTTPS.
  • Timeouts & Payload Limits: MCP tool requests timeout after 15 seconds by default, and response bodies are capped at 5MB to prevent memory exhaustion.

Permissions

Permissions are enforced inside the skill, at the data layer, never in the prompt. The source of truth is the capability, not a role name - so your skill never hardcodes a tenant's roles.

Botonom's built-in roles are owner, admin, member (and public for anonymous visitors). Everything else is a role the company defines in its dashboard, with names of its choosing.

  • Each tool has a capability, code.action (e.g. warehouse.location). In Company > Roles & Access each company grants that capability to whichever of its own roles it wants. Different companies with different role names all work, because the match is on the capability.
  • At call time the control plane resolves the caller's roles to their allowed capabilities and hands those to your skill; the SDK checks the capability (deny-by-default). A tool stays invisible until its capability is granted.
  • You may optionally add roles: [...] to a tool as a standalone fallback (used only when a skill runs on its own, before grants propagate). In production the panel's capability grants override it, so most skills omit it.
  • For a public-facing agent (embedded widget) grant only the safe capabilities to the anonymous public role.

Path B - register an existing MCP server

If you already run a standards-compliant MCP server you do not need the SDK at all. Point Botonom at its URL; Botonom reads its manifest, registers the tools, and enforces permissions the same way. This is the fastest path when a capability already exists as an MCP service.

Try it live

Test the endpoints from this article in the API Playground.

Open Playground
sdkskillmcptoolsskill-sdkmanifestrbacturn-tokeni18ntesting

Start hiring in three steps

No interviews, no onboarding calls. Just browse, hire, and let them work.

01

Browse Employees

Explore our AI talent pool. Filter by role, department, or industry to find the perfect candidate for your team.

02

Hire & Onboard

Select your AI employees and equip them with skills. Pick the plan that fits your headcount, no config needed.

03

Watch Them Work

Your agents handle tasks 24/7. Monitor performance, adjust skills, and scale your workforce anytime.

No credit card requiredSet up in 5 minutesCancel anytime