Custom tools
Package an API as governed agent tools.
Capability packages are registry-owned integration artifacts. They declare actions, schemas, secrets, runtime code, and policy hints, then expose agent-facing tools named pkg:<packageId>:<action>.
What a Package Provides
Use a package when the valuable tool is a private API or team-owned integration that should feel like one governed capability, not a pile of endpoint credentials. Start with one action, one declared secret, and one observable result.
Registry-owned
Packages are stored as workspace registry data, not app-bundled Node imports.
API-key auth
Declare package-local secret names in the manifest and configure values after creation.
Sandboxed runtime
JavaScript runs in the Wasm/QuickJS sandbox. Wasm artifacts run as WASI command modules.
Hosted UI
Attach static uiAssets outside the manifest. Published bundles render from isolated package UI origins.
Policy-gated tools
Published actions expose agent-facing tool names such as pkg:<packageId>:<action>; canonical grants use the package capability definition id.
Minimal Manifest
A manifest is the package contract: what the tool is called, which secret names it may read, what runtime file runs, and what input shape the agent must provide. Keep the first package boring: one read action with one small schema.
{
"packageId": "linear-lite",
"name": "Linear Lite",
"description": "Read Linear viewer data through a package-local API key.",
"version": "0.1.0",
"auth": {
"type": "api_key",
"secrets": [{ "name": "linear_api_key", "label": "Linear API key" }]
},
"runtime": { "kind": "javascript", "entry": "guest.js" },
"actions": [{
"id": "viewer.get",
"name": "Get viewer",
"description": "Read the authenticated Linear viewer.",
"readOnlyHint": true,
"inputSchema": {
"type": "object",
"properties": {},
"additionalProperties": false
}
}]
}Runtime Code
A JavaScript package registers source code separately from the manifest. The runtime receives the selected request and can read only the package-local secrets declared above.
const key = gateway.secrets.get("linear_api_key");
const res = await fetch("https://api.linear.app/graphql", {
method: "POST",
headers: {
authorization: key,
"content-type": "application/json"
},
body: JSON.stringify({
query: "{ viewer { id name email } }"
})
});
return { ok: true, data: await res.json() };Register and Publish
Package authoring is done through the gateway MCP management tools. Store a draft, configure its workspace-owned secrets, test a draft action, then publish the snapshot that callers can be granted.
gateway_capability_packages_validate({ manifest, runtime, uiAssets });
gateway_capability_packages_create({
manifest,
runtime: {
kind: "javascript",
source: runtimeSource
},
uiAssets
});
gateway_capability_packages_set_secret({
packageId: "linear-lite",
secretName: "linear_api_key",
value: "lin_api_..."
});
gateway_capability_packages_test({
packageId: "linear-lite",
action: "viewer.get",
params: {}
});
gateway_capability_packages_publish({ packageId: "linear-lite" });Grant the Published Tool
Publishing does not expose the package to every agent. A caller still needs an Agent identity, session, or workflow grant for the exact package action.
Ask the User Before Continuing
A package action can return a userInputRequest instead of completing immediately. ExecWarden stores the request, shows it to the workspace, and resumes the source session after a person answers. Use this when an integration needs judgment, a reason, a choice, or an explicit continue signal before it calls the provider. Open Human Input for the full lifecycle, MCP response shape, and trust-boundary notes.
return {
ok: true,
userInputRequest: {
title: "Review production change",
summary: "Terminate instance i-123 in us-east-1?",
input: {
kind: "single_choice",
choices: [
{
id: "approve",
label: "Terminate",
style: "danger",
followup: {
capability: "pkg:aws-admin:instances.terminate.commit",
params: { instanceId: "i-123", region: "us-east-1" }
}
},
{ id: "reject", label: "Cancel" }
]
}
}
};Approve/reject prompts are approvals: if a single-choice request has exactly approve and reject choice ids, it appears in the approvals API and UI, and answering it is the approval decision. Generic prompts still return pendingUserInputId; MCP clients see pending_user_input for generic input and pending_approval for approval-shaped input.
Manage Packages Through MCP
Package management tools are authoring controls, not tools every agent should see. Grant them only to a package-authoring identity or hosted session. Ordinary task identities should receive the published package actions, not package registry management.
gateway_docs_get
gateway_examples_list
gateway_examples_get
gateway_capability_packages_validate
gateway_capability_packages_create
gateway_capability_packages_update
gateway_capability_packages_list
gateway_capability_packages_get
gateway_capability_packages_set_secret
gateway_capability_packages_test
gateway_capability_packages_publish
gateway_capability_packages_disable
gateway_capability_packages_deletePackage-Owned Storage
Packages that need durable integration state should bring or configure their own storage. ExecWarden keeps workspace context, package-local secrets, runtime isolation, policy, approvals, and audit boundaries; the package owns its schema and provider choice.