Commit:
7405335892b964893384d2998e66d6d7db89824eSource updated: · Edit this page
Switchboard operator guide¶
This is the complete configuration and deployment reference. For the concise project overview and quick start, see the main README.
Switchboard is a private capability gateway: one curated MCP endpoint backed by the canonical HTTP APIs of independently secured applications.
Applications keep their business rules, state, authorization, auditing, and safety workflows. Switchboard owns MCP transport, profile-based capability composition, API adaptation, and client-facing tool descriptions.
Switchboard can be the only client-reachable MCP endpoint while upstream MCPs remain on loopback or private service networks. OAuth or Cloudflare Access group claims can map callers to composable, exact-tool entitlements. See Group entitlements and private MCP gateways.
Status¶
The initial implementation provides:
- stateless Streamable HTTP or stdio MCP transport;
- profile-based capability selection;
- profile-scoped capability search and descriptions;
- declarative REST capability manifests;
- federation of existing Streamable HTTP MCP servers;
- independently packaged stdio MCP modules with managed startup and shutdown;
- environment-referenced upstream URLs and credentials;
- read-only, mutating, and destructive MCP annotations;
- bounded upstream responses, timeouts, and redirect rejection for REST, MCP, and OAuth token requests;
- loopback-only unauthenticated HTTP, static bearer authentication, OAuth/OIDC JWT resource-server authentication, or Cloudflare Access assertions for identity-bound sessions;
- health, readiness, and Prometheus-compatible metrics endpoints.
Specialized integrations can run as local MCP modules when an operation needs
richer orchestration or lifecycle state than a safe HTTP mapping can express.
Compiled-in Go capabilities can still implement the small Capability
interface.
Quick start¶
Copy the examples without committing local credentials or URLs:
cp switchboard.example.json switchboard.json
cp capabilities/rilldns.example.json capabilities/rilldns.json
export RILLDNS_MCP_URL=https://rilldns.example.com/mcp
export RILLDNS_MCP_TOKEN=replace-me
go run ./cmd/switchboard -config switchboard.json
Connect an MCP client to http://127.0.0.1:8090/mcp. The operational endpoints
are /healthz, /readyz, and /metrics.
For a non-loopback stateless /mcp listener,
SWITCHBOARD_BEARER_TOKEN is mandatory and must contain at least 32 bytes. The identity-bound /mcp/sessions
endpoint instead requires configured static clients, OAuth, or Cloudflare
Access. Capability credentials use only environment-variable references:
Do not place credential values in configuration or capability manifests.
An unauthenticated loopback /mcp endpoint is a single-user development mode:
every local process on that host can call its allowed tools. Use an explicit
bearer or identity-bound sessions whenever the host is not fully trusted.
When a trusted reverse proxy connects to a loopback listener while preserving
an external Host header, set behind_loopback_proxy only after ensuring that
untrusted clients cannot reach the listener directly.
Profiles¶
Profiles limit tool exposure for a particular deployment:
{
"profile": "infrastructure-read",
"tool_policy": "infrastructure-read",
"profiles": {
"infrastructure-read": ["rilldns", "fleetglass"],
"publishing": ["rendercase"]
}
}
Only selected manifests are loaded, so environment variables for disabled capabilities are not required.
Capability manifests¶
Each JSON file in capabilities/ declares one capability. Declarative REST
manifests describe the API and its tools directly. Tool names are exposed as
<capability>_<tool>. Path arguments replace matching {name} segments using
URL escaping. Query arguments map MCP argument names to query parameter names.
Non-GET requests send unconsumed arguments as a JSON body, or the explicit
body_arguments subset when present.
Existing hosted MCP products use "type": "mcp", an endpoint_env, and
environment-backed headers or OAuth client credentials. OAuth access tokens
are acquired and refreshed automatically; client secrets remain in the process
environment. Switchboard discovers upstream tools at startup,
preserves schemas and annotations, adds the capability prefix when absent, and
proxies calls without duplicating the product's tool definitions.
For HTTP deployments, a transient connection, process-start, or tool-list failure degrades only that capability when at least one other capability is available. Switchboard serves the healthy subset and retries each failed capability after 5 seconds with exponential backoff capped at 5 minutes. A recovered capability is included in new downstream sessions; existing sessions keep their immutable tool registry and must reconnect to see it. Invalid manifests, missing environment configuration, and egress-policy violations remain fatal. Tool policy entries are validated immediately for available capabilities and before a recovered capability is admitted. Stdio deployments remain fail-fast.
Reviewed local integrations use "type": "module" and a clean absolute
command. Switchboard starts the executable over stdio, discovers its tools,
proxies calls, and closes it during shutdown. environment contains only names
of variables that may be copied into the otherwise isolated child environment;
it never contains credential values. Module manifests are operator-trusted code
configuration and must not point at downloaded or user-writable executables.
The first module is Log Watcher under modules/log_watcher.
Every network-capable module must declare
"enforce_egress_policy": true. Switchboard passes the non-secret network
boundary to the module, which must apply it to every outbound connection. The
Log Watcher module does so through the same guarded HTTP transport previously
used by its in-process REST capability. Application business rules and durable
state remain upstream.
An upstream that must retain its own per-user ownership or audit checks can set
"forward_oauth_subject": true. Switchboard then sends the exact subject from
the verified inbound OAuth session in X-Switchboard-OAuth-Subject on tool
calls. This option requires an authenticated upstream connection. The header is
absent during startup discovery and for legacy, static-client, and Cloudflare
Access sessions, and capability manifests cannot set the reserved header
directly. The upstream must trust it only when its bearer credential identifies
the configured Switchboard service client, map it to an existing principal,
and continue enforcing its own authorization. See
the reviewed remaining-capability policies.
When an upstream MCP omits or incorrectly applies behavior annotations, an
operator may supply annotation_rules. Each rule contains one or more exact
tool-name prefixes and a complete MCP annotations object. When rules are
present, every selected upstream tool must match exactly one rule; startup fails
for missing, empty, or overlapping classifications. This keeps annotation
corrections explicit and prevents newly added upstream tools from silently
receiving permissive metadata.
Generic manifests should expose the upstream application's safe operations, not bypass them. A DNS mutation should still call an API operation that requires the expected revision, dry-run/plan identifiers, and explicit confirmation.
Egress policy¶
The mandatory top-level egress_policy creates a fail-closed outbound boundary:
{
"egress_policy": {
"allowed_destinations": [
"inventory.example.com:443",
"id.example.com:443"
],
"allowed_cidrs": ["192.0.2.0/24"]
}
}
Every REST base URL, remote MCP endpoint, identity-provider URL, and OAuth token URL must
use HTTPS and match an exact host:port entry. insecure_skip_verify is
always prohibited. Before each new connection, Switchboard resolves the hostname itself,
rejects the complete DNS response if any address falls outside the configured
CIDRs, and dials a validated IP directly. Environment HTTP proxies are disabled
for these connections because they constitute a separate egress path. Include
every intentional proxy, tunnel, loopback, or private-network destination
explicitly. Empty destination and CIDR lists form a valid deny-all policy for a
gateway that needs no outbound network access. Use infrastructure-level firewall
rules as an independent boundary.
Catalog discovery¶
capability_search searches only capabilities selected by the active profile.
Pass optional query, tags, and limit arguments (default 20, maximum 100).
All query words must match the name, title, description, or tags; all requested
tags must match exactly, ignoring case. Results rank name matches ahead of
title, tag, and description matches, with alphabetical ties. Empty queries
list the catalog. total reports matches before the limit.
capability_describe takes an exact name and returns public metadata plus
exposed tool names, descriptions, and safety annotations. Remote MCP tool
summaries also include input schemas; native schemas remain available through
tools/list. Both discovery tools are read-only and preserve
the existing profile-selected tools and stateless transport.
REST, MCP, and module manifests accept optional title, description, tags,
and risk fields. Risk is read_only, mutating, destructive, or unknown;
omitted risk is displayed as unknown. It is operator-authored information,
not an authorization rule. Keep public metadata and upstream tool descriptions
free of secrets. Catalog responses use an explicit public-field allowlist and
exclude endpoint, header, OAuth, and environment configuration.
Authenticated sessions and dynamic tools¶
Configure clients to enable the stateful /mcp/sessions endpoint. Every
installation needs a unique token of at least 32 bytes, referenced by environment
variable. For example, alongside the existing profiles configuration:
{
"clients": {
"workstation": {
"token_env": "SWITCHBOARD_CLIENT_WORKSTATION",
"profile": "all",
"tool_policy": "workplace-read",
"limits": {
"requests_per_minute": 120,
"burst": 10,
"concurrency": 4
},
"discover": true,
"execute": true,
"activate": false
}
},
"tool_policies": {
"workplace-read": {
"version": "pilot-v1",
"profile": "all",
"capabilities": {
"fleetglass": "allow"
},
"tools": {
"wayminder_status": "allow"
},
"tool_limits": {
"wayminder_status": {
"requests_per_minute": 60,
"burst": 5,
"concurrency": 2
}
}
}
},
"session_limit": 256,
"session_idle_seconds": 1800
}
The server derives identity from the bearer credential on every request and
binds each MCP session to that identity. Profiles bound the available
capabilities. Every gateway and identity binding names a tool_policy, which authorizes whole capabilities with
optional exact tool overrides and an auditable policy version. Its decisions are
allow, deny, and require_approval; an exact tool decision overrides its
capability decision, and otherwise omitted tools default to deny. References to
capabilities outside the profile and stale explicit tool names fail startup.
Only tools whose effective decision is allow appear in native discovery or the
capability catalog. Denied tools remain blocked for stale client definitions and
compatibility calls. require_approval fails closed and remains undiscoverable
until a server-side approval workflow is configured.
Capability-level allow is an explicit decision to trust that upstream MCP's
current and future tool set. Switchboard still preserves the upstream tool
schemas, safety annotations, authorization, and plan/confirm workflows. Use
exact tools overrides to remove exceptional high-impact operations. Missing
tool-policy bindings fail startup, and omitted tools deny by default. The three
permissions default to false: discover
exposes search/describe, execute permits native and read-only compatibility
calls, and activate permits session changes when execution is also allowed.
Omit initial_capabilities to expose the whole allowed profile immediately;
this is the recommended configuration when clients should use connected MCP
tools without a separate activation step. Set an explicit subset only when
reducing the initial tool catalog is worth requiring session activation.
Optional client limits apply across every session belonging to that
authenticated identity. A client may have a token-bucket rate limit and a
non-blocking concurrency limit. A tool policy may add stricter tool_limits to
an explicitly allowed tool. Limits use requests_per_minute, burst, and
concurrency; zero values disable the corresponding limit. Rejections do not
reach the upstream and are recorded by the same audit event as other calls.
Permission inspection¶
The read-only permissions command explains the configured authorization
model without accepting credentials or changing policy:
# List identity bindings and flag operator hazards without contacting upstreams.
switchboard permissions report -config switchboard.json
switchboard permissions lint -config switchboard.json
switchboard permissions lint -config switchboard.json -strict
# Expand one configured role through the live capability catalog.
switchboard permissions explain -config switchboard.json \
-provider oauth -policy forgejo-users
# Simulate verified identity attributes using the same matcher as authentication.
switchboard permissions explain -config switchboard.json \
-provider oauth -subject user-id \
-group switchboard-rendercase-readers \
-scope mcp:connect -scope tools:read
# Preview this identity's exact tool changes against a proposed configuration.
switchboard permissions diff -config switchboard.json \
-against switchboard.proposed.json -provider oauth \
-subject user-id -group switchboard-rendercase-readers \
-scope mcp:connect -scope tools:read
Repeat -policy, -group, and -scope to inspect composed access. The report
distinguishes exact tool decisions, explicit capability-wide decisions,
default-denied tools, approval-blocked tools, inactive capabilities, and unavailable
upstreams. -json is available on every action for review automation. report
and lint use configuration only; explain loads the relevant upstream
catalogs so its tool-level answer matches a new live session. Direct -policy
inspection deliberately bypasses subject, group, and scope matching; use
identity attributes when validating an actual assignment. diff loads both
catalogs and reports changes in tool decisions, decision sources, activation,
availability, and callability, followed by lint warnings for the proposed
configuration. Add -strict to lint in CI or deployment preflight when any
warning must stop the change. This is especially appropriate for unattended
workload policies, where broad capability allows and unavailable approval
decisions should not pass review silently.
GET /metrics exposes Prometheus-compatible counters for authentication,
UserInfo, and authorization failures; session-capacity failures; active
sessions; per-capability availability and load-retry failures; tool-call counts and duration sums split by capability, tool,
decision, and outcome; and a numeric effective-policy hash for each composed
policy component set. The 52-bit hash value remains exact in Prometheus and
allows changes() alerts to detect policy or upstream catalog drift across
gateway restarts. Metrics deliberately omit identities, arguments, results,
and error text. The endpoint is not authenticated by Switchboard and must not
be included in a public reverse-proxy route. Allow only the intended monitoring
scraper through an authenticated proxy location or network boundary because
policy names, tool names, and usage volumes remain operationally sensitive.
Ready-to-install alert rules are in
monitoring/switchboard.rules.yml.
OAuth resource-server authentication¶
For short-lived user or workload identities, configure Switchboard as an OAuth
resource server on /mcp/sessions:
{
"oauth": {
"issuer": "https://id.example.com",
"resource": "https://switchboard.example.com/mcp/sessions",
"required_scopes": ["mcp:connect"],
"group_claim": "groups",
"group_source": "access_token",
"scope_claim": "scope",
"jwt_type": "at+jwt",
"static_client_allowlist": ["workload-agent"],
"policies": {
"workplace-readers": {
"version": "pilot-v1",
"groups": ["switchboard-readers"],
"required_scopes": ["tools:read"],
"profile": "all",
"tool_policy": "workplace-read",
"discover": true,
"execute": true,
"activate": false
}
}
}
}
Switchboard discovers the configured issuer, verifies JWT signatures against
its JWKS, and requires exact issuer, expiry, and aud resource validation. It
then requires the configured scopes and maps the immutable sub plus exact
group claims to gateway policy. In the default exclusive mode, more than one
match is denied. When a policy contains both subjects and groups, both
dimensions must match; any listed group satisfies the group dimension. Policy-specific
scopes allow the authorization server's API permissions to constrain the local
tool policy.
group_source defaults to access_token. Set it to userinfo for providers
that release groups only from their standard OIDC UserInfo endpoint. Switchboard
first validates the access token, calls the discovered HTTPS UserInfo endpoint
with that token, and requires the returned sub to equal the validated token
subject before trusting the configured group claim. UserInfo lookup failures
fail closed. UserInfo mode requires openid in required_scopes.
Set policy_mode to composed when group memberships should contribute
multiple entitlements. Composed policies must share one superset profile and
must each reference an explicit tool policy. Effective decisions use
deny-before-approval-before-allow precedence, limits only become stricter, and
the deterministic effective-policy hash is bound to the session and audit. The
default exclusive mode retains the single-match fail-closed behavior.
For issuers such as Pocket ID 2.14 that identify access tokens with the protected
JWT header typ: at+jwt, configure jwt_type: "at+jwt". Switchboard checks that
exact header value after verifying the signature, preventing ID-token substitution.
Issuers using a payload claim can instead use token_type_claim and
token_type_value; configuring both mechanisms requires both to match. If neither
is configured, token separation relies on distinct access-token audiences and scopes.
Validation is local JWT validation rather than token introspection. Individual token revocation therefore takes effect when the token expires unless the issuer removes its signing key; configure a short access-token lifetime.
The configured resource must be the canonical external MCP endpoint without a
trailing slash. Switchboard serves its RFC 9728 document at the corresponding
path-specific /.well-known/oauth-protected-resource/... URL and includes that
URL in authentication challenges. MCP clients must request the same resource
in authorization and token requests and send the access token—not an ID token—
on every MCP request.
allow_static_clients defaults to false whenever OAuth is configured. Prefer
static_client_allowlist for long-lived workload identities that must coexist
with OAuth; only the named entries in clients are enabled. The allowlist and
global switch are mutually exclusive. Use the global switch only temporarily
to migrate all existing clients, then remove those entries or leave the switch
disabled. The separate legacy /mcp endpoint remains
controlled by SWITCHBOARD_BEARER_TOKEN; unset that variable when migration is
complete. OAuth issuer discovery and JWKS requests also obey egress_policy, so
include every authorization-server destination they use.
For Pocket ID, create an API whose resource exactly matches oauth.resource,
define the scopes as API permissions, and grant user-delegated access to the
approved clients. Client ID Metadata Documents can be enabled for compatible
MCP clients; allowlist exact metadata-document URLs rather than wildcards. See
Pocket ID OAuth setup for the rollout checklist.
Cloudflare Access identity¶
An ingress protected by Cloudflare Access can authenticate the same dynamic
session endpoint using the edge-injected Cf-Access-Jwt-Assertion header. Set
cloudflare_access.team_domain, the exact Access application audience, and
subject/group policies that reference the same profiles and tool policies used
by OAuth identities. Switchboard verifies the assertion signature against the
team certs endpoint and requires its exact issuer, audience, expiry, type: app,
stable subject, and email. Root and custom.groups claims are combined for
exact policy matching. Audit identities are prefixed with
cloudflare_access: to prevent collisions with OAuth subjects.
Cloudflare Access is an additional inbound identity source; it is not advertised as an MCP OAuth authorization server. When OAuth is also configured, requests without an Access assertion retain the normal RFC 9728 OAuth challenge. A request containing both an Authorization credential and an Access assertion is rejected as ambiguous. Static clients stay enabled only when every configured identity provider explicitly enables its migration switch.
Restrict the origin so clients cannot bypass Cloudflare, and configure the proxy
to remove any client-supplied assertion before injecting its verified header.
For the same agent path used by Rendercase, Cloudflare validates the client's
bearer credential at the edge, removes Authorization, and injects the Access
assertion for Switchboard. The Access team-domain certs URL is subject to
Switchboard's egress policy and redirect and response-size restrictions.
capability_enable and capability_disable take an exact capability name.
They change only the current session's tool registry and send
notifications/tools/list_changed; clients should refresh tools/list.
Disabled capabilities remain discoverable but cannot execute through either
native calls or the compatibility fallback. Disabling waits for admitted calls
to finish before returning. Upstream sessions are shared by the gateway;
configured remote capabilities can add the verified OAuth subject to each tool
call as described above.
Sessions expire after 30 minutes without a new HTTP request by default, or after 24 hours regardless of activity. The default global limit is 256, with a maximum of 32 sessions per client. DELETE, expiry, and service shutdown close sessions and discard activation. An expired ID returns 404; a fresh initialize starts from the operator's defaults. Configuration and token changes require a service restart, which invalidates all previous sessions.
During migration, /mcp retains its static profile and legacy bearer credential.
When clients are configured, the legacy route is exposed only if
SWITCHBOARD_BEARER_TOKEN is set. Client tokens are accepted only at
/mcp/sessions. Persistent profile mutation is deliberately unavailable through
MCP; operators manage profiles through configuration and deployment.
The reverse proxy must support POST, GET, DELETE, and streaming responses at
/mcp/sessions. Keep response buffering disabled for tool-list notifications.
Switchboard bounds request reads and non-streaming response writes; the
long-lived GET/SSE notification stream is deliberately exempt from the write
deadline.
Do not attach an MCP SDK debug logger in a sensitive deployment. Debug-level SDK output may include tool arguments even though Switchboard's structured audit events deliberately exclude them.
Compatibility execution¶
capability_execute accepts capability, tool, and an arguments object.
Use the exact exposed tool name, including its prefix, from
capability_describe. For example:
This fallback supports remote MCP capabilities in the active profile only. It uses the same selected tool bindings and upstream session as native calls. Only tools explicitly annotated read-only are eligible; destructive annotations, missing safety annotations, excluded tools, REST capabilities, and local modules are rejected. Native mutating tools retain their existing upstream safety workflows.
Arguments are checked against the discovered input schema before forwarding. Schemas that cannot be resolved locally disable compatibility execution for that tool; Switchboard never fetches external schema references. Upstream tool errors, content, and structured results are preserved. Calls have a two-minute deadline and inherit caller cancellation. Remote HTTP response bodies (JSON or SSE, including discovery and native calls) are limited to 8 MiB per response.
Structured audit events cover native and compatibility tool calls. They contain
the authenticated identity (or legacy-shared), profile, session and gateway
correlation identifiers, capability, exact exposed tool, policy version and
decision, outcome, and duration. They omit arguments, results, and error text.
Switchboard forwards the gateway correlation identifier to REST and remote MCP
HTTP upstreams as X-Switchboard-Correlation-ID; manifests cannot override the
header. Local module protocols do not currently receive it. The events are
written to the process log and become durable only when the deployment ships
them to a log collector or SIEM. Upstream application records remain the
authoritative business audit.
The shared deployment credential still determines the active profile; this does
not introduce per-client identities or activation. Mutating compatibility calls
remain unavailable until an explicit confirmation workflow is designed.
Architecture¶
MCP client -> Switchboard profile -> capability adapter/module -> application API
application owns policy/state
Public products may retain their own product-scoped MCP endpoints. Switchboard is the private composition layer for using those and internal APIs together.
The proposed path from a static tool union to searchable and dynamically activated MCP capabilities is documented in Dynamic MCP discovery. The design keeps Switchboard as the single client bootstrap endpoint while preserving profile restrictions, upstream authorization, and application-owned safety workflows.
The executable provider-style boundary, lifecycle, state ownership, security contract, packaging, and control-plane roadmap are documented in Capability module design.
For scheduled and otherwise headless workloads, follow the distinct identity, exact-tool policy, host-network isolation, and audit-collection requirements in Unattended agents. Switchboard constrains only calls routed through it; it is not a shell or host sandbox.
Managed client bootstrap¶
After deploying client policies and their environment-backed credentials, add
workstations to the switchboard_clients inventory group and run
ansible-playbook bootstrap.yml from ansible/. The playbook runs as each
workstation's user. Set switchboard_client_home, switchboard_client_identity,
and switchboard_session_url as shown in the example inventory.
The bootstrap verifies TLS and authentication, installs each installation's
gateway credential in a mode-0600 environment file, and updates its single
Switchboard connection. Supported clients are Codex, Claude Code, OpenCode,
Qwen Code, and pi. It preserves unrelated configuration and existing
approval settings, and writes a protected rollback copy before changes. New
entries use write approvals. An optional switchboard_ca_file installs an
operator-provided private root on Debian, Fedora/Red Hat, or Arch Linux; otherwise
existing system trust must validate the gateway. For Node-based clients that
need the OS trust bundle explicitly, set switchboard_node_ca_bundle; bootstrap
exports it as NODE_EXTRA_CA_CERTS without disabling certificate validation.
Python 3.11+ and curl are required.
This bootstrap is the static-token installation path. Codex can instead use its native MCP OAuth login, and Pi can use an OAuth-capable local extension backed by a Pocket ID public client and PKCE. Those client-specific flows are described in Pocket ID OAuth setup. Do not combine an OAuth configuration with the bootstrap's bearer-token environment variable.
The helper can also be run directly:
Remove --check to apply. Use --client claude, --client opencode, or
--client qwen for their user-level configuration; JSON configuration must be
strict JSON (including a .jsonc file). Use --token-env to select the
installation-specific credential variable. Existing unrelated MCP entries are
preserved; retire direct downstream entries separately during migration.
For several clients on one workstation, set switchboard_installations in the
bootstrap inventory:
switchboard_installations:
- {client: codex, identity: workstation-codex}
- {client: claude, identity: workstation-claude}
- {client: opencode, identity: workstation-opencode}
- {client: qwen, identity: workstation-qwen}
- {client: pi, identity: workstation-pi}
Each identity must exist in switchboard_clients with its own credential.
The pi adapter uses pinned npm dependencies, discovers native tools, and
refreshes them after notifications. It preserves non-Switchboard pi tools and
requires UI approval for mutating or unannotated tools. Headless mutation calls
fail without forwarding. Its bootstrap archives the previous direct Wayminder
extension outside pi's extension discovery directory, retaining a rollback copy.
Start a new login environment and restart the client
to pick up credentials and MCP configuration. The Codex settings follow the
official MCP configuration documentation.
Client formats follow Claude Code's MCP documentation,
OpenCode's MCP documentation, and
Qwen Code's MCP documentation.
Native refresh support must be verified per installed client version. Clients without refresh support
can enable a capability and use capability_execute for read-only calls.
Deployment¶
Container¶
Release images are published for Linux amd64 and arm64 at
ghcr.io/kilo666mj/switchboard. They run as numeric user 65532:65532 from a
minimal scratch filesystem and include the gateway, optional Log Watcher module,
CA roots, project license, third-party notices, and dependency inventory.
Set listen to 0.0.0.0:8090 in the mounted configuration, then run:
docker run --rm --read-only --cap-drop ALL \
--security-opt no-new-privileges \
--publish 127.0.0.1:8090:8090 \
--env-file /path/to/switchboard.env \
--mount type=bind,src=/path/to/switchboard.json,dst=/etc/switchboard/switchboard.json,readonly \
--mount type=bind,src=/path/to/capabilities,dst=/etc/switchboard/capabilities,readonly \
ghcr.io/kilo666mj/switchboard:0.1
Protect the environment file and do not bake credentials or populated manifests
into derivative images. Pin production deployments to the release digest shown
in the GitHub release notes. The latest tag follows the newest semantic-version
release; main is a development image and is not a release channel.
Ansible¶
The ansible/ playbook builds Switchboard, installs the selected capability
manifests and a hardened systemd service, and verifies readiness. Log Watcher is
optional: set switchboard_enable_log_watcher: true only when its URL, token,
egress destination, and explicit tool-policy decision are configured. When the
flag is absent or false, its module, manifest, variables, and credentials are
not required.
Copy inventory.example.ini to the ignored inventory.ini and
private.yml.example to the ignored private.yml, then populate deployment
URLs and secrets before running ansible-playbook playbook.yml from that
directory. Put TLS termination on the same host and proxy to
http://127.0.0.1:8090.
Public release privacy¶
Run the privacy release gate on the exact commit and refs intended for publication. Complete the full-history privacy and secret scans, artifact verification, attribution review, and hosted checks before publishing a release.
Agent Relay coordination¶
Agent Relay is a separate durable mailbox/task service. Copy
capabilities/agent.example.json to capabilities/agent.json, supply
AGENT_RELAY_MCP_URL and AGENT_RELAY_MCP_TOKEN in the gateway environment,
and select the agent-relay example profile or add agent to an intended
profile. For dynamic clients, include agent in initial_capabilities when
clients need its native tools immediately at startup.
The gateway exposes agent_list, agent_send, agent_inbox, agent_read,
agent_reply, agent_claim, agent_complete, agent_cancel, and
agent_status.
Relay owns identities, messages, task state, and audit history; Switchboard
continues to own capability access and transport composition.
Each upstream token represents one Relay identity. Distinct gateway client credentials do not become distinct Relay identities on a shared upstream connection. Use a separate gateway process/upstream credential per installation when isolation is required, or connect directly to Relay. A client cannot choose a different Relay sender through tool arguments in per-agent mode. Compatibility execution remains read-only: use native tools for sending and task transitions. The existing pi adapter exposes Relay without another service-specific extension.
Agent Relay's docs/clients.md includes setup instructions and an opt-in
real-process integration test covering the gateway and mailbox task flow.
License¶
Switchboard is licensed under the MIT License. Third-party dependencies retain their own licenses and attribution requirements.
Release review archives¶
See review archives for reproducible Linux gateway builds, dependency inventories, verbatim notices and native MCP startup verification. The same guide includes pi source bundles with locked runtime dependency notices and clean-install verification. Licensing and final distribution review remain required. Nothing is published by the build commands.