Claude Code Bridge
A Claude Code channel plugin
that exposes an HTTP REST API and a WebSocket hub. External clients can:
- inject messages into a running Claude Code session,
- subscribe to live events (Claude's replies, permission requests, lifecycle hooks),
- approve or deny tool-use permission prompts remotely.
It is a single Node.js process: the MCP server (over stdio to Claude Code) and
the HTTP/WS server live together. One entry point. One port for clients.
Repo layout
plugin/ # the installable plugin — Node project + manifests live here
src/ # TypeScript sources
dist/ # compiled output (run `npm run build` inside plugin/)
.mcp.json # registers the bridge as an MCP server
hooks/ # hooks.json wiring every lifecycle hook to the bridge
.claude-plugin/plugin.json
.claude-plugin/
marketplace.json # single-plugin marketplace manifest pointing at ./plugin
robot_experiment/ # ESP32 firmware: OLED dashboard + WS client
examples/ # curl recipes, browser WS client
example_esp32_client/ # older ESP32 Firebase-polling sketch
example_esp32_ws_client/ # older ESP32 raw WS sketch
Prerequisites
- Claude Code 2.1.81+ (channels enabled for your org)
- Node.js 20+
- Logged in to claude.ai (channels do not work with raw API keys)
Install
1. Build the plugin
cd plugin
npm install
npm run build
cd ..
This produces plugin/dist/ which the plugin runtime and hooks reference via
${CLAUDE_PLUGIN_ROOT}.
2. Register the marketplace and install
The repo self-hosts as a single-plugin marketplace. From inside Claude Code
(CLI or the Code tab of Claude Desktop):
/plugin marketplace add C:/Users/you/path/to/claude-code-wrapper
/plugin install claude-code-bridge@claude-code-bridge-local
/reload-plugins
Use an absolute path with forward slashes. Git-Bash-style paths like
/c/Users/... get interpreted as git remotes and fail.
Confirm with /mcp — bridge should show as connected.
3. Refreshing after updates
Claude Code snapshots the plugin at install time (keyed by commit hash). After
pulling new changes or editing the plugin, re-snapshot with:
/plugin marketplace remove claude-code-bridge-local
/plugin marketplace add C:/Users/you/path/to/claude-code-wrapper
/reload-plugins
Configure
The bridge will not start without BRIDGE_TOKEN — it is the shared secret
clients use to inject messages and approve tool calls.
Recommended: ~/.claude/settings.json
Claude Code merges the env block into MCP subprocesses and hook commands.
This scopes the token to Claude rather than polluting the system env.
{
"env": {
"BRIDGE_TOKEN": "e0112a5b1f05",
"BRIDGE_URL": "http://127.0.0.1:8787",
"BRIDGE_LOG_FILE": "C:/Users/you/path/to/bridge.log",
"BRIDGE_DEBUG_FRAMES": "1",
"BRIDGE_DATABASE_URL": "https://your-project-default-rtdb.firebaseio.com/",
"BRIDGE_AGENT_ID": "test-agent"
}
}
(BRIDGE_URL is read by hook-forward.js when posting hook events back to the
bridge. The rest are consumed by the bridge process itself.)
Alternative: system env vars
On Windows:
setx BRIDGE_TOKEN "your-token-here"
Close and reopen your terminal (and fully restart Claude Desktop via the tray
icon) so the new value is inherited.
All env vars
| Variable | Default | Notes |
|---|
BRIDGE_TOKEN | (required) | Shared secret. Bridge refuses to start if unset. |
BRIDGE_PORT | 8787 | HTTP + WS port (set in plugin/.mcp.json). |
BRIDGE_HOST | 0.0.0.0 | Bind address (set in plugin/.mcp.json). 127.0.0.1 for localhost-only. |
BRIDGE_LOG_FILE | (unset) | If set, mirror stderr logs to this file. |
BRIDGE_DEBUG_FRAMES | (unset) | 1 → mirror every outbound MCP frame into BRIDGE_LOG_FILE. |
BRIDGE_DATABASE_URL | (unset) | Firebase RTDB URL. Enables Firebase sync + /api/firebaseData proxy. |
BRIDGE_AGENT_ID | (unset) | Agent key under <db>/agents/. Required alongside BRIDGE_DATABASE_URL. |
BRIDGE_URL | http://127.0.0.1:8787 | Where hook-forward.js POSTs hook events. |
BRIDGE_HOOK_TIMEOUT_MS | 500 | Per-hook POST timeout. Never blocks your turn. |
Quick smoke test
Two surfaces:
- Browser — open
examples/ws-client.html, paste your token, click
Connect.
- Terminal — send a message: