Skip to content

Releases: cmer/mcp-switchboard

v1.5.2

Choose a tag to compare

@cmer cmer released this 12 Oct 00:34
fa176c4

Fixed

  • SSE servers that retired the legacy transport. Cloudflare's MCP servers (and others moving
    off HTTP+SSE) now answer the SSE stream with 410 Gone, which left the server stuck on
    "Unreachable · Non-200 status code (410)" and gave no hint about the fix. When an SSE server
    refuses the stream (404/405/410), the switchboard now retries Streamable HTTP at the same URL
    and switches the server to HTTP once that connects. OAuth servers go to Needs auth as usual.
    If HTTP fails too, the error says to change the transport and URL (usually /sse → /mcp).

v1.5.1

Choose a tag to compare

@cmer cmer released this 09 Oct 00:28
02d3f50

Fixed

  • Claude connectors behind chained proxies. Behind Cloudflare → Caddy (or any proxy hop that
    speaks plain HTTP), the agent OAuth metadata advertised http:// URLs, because the inner proxy
    reports its own scheme, and Claude refused to sign in. A PUBLIC_URL that is https:// now
    settles the scheme for requests to its own host, so the common one-hostname setup works without
    also setting MCP_PUBLIC_URL.

Changed

  • Clearer env var docs. The README now splits the variables into the admin UI's and the agent
    endpoint's, spells out which OAuth direction PUBLIC_URL and MCP_PUBLIC_URL each serve, lists
    typical setups, and adds a Behind a reverse proxy section with a curl check for the metadata
    Claude reads. The Claude connector steps now match the current dialog (full /mcp/<slug> URL,
    dynamic registration, CIMD unsupported).

v1.5.0

Choose a tag to compare

@cmer cmer released this 07 Oct 01:40
2f68ff9

Added

  • OAuth for agents — connect Claude Desktop and claude.ai. Custom connectors in Claude Desktop
    and claude.ai can't send a static Authorization header, so they couldn't reach
    /mcp/<agent-slug> at all. The switchboard is now its own OAuth 2.1 authorization server for its
    agent endpoints (protected-resource and authorization-server metadata, dynamic client
    registration, PKCE, refresh-token rotation): paste the agent's endpoint URL into Add custom
    connector
    and approve the connection with a one-time pairing code generated on the Agents
    page. Pairing codes keep the agent's long-lived token off a web page anyone can link to. Approved
    clients are listed per agent under OAuth connections and can be revoked; static bearer tokens
    keep working unchanged. The endpoint must be reachable over public HTTPS, since Claude's
    connectors connect from Anthropic's cloud.
  • CORS on /mcp/<agent-slug>, so browser-based clients such as MCP Inspector can read the
    session id and the OAuth challenge.

v1.4.3

Choose a tag to compare

@cmer cmer released this 11 Sep 03:10
0779f44

