# mcp-bridge Connect zot to [MCP (Model Context Protocol)](https://modelcontextprotocol.io) servers. This extension reads MCP server configurations from standard locations (same format as Claude Desktop, Cursor, Cline, etc.) and bridges their tools into zot so the LLM can call them directly. ## Features - **Standard config format** — same JSON as Claude Desktop, Cursor, Cline - **On-demand tool discovery** — only `mcp__search_tools` is advertised initially; matching MCP schemas load when needed instead of bloating every model request - **Smart lazy loading** — cached definitions register as deferred tools at startup, servers wake for refresh or tool calls, then auto-sleep after idle time - **Auto-respawn** — calling a loaded tool on a sleeping server wakes it up automatically - **Multi-transport** — stdio, streamable-http, and SSE transports - **Multi-server** — connect to any number of MCP servers simultaneously - **Tool namespacing** — tools appear as `mcp____` to avoid collisions - **Tool annotations** — read-only, destructive, idempotent hints surfaced to LLM - **Configurable timeouts** — per-server connect, request, and idle timeouts - **Custom headers** — auth tokens and other headers for HTTP servers - **Slash commands** — `/mcp` to check status, start/stop/restart servers - **Better error messages** — context-aware errors with actionable suggestions ## Environment variables Like [Claude Code](https://code.claude.com/docs/en/mcp#environment-variable-expansion-in-mcp-json), the bridge expands `${VAR}` and `${VAR:-default}` in `command`, `args`, `env` values, `url`, and `headers` values. This is client configuration compatibility, not a requirement of the MCP protocol. ```json {"mcpServers":{"api":{"transport":"streamable-http","url":"${API_BASE_URL:-https://api.example.com}/mcp","headers":{"Authorization":"Bearer ${API_KEY}"}}}} ``` Expansion uses the bridge process environment after global/project configurations are merged. Defaults apply to unset variables; an explicitly empty variable stays empty. Values are expanded once, without shell execution, bare `$VAR` expansion, nested defaults, or references to sibling `env` entries. Config files are not rewritten. A missing variable without a default disables that server and reports the server, field, and variable name, never the field value; other valid servers remain available. If the project config cannot be read or parsed, the bridge reports that error and still expands and validates retained global servers. Servers with missing required variables are excluded in this case too. ## Quick Start 1. **Build the extension:** ```bash cd examples/extensions/mcp-bridge go build -o mcp-bridge . ``` 2. **Create a project config file:** ```bash mkdir -p .zot cat > .zot/mcp.json << 'EOF' { "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "."] }, "context7": { "command": "npx", "args": ["-y", "@upstash/context7-mcp@latest"] } } } EOF ``` 3. **Install the extension:** ```bash zot ext install . ``` 4. **Restart zot.** On first run the extension refreshes its tool cache in the background. When zot shows `MCP tool cache changed`, run `/reload-ext` once. Future launches register the cached MCP tools immediately as deferred definitions. The model initially sees one small loader tool, `mcp__search_tools`. It searches cached MCP tool names and descriptions locally, activates up to eight relevant definitions by default, and then calls the selected MCP tool normally. This keeps large MCP installations compatible with providers that limit request or tool-schema size. ### Phone pairing with Build Remote Agent [Build Remote Agent](https://grokbuildremote.com/) is an optional, third-party integration that lets a paired phone observe terminal sessions and veto actions. It is an independent Linespotting AB product and is not affiliated with xAI or SpaceX. #### Install the agent Pin release `v0.6.0` and verify the binary against the checksum listed here. The release's own `SHA256SUMS` file does not currently match five of its six binary assets, so do not use that file as the trust source. These checksums were verified directly against the release assets on 2026-08-24: ```text 62673a6856342a87d4a2a659bc1de92200aa19a5b60d88d252254940820f0b7f gbr-agent-darwin-amd64 7baa1a8e214cd71b60e3f2b5063713e00ff740939749c3cab3d702784a1432f8 gbr-agent-darwin-arm64 fb54724367882497f2e8e05e40ecdeb4be29e008e6c865fc5c426cf464e6ad6e gbr-agent-linux-amd64 9e9d7ca45bb0c4ded9d04226136013e9b64ae30f16bcf03069d35e9c38171cb9 gbr-agent-linux-arm64 40355b2be6cd68f3be68f2a06dfd30307ec1a60f16f87f1d6174012b35aa4a49 gbr-agent-windows-amd64.exe 8fb9efcbc7e2ac91c11964944bf0f45e31bb23f4356d9dcb4b305d7cb9b0fe8c gbr-agent-windows-arm64.exe ``` This macOS Apple Silicon example downloads, verifies, and installs the binary. Change both `ASSET` and `SHA` for another platform. ```bash VER=v0.6.0 ASSET=gbr-agent-darwin-arm64 SHA=7baa1a8e214cd71b60e3f2b5063713e00ff740939749c3cab3d702784a1432f8 BASE="https://github.com/LinespottingOrg/GrokBuildRemote-Agents/releases/download/$VER" curl -fsSL -o "$ASSET" "$BASE/$ASSET" if command -v sha256sum >/dev/null 2>&1; then printf '%s %s\n' "$SHA" "$ASSET" | sha256sum -c - else printf '%s %s\n' "$SHA" "$ASSET" | shasum -a 256 -c - fi mkdir -p "$HOME/.local/bin" install -m 0755 "$ASSET" "$HOME/.local/bin/gbr-agent" export PATH="$HOME/.local/bin:$PATH" gbr-agent version # must report v0.6.0 gbr-agent pair gbr-agent run ``` Keep `gbr-agent run` running. Its Bot API should only be available over loopback: ```bash curl -sS http://127.0.0.1:8788/health curl -sS http://127.0.0.1:8788/v1/sessions ``` #### Install the MCP server The MCP server requires Node.js 20 or newer. Pin its source instead of cloning the mutable default branch: ```bash git clone --branch v0.6.0 --depth 1 https://github.com/LinespottingOrg/GrokBuildRemote-Agents.git cd GrokBuildRemote-Agents/mcp/gbr-mcp npm install --ignore-scripts MCP_PATH="$(pwd)/bin/gbr-mcp.js" node "$MCP_PATH" --diagnose ``` The `v0.6.0` source does not include a package lock, so its npm dependency resolution is not fully reproducible. Review the package manifest and resolved dependency tree before use. Put the absolute value of `MCP_PATH` in the configuration below. Never put mailbox keys in `mcp.json`. ## Configuration Config files are loaded from two locations (project overrides global per-server): | Location | Scope | |---|---| | `$ZOT_HOME/mcp.json` | Global (`$XDG_STATE_HOME/zot/mcp.json` when `XDG_STATE_HOME` is set) | | `.zot/mcp.json` | Project-level (in your project root) | ### Config Format Standard MCP config — same as Claude Desktop, with zot-specific extensions: ```jsonc { "mcpServers": { // ── Stdio transport (local subprocess) ─────────────────────────────────── "filesystem": { "command": "npx", // executable to spawn "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"], "env": { // extra environment variables "NODE_ENV": "production" }, "connectTimeout": 30, // connection timeout (seconds) "requestTimeout": 60, // per-request timeout (seconds) "idleTimeout": 300 // idle timeout before stopping (seconds) }, // Build Remote Agent (gbr/1). Pair with `gbr-agent pair`, then keep // `gbr-agent run` running. Use an absolute path to the pinned MCP checkout. "gbr": { "command": "node", "args": ["/ABSOLUTE/PATH/GrokBuildRemote-Agents/mcp/gbr-mcp/bin/gbr-mcp.js"] }, // ── Streamable HTTP transport (modern HTTP) ───────────────────────────── "supabase": { "transport": "streamable-http", "url": "https://mcp.supabase.com/mcp", "headers": { // custom HTTP headers "Authorization": "Bearer YOUR_TOKEN" } }, // ── SSE transport (legacy HTTP) ───────────────────────────────────────── "legacy-server": { "transport": "sse", "url": "https://example.com/sse" } } } ``` ### Configuration Options | Field | Type | Default | Description | |---|---|---|---| | `command` | string | — | Executable to spawn (stdio only) | | `args` | string[] | [] | Arguments for the command | | `env` | object | — | Extra environment variables | | `transport` | string | "stdio" | Transport: "stdio", "streamable-http", or "sse" | | `url` | string | — | Server URL (HTTP transports only) | | `headers` | object | — | Custom HTTP headers (HTTP transports only) | | `connectTimeout` | number | 30 | Connection timeout in seconds | | `requestTimeout` | number | 60 | Per-request timeout in seconds | | `idleTimeout` | number | 300 | Idle timeout before stopping in seconds | ### Example: Multiple Servers ```jsonc { "mcpServers": { // Filesystem access (stdio) "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"] }, // Grep.app - Search GitHub (streamable-http) "grep": { "transport": "streamable-http", "url": "https://mcp.grep.app/" }, // Database queries (stdio) "sqlite": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-sqlite", "test.db"] }, // Documentation lookup (stdio) "context7": { "command": "npx", "args": ["-y", "@upstash/context7-mcp@latest"] }, // You.com web search (streamable-http, keyless) "you": { "transport": "streamable-http", "url": "https://api.you.com/mcp?profile=free" }, // Serply Google-backed search (streamable-http, keyed) "serply": { "transport": "streamable-http", "url": "https://api.serply.io/mcp", "headers": { "X-Api-Key": "${SERPLY_API_KEY}" } } } } ``` ### You.com template `/mcp setup add you` registers the keyless You.com MCP profile (`you-search`). It needs no account or API key. To use the authenticated server and its additional tools, edit `$ZOT_HOME/mcp.json` after adding the template: ```jsonc { "mcpServers": { "you": { "transport": "streamable-http", "url": "https://api.you.com/mcp", "headers": { "Authorization": "Bearer YOUR_YDC_API_KEY" } } } } ``` The authenticated endpoint does not expose `you-finance` by default. Request it explicitly with the `?tools=` URL parameter or the `X-Allowed-Tools` header. ### Serply template `/mcp setup add serply` registers the [Serply](https://serply.io) MCP server, which returns Google-backed results. It has no keyless profile, so the template is the first one that writes a `headers` entry: ```jsonc { "mcpServers": { "serply": { "transport": "streamable-http", "url": "https://api.serply.io/mcp", "headers": { "X-Api-Key": "${SERPLY_API_KEY}" } } } } ``` The template writes the variable reference, not the key, so this entry holds no secret. The file around it is a separate question: another server can hold a literal credential, the way the You.com example above writes one inline, so treat `mcp.json` as safe to commit or sync only when every entry in it uses a variable reference. The bridge expands the reference from its own environment at load time (see [Environment variables](#environment-variables)); with `SERPLY_API_KEY` unset, this server is disabled and reported by name while every other server keeps working. Get a key at [serply.io](https://serply.io); the API reference is at [serply.io/docs](https://serply.io/docs). The server exposes 14 tools, so it covers several verticals rather than one general search: | tool | returns | |------|---------| | `google_search` | Google organic results | | `google_news_search` | Google News | | `google_scholar_search` | Google Scholar, including citation counts | | `google_jobs_search` | Google Jobs | | `google_maps_search` | Google Maps places | | `google_video_search` | Google video results | | `bing_search` | Bing organic results | | `amazon_product_search` | Amazon product listings | | `scrape_url` | a URL's content through the proxy layer | | `reddit_subreddit_posts`, `reddit_subreddit_about`, `reddit_user_posts`, `reddit_post_comments`, `reddit_post` | Reddit subreddits, users, posts, and comments | They reach the model as `mcp__serply__google_scholar_search` and so on, per [Tool Naming](#tool-naming). ## How It Works ``` ┌──────────────────────────────────────────────────────────────┐ │ zot agent │ │ │ │ ┌──────────┐ tool_call ┌──────────────┐ │ │ │ LLM │───────────────▶│ mcp-bridge │ │ │ │ │◀───────────────│ (extension) │ │ │ └──────────┘ tool_result └──────┬───────┘ │ │ │ │ │ ┌──────────┼──────────┐ │ │ ▼ ▼ ▼ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ MCP │ │ MCP │ │ MCP │ │ │ │ server 1 │ │ server 2 │ │ server 3 │ │ │ │ (stdio) │ │ (stdio) │ │ (stdio) │ │ │ └──────────┘ └──────────┘ └──────────┘ │ └──────────────────────────────────────────────────────────────┘ ``` 1. **Startup**: mcp-bridge reads config and registers tools from `mcp-tools-cache.json` 2. **Background refresh**: starts configured MCP servers, calls `tools/list`, and updates the cache when definitions change 3. **Reload**: if the cache changed, run `/reload-ext` once so zot rebuilds the tool registry with the new definitions 4. **Naming**: tools appear as `mcp____` (e.g., `mcp__filesystem__read_file`) 5. **Idle timeout**: servers not used for 5 minutes are automatically stopped 6. **Auto-respawn**: calling a tool on a stopped server wakes it up 7. **Routing**: tool calls are forwarded to the appropriate MCP server ## Slash Commands | Command | Description | |---|---| | `/mcp` | Show status of all configured servers | | `/mcp help` | Show available MCP commands | | `/mcp ` | Show detailed status for one server | | `/mcp start ` | Manually start a server | | `/mcp stop ` | Manually stop a server | | `/mcp restart` | Restart all servers | | `/mcp start all` | Manually start all servers | | `/mcp stop all` | Manually stop all servers | | `/mcp setup templates` | Show available setup templates | | `/mcp setup add