Developer docs
Connect any MCP-speaking agent to the Bezalel capability plane. Two values are all a consumer needs: the MCP URL and a bearer token.
Endpoint and auth
https://bezalel.sh/api/mcpAuthorization: Bearer <TOKEN>Tokens look like bzl_… and are minted per agent by the plane’s owner in the dashboard. /api/* on this site proxies same-origin to the plane server; the setup instructions always carry the plane’s current direct URL as well.
The one-paste setup
Paste one prompt into your agent and it registers the plane in its own harness. The Agents page shows it pre-filled with your token:
Connect yourself to my Bezalel capability plane: fetch https://bezalel.sh/api/setup and follow the instructions. Your token is <TOKEN>.The setup instructions are a markdown document, kept current by the plane itself, with exact registration commands for every harness — plus skill installation and proactive-memory hooks.
Register by harness
Claude Code
claude mcp add --scope user --transport http bezalel https://bezalel.sh/api/mcp \
--header "Authorization: Bearer <TOKEN>"Codex CLI
Append to the file[mcp_servers.bezalel]
url = "https://bezalel.sh/api/mcp"
http_headers = { "Authorization" = "Bearer <TOKEN>" }Cursor
Merge into the project file, or ~/.cursor/mcp.json for every project{
"mcpServers": {
"bezalel": {
"url": "https://bezalel.sh/api/mcp",
"headers": { "Authorization": "Bearer <TOKEN>" }
}
}
}OpenClaw
openclaw mcp add bezalel --transport streamable-http \
--url https://bezalel.sh/api/mcp --header "Authorization: Bearer <TOKEN>"eve
Set BEZALEL_TOKEN in the app environmentimport { defineMcpClientConnection } from "eve/connections";
export default defineMcpClientConnection({
url: "https://bezalel.sh/api/mcp",
description: "Bezalel capability plane: the owner's connected apps, memory, email, texting, money, computer, and sandboxes.",
auth: { getToken: async () => ({ token: process.env.BEZALEL_TOKEN! }) },
});Anything else that speaks MCP: Streamable HTTP endpoint https://bezalel.sh/api/mcp with the Authorization header above.
Verify a connection
Reconnect first — MCP clients cache tool lists per session. Then call the health__check tool: it reports the agent identity and the scopes the token grants. tools/list shows only the tools those scopes can call, and every call is re-checked server-side.
Scopes
Tokens carry capability-domain scopes. A denied call returns a descriptive error naming the missing scope.
healthConnectivity check; reports the agent identity and granted scopes.
memoryLong-term memory shared across every agent: search, add, profile, forget.
emailReal inboxes the plane owns: send, reply, read messages and threads.
imessageTexting on the owner's paired line: messages, attachments, polls, reactions.
chatThe owner's own bots on Telegram and other chat platforms: wake on their messages, answer in the thread.
financeThe spend ledger plus linked bank accounts and transaction sync.
cardsSaved payment cards in Vault, with agent shopping, spending limits, and owner approval. Connect your Agentcard account in the dashboard first.
computerThe cloud desktop: shell, screenshots, vision-driven tasks.
sandboxDisposable code-execution microVMs: exec, files, lifecycle.
connectorsHundreds of third-party apps behind managed OAuth: discover and execute.
appsSmall apps agents build for the owner, with their own data and a screen on the dashboard: list, publish, preview, run.
Plan limits and billing errors
When a call needs more than the owner's plan allows, or billing can't be checked, it fails with one of these code values:
plan_limitAn allowance is used up, compute isn't in the plan, or account capacity is full.
payment_requiredThe account has no active plan, or a payment is past due.
billing_unavailableBezalel couldn't reach its billing service. This isn't a plan limit.
billing_pendingBilling is busy, or this operation already has a billing reservation.
session_endedA compute session reached its deadline. Start a new session to continue. When transient is true, the work may have run, so check its result before retrying.
Most of these failures also carry a billing object. Every billing object has kind, reason, retryable, and retryAfterSeconds, and a plan_limit also has the other fields below when the plane knows them:
kind,reason: The kind isplan_limit,payment_required, orprovider_unavailable. The reason isallowance_used_up,not_in_plan,capacity_reached,held_by_running_requests,no_plan,past_due,plan_inactive,billing_unavailable, orbilling_busy.retryable,retryAfterSeconds: Whether trying again can work, and how many seconds to wait first.allowance,feature,name,unit,plan: Which allowance it was, such asapp_actions, and the plan:free,personal,pro,grace, or null.requested,used,limit,remaining: The request's size, then the usage, limit, and what is left of the plan's allowance this period. Top-up units count intopUpBalanceinstead.resetsAt,graceEndsAt: When the allowance resets and when grace ends, as ISO 8601 times in UTC.topUpBalance,topUpAvailable,topUpPack: Prepaid top-up units left, or null when that's unknown or the allowance has no packs. Then whether the owner can buy a top-up, and the pack'sunitsandpriceUsd.autoTopUp:enabledis false when automatic top-ups don't cover this allowance.statusispurchasedwhen the plane just bought a pack but running requests used it,in_progresswhile another request buys one,waitingwhen the next try has to wait,owner_action_neededwhen the owner has to act on the billing page, oroff.billingUrl,upgradeUrl,topUpUrl: Absolute links to the owner's billing page, such as https://bezalel.sh/dashboard/billing. Pro has noupgradeUrl, andtopUpUrlappears only when the owner can buy a top-up.
A payment_required adds only plan and billingUrl, plus upgradeUrl when no plan is active. It never has allowance, used, limit, resetsAt, or topUpBalance. When billing is unavailable or busy, the kind is provider_unavailable and the object adds nothing, so it has no links.
Retry only when retryable is true, and wait retryAfterSeconds first. Otherwise, pass the message and links to the owner. The same call fails until the owner acts or the allowance resets. A wait of more than five minutes, such as automatic top-ups paused for an hour, isn't retryable either, and its message says until when.
Over MCP, a failed tool call returns isError: true, and its text content is one JSON object with the message in error, the code, billing when there is one, and transient when the work may have run.
Private connections
Let an agent read selected facts from an internal order service through a private gateway. The guide covers setup requirements, agent access, approvals, order tests, and troubleshooting. Worker and gateway provisioning require your operator and the Bezalel team.
Read the private connections guideSkill playbooks
Per-domain usage playbooks (Agent Skills, SKILL.md convention) are served by the plane:
GET https://bezalel.sh/api/skillsGET https://bezalel.sh/api/skills/<name>Service status
GET https://bezalel.sh/apiReturns the plane version, uptime, and which capability domains are configured on this deployment — see it live.
Self-hosting
The plane is a single long-lived Node process, deployable from the repository Dockerfile to any container host. Your deployment uses your own database and provider credentials, and keeps each account’s data separate by owner id, as the hosted service does.
For agents
The overview and link index live at llms.txt. Every page on this site serves markdown from the same URL via Accept: text/markdown, or by appending .md to the path (this page: /docs.md).