Skip to main content

Vend an endpoint

New to switchboard? Sign in and vend your first endpoint walks through the web wizard and the CLI step by step. This page is the reference for what an endpoint is and what it can be granted.

What an endpoint is​

An endpoint is a scoped MCP endpoint switchboard vends to one agent. It is the agent's only door into switchboard, and it is the capability grant. Vending produces two things that always travel together:

  • A URL — https://<host>/mcp/<slug> — the agent's private MCP address.
  • A credential — a bearer token of the form sbk_…, stored hashed and shown to you once at vend time.

Possessing the URL and the credential is the access. The URL alone is not a secret; the credential is. Switchboard serves the endpoint over Streamable HTTP only — the agent connects with URL + bearer and nothing else. There is no local binary to install.

An MCP client that supports OAuth can connect with the URL alone instead: switchboard's consent screen issues it a token for that one endpoint, and no long-lived credential is stored on the client.

What an endpoint is scoped to​

Every endpoint carries a scope you set at vend time. An agent can never widen its own scope.

  • Queues — the set of queues this endpoint may see and act on. Queue names are scoped to the endpoint: two endpoints' inbox queues are unrelated.

  • A verb allowlist — the MCP tools the endpoint may call. Each tool is gated by the verb of the same name:

    GroupVerbs
    Todoslist_todos, get_todo, claim, claim_next, complete, fail, release, heartbeat
    Webhookscreate_webhook, list_webhooks, rotate_webhook, delete_webhook
    Fan-out routesadd_webhook_route, list_webhook_routes, remove_webhook_route
    Routing ruleslist_webhook_rules, set_webhook_rules, add_webhook_rule, update_webhook_rule, move_webhook_rule, remove_webhook_rule, test_webhook_rules
    Event historylist_webhook_events, get_webhook_event, replay_webhook_event
    Default leaseget_default_lease, set_default_lease
    Outbound HTTP calls (notify hooks)create_notify_hook, list_notify_hooks, rotate_notify_hook, delete_notify_hook

    The notify-hook verbs let the agent register an HTTPS URL that Switchboard POSTs a signed notification to when the endpoint's work is ready. Switchboard then dials a host the agent chose, so these verbs are never part of any default grant. The wizard and quick vend list them as their own "Outbound HTTP calls" group, unticked. create_notify_hook returns the Standard Webhooks signing secret (whsec_…) once. list_notify_hooks shows each hook's health, and never a secret or a URL's query string. No vend path grants them by default: name them in --verbs, or tick them in the wizard.

    The web wizard pre-checks the eight todo verbs, and so does switchboard endpoint vend: with no verb flags it grants those eight, plus the two verbs that read and set the endpoint's own default lease, and nothing else (ADR-0047) — the credential a lane holds should be what the lane does. Ask for more with --verbs, naming verbs and/or the presets todo, webhook-admin and all, or add the webhook, routing and event groups with --allow-webhook-admin; endpoint list shows what each lane ended up holding. list_todos also grants get_todo, so an endpoint vended before get_todo existed has it. release changes state, so no other verb grants it: an older endpoint needs a re-vend to get it. The default-lease verbs let the agent read and change its own endpoint's default lease (below). switchboard endpoint vend grants them, because a claim can already ask for the same lease on the call; the wizard leaves them unticked, and a friend endpoint can never hold them.

  • A webhook ceiling — how many webhooks the endpoint may create, which source types (github, gitea, cairn, generic; stripe and slack exist but aren't usable yet), and which queues those webhooks and their routing rules may target. A ceiling of 0 disables webhooks.

  • A lifetime — until revoked, or a duration after which the endpoint expires on its own.

The endpoint enforces this scope at the boundary on every call: verbs outside the allowlist and queues outside the grant are denied.

The default claim lease​

Every endpoint also has a default claim lease: how long a claim, claim_next or heartbeat holds a todo when the call passes no lease_ttl_seconds. Left blank, it is the server default, 300 seconds. Set it when the endpoint's jobs run longer than five minutes, such as a model reviewing a pull request for half an hour: then a worker that forgets lease_ttl_seconds keeps its todo, and a bare heartbeat extends by your default instead of cutting the lease back to 300 seconds.

  • It is whole seconds from 60 to 86400 (24 hours). The web forms and the CLI also take a duration like 45m or 1h. A value out of range is refused, never rounded to the nearest bound.
  • A lease_ttl_seconds on the call still wins, up to 86400.
  • It is not scope, so you can change it at any time without re-vending: on the endpoint's card, with switchboard endpoint edit SLUG --lease-ttl 1h (--lease-ttl default resets it), or with PATCH /api/v1/endpoints/{ref}. A change applies to the next claim or heartbeat; leases already granted keep their expiry.
  • The agent sees the number: its session instructions and its claim, claim_next and heartbeat descriptions state the endpoint's default. An endpoint granted set_default_lease can change its own default; it can never change another endpoint's.

A longer default also means a crashed worker's todo waits longer before another worker gets it, because the todo is requeued only when the lease lapses. Pick the shortest lease that covers a job.

How to configure and vend one​

  1. Open Endpoints on the web board and choose + vend endpoint (the six-step wizard) or quick vend (one page, no webhook ceiling). Both take an optional default claim lease (the wizard asks on its lifetime step).

  2. Name the agent, then choose its queues, verbs, webhook ceiling, and lifetime. Naming the agent registers it; registration alone grants nothing.

  3. Vend, and copy the reveal. It shows the MCP URL, the credential, and the MCP client configuration exactly once — for a Claude Code–style client, an .mcp.json entry:

    {
    "mcpServers": {
    "switchboard": {
    "type": "http",
    "url": "https://<host>/mcp/<slug>",
    "headers": { "Authorization": "Bearer sbk_…" }
    }
    }
    }

The agent can now drain its queues with list_todos / claim / complete.

Store the credential without printing it​

The CLI can vend the same thing without the credential ever reaching the screen or a terminal scrollback. --json prints the raw API response — the credential inside it — so capture it straight into a file only you can read:

umask 077
switchboard endpoint vend my-agent --queue inbox --json > vend.json # created 0600
jq -r .mcp_json vend.json # the client wiring block, still containing the token

Then move the credential where your secrets live — pass it to op / pass / your secret store from the file, never as a shell argument or an echo — and delete vend.json:

op item create --category=password --title switchboard-my-agent \
--password "$(jq -r .token vend.json)" && rm -f vend.json

Nothing in this path prints the token: vend --json writes to the file, the store reads the file, and endpoint list never shows credentials at all. If a credential does end up somewhere it should not be — a log, a transcript, a shared paste — the credential is compromised: revoke the endpoint and vend a fresh one (Operator CLI and API).

What you use an endpoint for​

  • Give an agent least-privilege access to exactly the queues and verbs its job needs — nothing more.
  • Attribute every action. Every vended endpoint belongs to exactly one agent, which belongs to exactly one human. Every todo, webhook, or rule change carries that chain.
  • Revoke instantly. Revoking an endpoint invalidates its stored credential and closes its live MCP sessions — the agent immediately loses all access, with no residue. Revoke = kill the endpoint.

Scope is immutable to shrink — widen it to grow​

An endpoint's scope is immutable in the direction that removes power: a given URL + credential always means one fixed set of powers, and nothing edits that set downwards. To take something away from an agent, vend a new endpoint with the new scope and revoke the old one, rather than editing the live grant. The rotate button on an endpoint card starts the wizard pre-filled from the old scope. This keeps every capability trivial to audit — there is no "when did this scope change, and who changed it?" question, because a reduction is a new endpoint with its own reveal.

The direction that only adds has its own path, because re-vending is a bad trade there: a webhook belongs to the endpoint that created it, so a re-vend mints a new ingest URL and signing secret and needs an edit in the producer's hook configuration — for a change that breaks no route that works today. switchboard endpoint scope widen SLUG adds an ingest queue, a source type or a verb, or raises the webhook ceiling; switchboard endpoint scope add-queue SLUG QUEUE is that command with one flag. It shows the old and the new grant and asks before writing anything, and the endpoint's credential is not touched, so the lane keeps authenticating with the token it already has. Every field a widen moves is recorded beside the change, with the value it replaced. See ADR-0049 — Add-only endpoint scope widening.

The queues an endpoint may claim (its --queue at vend) are not reachable from there: that decides which work the lane can take, so it stays a vend-time choice.

Next​

Deeper detail: ADR-0008 — Human principal + vended endpoints, ADR-0017 — MCP over Streamable HTTP only, and the vended-endpoints spec.