Your API as agent tools
Register your own OpenAPI spec — or a code bundle — as a private connector, and your product's actions become first-class agent tools beside the catalog.
Scenario: Acme's assistant shouldn't only act on other products — the highest-value tools are Acme's own: create_ticket, escalate, issue_refund. Registering Acme's API as a private connector makes those actions identical citizens to Gmail or HubSpot: same execution pipeline, same policies, same traces, same MCP serving.
Private connectors are visible only to your workspace. Two shapes: an OpenAPI spec (your existing API, zero new code) or a code bundle (logic that isn't one HTTP call).
From an OpenAPI spec
const connector = await protobox.connectors.registerOpenApi({
slug: 'acme',
spec: 'https://api.acme.com/openapi.json', // inline OpenAPI 3.x object also accepted
name: 'Acme',
// Don't tool-ify all 120 operations — pick the agent-safe ones:
operations: { include: ['createTicket', 'searchTickets', 'escalateTicket'] },
// Relay caller context (your conversation/user ids) as a header on each call:
forwardContext: true,
});Each included operation becomes an action named ACME_<OPERATION>; auth is auto-mapped from the spec's securitySchemes (override with auth if needed).
Authenticate calls to your API
Your API needs a credential too. For a service-level token (one credential for the whole workspace):
await protobox.authConfigs.create('acme', {
mode: 'service',
credentials: { token: process.env.ACME_INTERNAL_API_TOKEN!, headerName: 'X-Acme-Key' },
});mode: 'service' is principal-level infrastructure auth — no per-user OAuth dance, the platform presents the token on every call. Per-user auth modes work here exactly as for catalog apps.
Keep it in sync
When your API changes, diff-sync instead of re-registering:
const diff = await protobox.connectors.syncOpenApi('acme', { spec: newSpec });
// Arrays carry the spec's operationIds, not the prefixed action names:
// { added: ['closeTicket'], removed: [], changed: ['createTicket'] }Run it from CI on API releases and alert on removed/changed — those can break live agents.
From a code bundle
For tools that aren't one endpoint call — aggregate three internal services, transform data, enforce invariants.
Your entry point exports one async function, and it receives the tool's arguments object directly — not wrapped in an envelope:
// index.js — the entry point named by `entryPoint`
module.exports = async function run(args) {
// args is exactly what the caller passed as `arguments`
return { period: args.period, rows: 3 };
};invokeTest and live agent execution hand the module the same object, so what you smoke-test is what runs in production.
const result = await protobox.connectors.registerCode({
slug: 'acme-reports',
name: 'Acme reports',
runtime: 'node', // or 'python'
entryPoint: 'index.js',
files: [
{ path: 'index.js', content: reportToolSource },
],
requiredSecrets: ['ACME_DB_URL'], // resolved per-workspace at run time
});Bundles run in a managed sandbox. Secrets named in requiredSecrets are injected from the workspace vault — set them once:
await protobox.secrets.set({
principalId: 'acme', // shape-required; the workspace itself is resolved from your API key
key: 'ACME_DB_URL',
value: process.env.ACME_DB_URL!,
});Secrets can also be actor-scoped (actorId: 'user_123') so each end-user's run resolves their own value — the same two-level model as connections.
Test before agents touch it
const test = await protobox.connectors.invokeTest('acme-reports', {
arguments: { period: 'last_7_days' },
});
console.log(test.success, test.latencyMs, test.logs);invokeTest is a management-API harness — full sandbox logs, timing, and exit code, not a billed execution.
Use it everywhere
The moment it's registered, your connector is just another connector:
// In an agent conversation:
const acme = user.forLLM('anthropic', { integrationId: 'acme' });
// In a curated toolset (mixed with catalog tools), served over MCP:
const toolset = await protobox.toolsets.create({
name: 'Support agent',
tools: [/* acme tool ids + gmail tool ids */],
});
// From a background job:
await protobox.actions.execute('ACME_CREATETICKET', {
actorId: 'user_123',
arguments: { subject: 'Renewal follow-up', priority: 'high' },
});Retire it cleanly with protobox.connectors.setRegistrationStatus('acme', 'disabled') (reversible) or protobox.connectors.unregister('acme') (gone).
On the roadmap: registering an external MCP server you already run as a private connector — same curation, policies, and serving over its tools. Today's private connectors are OpenAPI and code bundles.
Production notes
- Curate with
operations.include. An agent with your full admin API is an incident waiting to happen. Start with 3–5 read-mostly operations; add writes behind approvals. forwardContext: truerelays execution context verbatim as anX-Protobox-Contextheader — your API can log or scope by your own conversation/user ids without Protobox ever parsing them.- Bundle limits: ≤20 files, ≤200KB each, ≤1MB total, one entry point.
Related
- Tools — the tool model these register into
- Publish an MCP server — expose your connector to your customers' AI clients
Agent tool-calling
Hand a connected user's tools to OpenAI, Anthropic, the Vercel AI SDK, LangChain, or Google GenAI — and run the model's tool-calls server-side with that user's credentials.
Human-in-the-loop
Gate risky tools behind human sign-off: a toolset policy pauses the call, your product shows the approval, and approve() replays it server-side.