Fixed

  • OAuth no longer breaks for good when PUBLIC_URL changes. A dynamically registered OAuth
    client is bound to the redirect URI it was registered with, so after PUBLIC_URL changed the
    stored registration kept sending the old URI and providers rejected every attempt with
    "Invalid redirect URI … does not match any registered URI for this client" (Linear's wording) —
    with no way out from the UI. A registration whose redirect URI no longer matches is now discarded
    and re-created on the next authorization, and a redirect-URI error explains that the provider
    wants an https or loopback PUBLIC_URL.

v1.4.2

Choose a tag to compare

@cmer cmer released this 14 Aug 02:44
24d011c

Fixed

  • Idle agent sessions are less likely to be dropped by a reverse proxy. The MCP SDK was updated
    to 1.30.0, whose Streamable HTTP server transport now emits SSE keep-alive comment frames (and
    fixes the keep-alive timer's lifecycle) — an agent that sits idle between tool calls no longer
    looks like a dead connection to an intermediary that times out silent streams, which showed up as
    a session vanishing mid-conversation. The same bump tightens Content-Type validation to parse
    the media type instead of substring-matching it, and bounds the read buffer for stdio servers that
    emit very large responses.

v1.4.1

Choose a tag to compare

@cmer cmer released this 14 Aug 02:43
0079560

Fixed

  • git in the Docker image. stdio MCP servers installed from a git+https://… spec (e.g. via
    pipx run / uvx) failed with Cannot find command 'git' because the runtime image only had
    python and pipx. git and ca-certificates are now installed alongside them.

v1.4.0

Choose a tag to compare

@cmer cmer released this 13 Aug 17:40
673872a

Added

  • Lean mode per agent. An agent with 5–10 enabled servers can receive 100+ tool definitions —
    tens of thousands of context tokens paid on every session for schemas it mostly never uses. A new
    per-agent Tool exposure toggle (Agents page, default Full) switches an agent to Lean: its
    tools/list shrinks to a constant-size set of meta-tools — switchboard__search_tools (ranked
    lexical search over its enabled catalog), switchboard__describe_tools (full descriptions with
    input/output shapes rendered as compact TypeScript instead of JSON Schema), and
    switchboard__call_tool (invoke any enabled tool by namespaced name) — so tools are discovered on
    demand via search → describe → call. The switch matrix still governs what is searchable and
    callable, typo'd names come back with suggestions, the Logs page attributes wrapped calls to the
    real upstream tool, and toggling the mode updates live sessions immediately.

  • Agents can register MCP servers themselves. Discovering a useful server used to mean relaying
    its config to a human to paste into the UI. An agent granted the new manager role (a per-agent
    toggle on the Agents page, off by default) gets switchboard__add_server — paste the same
    claude mcp add … line or mcpServers JSON found in a README and the server is created, enabled,
    and its tools appear in the same live session — plus switchboard__assign_server,
    switchboard__list_agents and switchboard__server_status to manage the matrix and self-debug.
    Local stdio servers are the deliberate exception: they execute a command on your machine, so no
    agent can create one directly, whatever its role.

  • A request/approval queue keeps humans in the loop. Every agent (manager or not) gets
    switchboard__request_server: it files the ask — with a pasted config or just a reason — and
    returns immediately. Pending requests show as a badge in the UI with a review panel that renders
    stdio commands in a "this will execute on your machine" warning block; approving one creates the
    server through the same path as the UI and pushes the new tools into the requesting agent's
    still-open session. Denials carry an optional note the agent reads back with
    switchboard__request_status. Stored request configs are encrypted at rest like every other
    secret, and a Settings toggle hides the request tools entirely if you'd rather agents couldn't
    ask. Servers created by agents show an "added by" chip for provenance, and because meta-tool
    calls are ordinary MCP requests, every management action lands in the request logs.

Changed

  • Calls to a server an agent lacks now fail exactly like calls to a server that doesn't exist.
    The two cases used to return different errors ("not enabled for this agent" vs "unknown server"),
    which let any agent probe which server slugs were configured globally. Both now return the same
    Unknown server error, so the switch matrix no longer leaks the existence of servers it hides.

Fixed

  • Request logs no longer attribute switchboard__* meta-tool calls to a phantom "switchboard"
    server.
    Management and request meta-tools were logged with switchboard as their upstream
    server — a server that doesn't exist — polluting the Logs page's server filter. They now log with
    no upstream server, like the other switchboard-native rows.

v1.3.0

Choose a tag to compare

@cmer cmer released this 31 Jul 03:01
d6c9ceb

Added

  • Oh My Pi connection snippet. The connect dialog only covered Claude Code, Codex and raw JSON,
    so Oh My Pi users had to hand-translate the URL and token into its /mcp add syntax. A fourth tab
    now gives a ready-to-paste slash command.

v1.2.0

Choose a tag to compare

@cmer cmer released this 27 Jul 17:12
535d2ea

Added

  • MCP_PORT puts the agent endpoint on its own port. The UI, the REST API and the agent
    endpoint all shared one port, so exposing /mcp/<agent> beyond the LAN meant exposing the admin
    UI with it. Set MCP_PORT and the same process opens a second listener that serves only
    /mcp/<agent-slug> — you can then firewall, tunnel or reverse-proxy that port on its own while
    the UI stays on the trusted interface. Both listeners share the same database, upstream
    connections and sessions. HOST / MCP_HOST bind each listener to a specific interface, and
    MCP_PUBLIC_URL overrides the base URL shown in the connection snippets when the endpoint is
    reached through a proxy or tunnel.
  • Request logs. A new Logs page records every JSON-RPC request an agent sent through the
    switchboard and the response sent back, so "the agent says the tool failed" stops being a
    guessing game. Each request is one line — time, agent, upstream server, tool name, arguments
    preview, duration — that expands to the exact frames on the wire. Filter by agent, by server,
    by method, or by errors / slow (>1s) / in-flight, and search across tool names, summaries and
    error messages. Errors, slow calls and requests still in flight are distinguishable by shape,
    not only colour. Headline counts for the last 24h (volume, error rate, median, p95) sit above
    the list.
  • The log tails live. New requests appear as they arrive over a server-sent-events stream,
    including long-running calls, which show up as in-flight the moment they start and update in
    place when they finish. Some reverse proxies buffer or drop event streams; when the stream
    can't be established the page falls back to polling and says so.
  • Log retention and payload capture are configurable in Settings → Logs. Requests are kept
    for 48 hours by default and pruned automatically; shortening the window prunes immediately.
    Full request/response payloads are recorded by default (capped at 32 KB per frame, with the
    true size still reported) — turning capture off keeps the metadata but stores no frames, which
    matters because tool arguments pass through unredacted.

v1.1.0

Choose a tag to compare

@cmer cmer released this 21 Jul 20:29
3fc87d3

Added

  • Light / dark / system theme switcher. The dark palette was previously locked to the OS
    prefers-color-scheme setting with no way to override it. The choice now persists per
    browser and, in system mode, still follows the OS live. The segmented picker sits in the
    sidebar footer and in Settings → General (the sidebar is hidden below the sm breakpoint).
  • Published to npm as @cmer/mcp-switchboard, runnable with npx @cmer/mcp-switchboard.
    The package bundles the built UI alongside the compiled server, so trying the switchboard no
    longer requires cloning the repo or installing Docker. Docker remains the better fit for a
    long-running install.

Changed

  • The data directory now defaults to ~/.config/mcp-switchboard (respecting
    XDG_CONFIG_HOME) instead of ./data relative to the working directory. The old default
    meant the switchboard you got depended on which directory you launched it from — harmless
    under Docker, which pins DATA_DIR, but a real hazard for npx, where it would scatter
    databases and encryption keys across the filesystem. Existing installs keep working: if a
    cwd-relative data/switchboard.db is found and the new location is empty, it is used and a
    warning points at the new path. DATA_DIR still overrides everything.
  • The data directory is now created 0700. It holds the encryption key and every stored OAuth
    token, and was previously world-readable (the key file itself was already 0600).