{
  "markdown": "# opencode-mcp-bridge\n\nA coordinator-facing MCP server for a self-hosted\n[`OpenCode`](https://opencode.ai) instance.\n\nA host harness (Codex, Claude Code, Cursor, or any MCP-capable client)\ndelegates repository or system work to an OpenCode worker on another\nmachine. The host model scopes the task, coordinates the worker, and\nverifies the result. The bridge speaks MCP over Streamable HTTP with\nBearer authentication (remote HTTP only; there is no local stdio\ntransport). It coordinates OpenCode workers; it does not replace\nOpenCode.\n\nThis is not a hosted OpenCode service for production. Each user should\nself-host for production: provide an OpenCode server, or use one they\ncontrol, plus their own bridge deployment and token. The project includes\nan optional community demo endpoint operated by ManuOtel at\n`https://opencode-mcp.manuotel.com/worker-mcp` (`/worker-mcp` only); it\nrequires its own token and is not for production. Placeholder URLs such as\n`https://YOUR-BRIDGE-HOST/worker-mcp` are not usable servers.\n\n## Section map\n\n1. [Quick start (60 seconds)](#quick-start-60-seconds)\n2. [Endpoints](#endpoints)\n3. [Harness setup](#harness-setup)\n4. [Worker workflow](#worker-workflow)\n5. [Tools](#tools)\n6. [Security](#security)\n7. [Local deployment](#local-deployment)\n8. [Contributor workflow](#contributor-workflow)\n9. [Publish and discover](#publish-and-discover)\n10. [Community and license](#community-and-license)\n\n## Quick start (60 seconds)\n\nYou need your own bridge deployment ([Local deployment](#local-deployment))\nand its Bearer token. Keep the token in environment variables. Never\npaste a real token into a file, a chat log, or a commit.\n\n```bash\nexport OPENCODE_MCP_URL=\"https://<your-domain>/worker-mcp\"\nexport OPENCODE_MCP_BEARER_TOKEN=\"<paste-token-here>\"\n```\n\nReplace `<your-domain>` with your bridge host and `<paste-token-here>`\nwith the value of `MCP_BEARER_TOKEN` on that host. Then register the\ntransport in your harness (see [Harness setup](#harness-setup)).\n\nQuick connect (your own bridge): `./scripts/install-client.sh both`\nregisters Codex and Claude Code transports from `OPENCODE_MCP_URL` and\n`OPENCODE_MCP_BEARER_TOKEN`. Full steps live in\n[docs/client-setup.md](docs/client-setup.md). The maintainer demo is\nopt-in only and may require its own token; generic installs never point\nat another person's server.\n\nRules for every example in this file:\n\n- `https://<your-domain>/worker-mcp` is the safe default. It exposes\n  exactly five worker tools and never includes `exec_run`.\n- `https://<your-domain>/mcp` exposes the full legacy catalog, including\n  `exec_run` when the operator enables it. Use it only for legacy clients.\n- `https://YOUR-BRIDGE-HOST/worker-mcp` (as shipped in `.mcp.json`) is a\n  placeholder. It fails loudly by design. Always register your own URL\n  per machine for production. The optional community demo endpoint\n  `https://opencode-mcp.manuotel.com/worker-mcp` (`/worker-mcp` only) is\n  operated by ManuOtel, requires its own token, and is not for production.\n- Generate a fresh token with\n  `python3 -c \"import secrets; print(secrets.token_urlsafe(48))\"`.\n\nThe helper `./scripts/install-client.sh --help` registers Codex or Claude\nCode transports from these variables. It requires both variables and\nfails clearly when either is missing or the URL is malformed (it must be\n`http(s)://...` ending in `/mcp` or `/worker-mcp`); it never falls back\nto anyone else's server. Full Codex and Claude Code steps live in\n[docs/client-setup.md](docs/client-setup.md). Copilot-family products\nhave their own guide at [docs/copilot-setup.md](docs/copilot-setup.md).\nFor the public registry metadata and publication checklist, see\n[docs/registry.md](docs/registry.md). The registry entry describes the\nsoftware and advertises the optional community demo endpoint operated by\nManuOtel; it never supplies a token. Self-host for production with your\nown token.\n\n## Endpoints\n\nTwo Streamable HTTP endpoints share one Bearer token.\n`GET /health` is the only unauthenticated endpoint. Remote HTTP only;\nthere is no local stdio command.\n\n| Endpoint | Tools | Use |\n| --- | --- | --- |\n| `/worker-mcp` | Exactly five: `worker_catalog`, `worker_run`, `worker_status`, `worker_verify`, `worker_cleanup` | Default for all new clients. Least privilege; no shell. |\n| `/mcp` | Full 16-tool catalog: the five worker tools plus `list_*`, session tools, `get_diff`, `exec_run` | Legacy clients only. `exec_run` stays listed but fails closed unless `ENABLE_EXEC_RUN=true`. |\n| `/health` | None (open) | Reverse-proxy checks. |\n\nThere is no global tool-profile switch. Both endpoints are always served\nfrom the same process.\n\n## Harness setup\n\nCompatibility is protocol-level (MCP over Streamable HTTP with a Bearer\nheader) unless an end-to-end test is documented in this repo. Client\nconfig keys differ per product; confirm key names in the linked official\ndocs before pasting.\n\n| Harness | How to connect | Status |\n| --- | --- | --- |\n| OpenAI Codex CLI | `codex mcp add` with `--bearer-token-env-var` | Protocol-level, syntax from official docs |\n| Claude Code | `claude mcp add --transport http` or `opencode-worker` plugin | Protocol-level, syntax from official docs |\n| ChatGPT Developer Mode | Remote MCP connector, URL mode + Bearer token | Protocol-level; needs an eligible plan and workspace, plus admin approval where required |\n| Cursor | Project `.cursor/mcp.json`, `url` + `headers` | Protocol-level |\n| Gemini CLI | `~/.gemini/settings.json`, `httpUrl` + `headers` | Protocol-level |\n| Windsurf | `~/.codeium/windsurf/mcp_config.json`, `serverUrl` + `headers` | Protocol-level, key names from official docs |\n| Cline | `cline_mcp_settings.json`, `type: streamableHttp` + `url` + `headers` | Protocol-level, key names from official docs |\n| Roo Code | `mcpServers` entry, `url` + `Authorization` header | Protocol-level, client-specific shape |\n| Pi | `pi-mcp-adapter`, shared `~/.config/mcp/mcp.json` | Protocol-level, syntax from official docs |\n| Hermes Agent | YAML `mcp_servers` entry + `tools.include` | Protocol-level, syntax from official docs |\n| GitHub Copilot / Copilot Studio / M365 Copilot | See [docs/copilot-setup.md](docs/copilot-setup.md) | Separate guide, three distinct cases |\n| MCP Inspector | Streamable HTTP transport + `Authorization` header | Debugging only |\n\nThe safe pattern in every client-specific block below: URL\n`https://<your-domain>/worker-mcp`, header\n`Authorization: Bearer ${OPENCODE_MCP_BEARER_TOKEN}`, tools\n`worker_catalog`, `worker_run`, `worker_status`, `worker_verify`,\n`worker_cleanup`.\n\n### OpenAI Codex CLI\n\n```bash\ncodex mcp add opencode --url \"$OPENCODE_MCP_URL\" --bearer-token-env-var OPENCODE_MCP_BEARER_TOKEN\n```\n\nCodex reads the token from the environment at request time. Codex plugin\nbundles do not interpolate environment variables in the server URL, so\nregister the transport per machine with your concrete URL. There is also\nan `opencode-worker` plugin with worker skills, installed from a Git\nmarketplace pinned at `v0.2.0`:\n\n```bash\ncodex plugin marketplace add ManuOtel/opencode-mcp-bridge --ref v0.2.0\n```\n\nThen install `opencode-worker` from that marketplace and register your\nown transport as above (required: the bundled placeholder URL is not\nusable). Details: [docs/client-setup.md](docs/client-setup.md) sections\n2 and 6. Official docs:\nhttps://developers.openai.com/codex/cli/reference\n\n### Claude Code\n\nPreferred transport (no skills): a project `.mcp.json` entry. Claude\nCode expands `${VAR}` references in `url` and `headers` at load time,\nso the token stays in the environment and out of the file:\n\n```json\n{\n  \"mcpServers\": {\n    \"opencode\": {\n      \"type\": \"http\",\n      \"url\": \"${OPENCODE_MCP_URL}\",\n      \"headers\": {\n        \"Authorization\": \"Bearer ${OPENCODE_MCP_BEARER_TOKEN}\"\n      }\n    }\n  }\n}\n```\n\nCLI alternative (transport only, no skills). Double quotes let the shell\nexpand the token before Claude Code sees it:\n\n```bash\nclaude mcp add --transport http opencode \"$OPENCODE_MCP_URL\" --header \"Authorization: Bearer $OPENCODE_MCP_BEARER_TOKEN\"\n```\n\nWarning: `claude mcp add` writes the resolved header into its local MCP\nconfig, which can persist the token on disk. Prefer the `.mcp.json`\nform above on shared hosts, and rotate the token if a config file\nleaks.\n\nPrefer the env-var reference form so the token value never lands in\nconfig (see [docs/client-setup.md](docs/client-setup.md) section 3):\n\n```bash\nclaude mcp add --transport http --header 'Authorization: Bearer ${OPENCODE_MCP_BEARER_TOKEN}' opencode \"$OPENCODE_MCP_URL\"\nclaude mcp add --transport http --header 'Authorization: Bearer ${OPENCODE_MCP_BEARER_TOKEN}' opencode-bridge \"$OPENCODE_MCP_URL\"\n```\n\nRecommended path: the `opencode-worker` plugin from this repo's Claude\nmarketplace (`.claude-plugin/marketplace.json`). It bundles the MCP transport\n(URL `${OPENCODE_MCP_URL}`, token `${OPENCODE_MCP_BEARER_TOKEN}`) plus\nthe `coordinate-opencode-worker` skill. Export both variables before\ninstalling:\n\n```bash\nclaude plugin marketplace add ManuOtel/opencode-mcp-bridge\nclaude plugin install opencode-worker@opencode-mcp-bridge\n```\n\nThere is no npm or Brew package; both marketplaces install from this Git\nrepo. Details: [docs/client-setup.md](docs/client-setup.md) sections 3\nand 7. Official docs: https://docs.anthropic.com/en/docs/claude-code/mcp\n\n### ChatGPT Developer Mode\n\nDeveloper Mode ON, then Connectors, Create connector, URL mode with\n`https://<your-domain>/worker-mcp` plus your Bearer token, then Scan\nTools. Select `https://<your-domain>/mcp` only when you explicitly need\nthe full legacy catalog or `exec_run`.\nRemote MCP connectors need an eligible plan and workspace, and may need\nadmin approval. Availability depends on your account, not on this repo.\n\n### Cursor\n\nAdd to `.cursor/mcp.json` in your project (key names per\nhttps://cursor.com/docs/context/mcp):\n\n```json\n{\n  \"mcpServers\": {\n    \"opencode-bridge\": {\n      \"url\": \"https://<your-domain>/worker-mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer ${OPENCODE_MCP_BEARER_TOKEN}\"\n      }\n    }\n  }\n}\n```\n\n### Gemini CLI\n\nAdd to `~/.gemini/settings.json` (key names per\nhttps://google-gemini.github.io/gemini-cli/docs/tools/mcp-server.html):\n\n```json\n{\n  \"mcpServers\": {\n    \"opencode-bridge\": {\n      \"httpUrl\": \"https://<your-domain>/worker-mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer ${OPENCODE_MCP_BEARER_TOKEN}\"\n      }\n    }\n  }\n}\n```\n\n### Windsurf\n\nEdit `~/.codeium/windsurf/mcp_config.json`. Windsurf uses `serverUrl`\n(not `url`) for remote servers and supports `${env:VAR}` interpolation\nin `headers`. Official docs: https://docs.windsurf.com/windsurf/cascade/mcp\n\n```json\n{\n  \"mcpServers\": {\n    \"opencode-bridge\": {\n      \"serverUrl\": \"https://<your-domain>/worker-mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer ${env:OPENCODE_MCP_BEARER_TOKEN}\"\n      }\n    }\n  }\n}\n```\n\nRefresh the server list in Cascade after saving.\n\n### Cline\n\nOpen MCP Servers, Configure tab, Configure MCP Servers\n(`cline_mcp_settings.json`), or use the Remote Servers tab with\nTransport Type Streamable HTTP. Official docs:\nhttps://docs.cline.bot/mcp/mcp-overview\n\n```json\n{\n  \"mcpServers\": {\n    \"opencode-bridge\": {\n      \"type\": \"streamableHttp\",\n      \"url\": \"https://<your-domain>/worker-mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer ${OPENCODE_MCP_BEARER_TOKEN}\"\n      }\n    }\n  }\n}\n```\n\nSet `\"type\": \"streamableHttp\"` explicitly. Omitting it falls back to\nlegacy SSE transport.\n\n### Roo Code\n\nClient-specific shape; confirm key names in the Roo Code docs for your\nversion. Minimal standard form:\n\n```json\n{\n  \"mcpServers\": {\n    \"opencode-bridge\": {\n      \"url\": \"https://<your-domain>/worker-mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer ${OPENCODE_MCP_BEARER_TOKEN}\"\n      }\n    }\n  }\n}\n```\n\n### Pi\n\nInstall the adapter, then add the bridge to the shared\n`~/.config/mcp/mcp.json` (key names per\nhttps://pi.dev/packages/pi-mcp-adapter):\n\n```bash\npi install npm:pi-mcp-adapter\n```\n\n```json\n{\n  \"mcpServers\": {\n    \"opencode-bridge\": {\n      \"url\": \"https://<your-domain>/worker-mcp\",\n      \"auth\": \"bearer\",\n      \"bearerTokenEnv\": \"OPENCODE_MCP_BEARER_TOKEN\",\n      \"includeTools\": [\"worker_catalog\", \"worker_run\", \"worker_status\", \"worker_verify\", \"worker_cleanup\"],\n      \"lifecycle\": \"lazy\"\n    }\n  }\n}\n```\n\nThe token stays in `OPENCODE_MCP_BEARER_TOKEN`; only the variable name\nis stored in the file. Servers are lazy by default and connect on first\ntool call. There is no one-click plugin for this bridge; do not claim\none. Adapter version and current syntax:\nhttps://pi.dev/packages/pi-mcp-adapter\n\n### Hermes Agent\n\nHermes uses YAML `mcp_servers` entries (key names per\nhttps://hermes-agent.nousresearch.com/docs/reference/mcp-config-reference\nand https://github.com/hermes-agent-org/hermes/blob/main/website/docs/guides/use-mcp-with-hermes.md):\n\n```yaml\nmcp_servers:\n  opencode-bridge:\n    url: \"https://<your-domain>/worker-mcp\"\n    headers:\n      Authorization: \"Bearer ${OPENCODE_MCP_BEARER_TOKEN}\"\n    tools:\n      include: [worker_catalog, worker_run, worker_status, worker_verify, worker_cleanup]\n      resources: false\n      prompts: false\n```\n\nHermes resolves `${VAR}` (or `${env:VAR}`) references from its active\nprofile secret scope, falling back to the process environment. Put the\ntoken in `~/.hermes/.env`; an unset variable keeps its literal\nplaceholder. Reload servers with `/reload-mcp` after changing config.\n\n### MCP Inspector (debugging)\n\n```bash\nnpx @modelcontextprotocol/inspector\n```\n\nSelect Streamable HTTP transport, enter\n`https://<your-domain>/worker-mcp`, and add the `Authorization: Bearer`\nheader in the Inspector UI. Never use a real token on a machine you do\nnot control. Docs: https://github.com/modelcontextprotocol/inspector\n\nYou can also smoke-test the deployment without a client:\n`./scripts/smoke.sh` (see the script header).\n\n## Worker workflow\n\nLifecycle, in order. There is no `worker_wait` tool; poll instead.\n\n```text\nworker_catalog()\nworker_run(message=\"Implement X in /path/to/repo\", directory=\"/path/to/repo\", title=\"feat-x\")\nworker_status(taskID=\"<taskID>\", directory=\"/path/to/repo\")  # repeat until idle\nworker_verify(taskID=\"<taskID>\", directory=\"/path/to/repo\")\nworker_cleanup(taskID=\"<taskID>\", directory=\"/path/to/repo\")\n```\n\n1. Pick a model: `worker_catalog` (free and connected only by default).\n   Default model is `opencode/muse-spark-1.3-contributor-free`. No paid\n   models unless explicitly requested for that task. Ordered fallback:\n   free first, then paid `opencode-go/muse-spark-1.3-contributor`\n   (\"Muse Spark 1.3 Contributor\") from `worker_catalog.recommendations[1]`.\n   Paid use must be intentional: pass `providerID`/`modelID` explicitly\n   only when the boss asked for paid for that task. The bridge never\n   auto-selects paid.\n2. Launch: `worker_run` with `message`, `directory`, `title`, and\n   optional `requestID` for safe retries. Save `taskID` and `directory`.\n3. Poll: `worker_status` with the same `taskID` and `directory` until\n   `idle`. States: `running` (wait), `idle` (verify), `error`/`unknown`\n   (recover, see `skills/recover-opencode-task/SKILL.md`).\n4. Verify: call `worker_verify`, then inspect the exact diff and run\n   tests and lint with the host's own tools. Never trust a worker\n   summary alone.\n5. Clean up: `worker_cleanup` (`action=abort` stops, `action=delete`\n   removes) when done.\n\nStatus and messages are directory-scoped: always pass the `directory`\nreturned by `worker_run` when it differs from the server default, or\nstatus reads `unknown`. When omitted, `worker_status` and\n`worker_verify` recover the saved directory from the durable task\nregistry (`TASK_STATE_PATH`). Tasks are idempotent by `requestID`: same\nID plus same inputs returns the existing task with `deduplicated=true`;\nconflicting reuse fails before side effects.\n\nThe plugin skills enforce this workflow: Codex\n(`delegate-to-opencode`, then `verify-opencode-work`, on failure\n`recover-opencode-task`) and Claude Code\n(`coordinate-opencode-worker`). Code changes follow\n`opencode-git-workflow`.\n\n## Tools\n\nFull signatures: [docs/tool-api.md](docs/tool-api.md).\n\nWorker tools (also the full `/worker-mcp` catalog):\n\n| Tool | What it does |\n| --- | --- |\n| `worker_run` | Start a background worker. Returns `taskID` (= session ID), state, model, directory, title, `requestID`, `deduplicated`. Prompts before running. |\n| `worker_status` | Poll state (`running`/`idle`/`error`/`unknown`) plus latest assistant text only, with truncation counts. Read-only. |\n| `worker_catalog` | List models, free and connected only by default, with bridge defaults and ordered `recommendations` (free first, paid fallback second). Read-only. |\n| `worker_verify` | Re-check a finished worker (state plus read-only git evidence). Read-only. |\n| `worker_cleanup` | Abort (`action=abort`) or delete (`action=delete`) a worker session. Prompts before running. |\n\nLegacy tools (`/mcp` only, advanced compatibility):\n\n`list_providers`, `list_agents`, `create_session`, `send_message`,\n`list_sessions`, `get_session`, `list_messages`, `abort_session`,\n`delete_session`, `get_diff`, `exec_run` (raw shell, opt-in via\n`ENABLE_EXEC_RUN=true`, disabled by default).\n\nCompatibility notes: `send_message` accepts `message`; `prompt` remains\nan alias (supply exactly one). `providerID`/`modelID` must be given\ntogether or omitted; when omitted the bridge uses its configured\ndefault. `worker_catalog` filters (`free_only`, `connected_only` default\ntrue, `limit` default 20, cap 100) apply to `models`/`total` only;\n`recommendations` is always two entries (free default rank 1, paid\n`opencode-go/muse-spark-1.3-contributor` rank 2) so clients can discover\nthe fallback when the free model is unavailable. `abort_session`, `delete_session`, and `get_diff` are the\nfull-profile equivalents of `worker_cleanup` and `worker_verify`;\nprefer the worker tools.\n\nPer-tool approval ships in `.mcp.json`: `worker_run` and\n`worker_cleanup` prompt; `worker_status`, `worker_catalog`, and\n`worker_verify` auto-approve. If your client ignores that file, enforce\nthe same policy in the client config.\n\n## Security\n\n- Treat `MCP_BEARER_TOKEN` like a root password: long random value,\n  rotate on leak, never commit `.env` or tokens. Generic install steps\n  never point at another person's server.\n- Use `/worker-mcp` for least privilege. It never exposes `exec_run`,\n  so a leaked token cannot become a direct shell.\n- Do not expose `/mcp` or set `ENABLE_EXEC_RUN=true` on an untrusted\n  deployment. When enabled, plus open directories, anyone with the\n  Bearer token has a shell where the bridge runs. Prefer session tools\n  for code edits; reserve `exec_run` for system ops.\n- Token rotation (zero downtime): `MCP_BEARER_TOKEN_SECONDARY` accepts\n  one extra token during overlap. Steps: 1) generate a new token,\n  2) set it as `MCP_BEARER_TOKEN_SECONDARY` and restart or reload the\n  bridge, 3) move clients to the new token, 4) promote it to\n  `MCP_BEARER_TOKEN`, unset the secondary, restart. Blank or duplicate\n  secondary values fail startup closed. Comparison is constant-time and\n  token values are never logged.\n- `/health` is the only unauthenticated endpoint, plus read-only\n  RFC 9728 discovery at `GET /.well-known/oauth-protected-resource`\n  (and its `/mcp` and `/worker-mcp` children, no secrets, no\n  authorization server). Everything under `/mcp` and `/worker-mcp`\n  requires the Bearer token.\n- Request-body limit: `MCP_MAX_BODY_BYTES` (default 1048576, 1 MiB) caps\n  the declared `Content-Length` and the actual streamed body on `/mcp`\n  and `/worker-mcp`. Oversized requests get a generic 413 before any\n  tool runs. Auth still runs first, so missing tokens stay 401.\n- Browser-origin allowlist (optional): `MCP_ALLOWED_ORIGINS` is a\n  comma-separated exact-origin list (`scheme://host[:port]`, http/https,\n  no path/query/fragment) for `/mcp` and `/worker-mcp`. Unset or blank\n  means no origin policy. Absent `Origin` and `Referer` stays allowed\n  for CLI/SDK clients. Auth runs first (missing tokens stay 401),\n  `/health` never checks origins, and rejections are a generic 403 with\n  no secret or header echo.\n\n## Local deployment\n\nRequires Python 3.11+ and [uv](https://docs.astral.sh/uv/), plus a\nrunning `opencode serve` or `opencode web` (see\n[OpenCode server docs](https://opencode.ai/docs/server/)).\n\n```bash\ngit clone https://github.com/ManuOtel/opencode-mcp-bridge.git\ncd opencode-mcp-bridge\nuv sync\ncp .env.example .env\n# edit .env: OpenCode credentials + a fresh MCP_BEARER_TOKEN\nuv run python -m opencode_mcp_bridge.server\n```\n\nCheck it: `curl http://127.0.0.1:8087/health` should report OpenCode\nhealthy. `POST /mcp` and `POST /worker-mcp` without a Bearer token must\nreturn 401.\n\n| Variable | Default | Purpose |\n| --- | --- | --- |\n| `OPENCODE_BASE_URL` | `http://127.0.0.1:4096` | OpenCode server URL. |\n| `OPENCODE_SERVER_USERNAME` | `opencode` | Basic auth user for OpenCode. |\n| `OPENCODE_SERVER_PASSWORD` | (required) | Basic auth password of your OpenCode server. |\n| `MCP_BEARER_TOKEN` | (required) | Static token clients send as `Authorization: Bearer <token>`. |\n| `MCP_BEARER_TOKEN_SECONDARY` | (unset) | Overlap token for rotation; unset means single-token mode. |\n| `MCP_HOST` | `127.0.0.1` | Bridge listen address. Use a host IP reachable from your reverse proxy when proxying from Docker. |\n| `MCP_PORT` | `8087` | Bridge listen port. |\n| `DEFAULT_DIRECTORY` | `$HOME` | Working directory for sessions when clients omit it. |\n| `DEFAULT_PROVIDER_ID` | `opencode` | Default provider. |\n| `DEFAULT_MODEL_ID` | `muse-spark-1.3-contributor-free` | Default model. |\n| `EXEC_TIMEOUT_S` | `120` | Cap for `exec_run` timeouts. |\n| `EXEC_MAX_OUTPUT_CHARS` | `20000` | Output truncation cap for `exec_run`. |\n| `ENABLE_EXEC_RUN` | `false` | Opt-in for `exec_run` on `/mcp`. Set `true` only where a shell is intended. |\n| `TASK_STATE_PATH` | `/var/lib/opencode-mcp-bridge/tasks.json` | JSON registry for durable tasks (atomic writes, bounded records, no prompts or secrets). |\n| `MCP_MAX_BODY_BYTES` | `1048576` | Max request body (bytes) for `/mcp` and `/worker-mcp`, declared and streamed; oversized returns generic 413. |\n| `MCP_ALLOWED_ORIGINS` | (unset) | Optional exact-origin allowlist for `/mcp` and `/worker-mcp`; unset/blank disables. Single trailing slash stripped. |\n\nPut a reverse proxy with TLS in front. Traefik example:\n`deploy/traefik-opencode-mcp.yaml`. Host systemd keeps full terminal\naccess for `exec_run` (see `deploy/opencode-mcp-bridge.service`, env\nfile `0640`); Docker scopes `exec_run` to the container\n(`docker compose up -d` after filling `.env`). For clean release,\npre/post-deploy checks, rotation, rollback, and log steps, follow\n[docs/operations.md](docs/operations.md).\n\n## Contributor workflow\n\nRead [AGENTS.md](AGENTS.md) first: ownership boundaries, edit\ndiscipline, free-model policy, test commands, secrets, worktree and\ncommit rules, and reporting. The worker playbook lives in `skills/`\n(`delegate-to-opencode`, `verify-opencode-work`,\n`recover-opencode-task`, `opencode-git-workflow`). Planned work lives in\n[docs/roadmap.md](docs/roadmap.md); read phases in order and do not skip\na gate.\n\n```bash\nuv sync\nuv run pytest\nuv run ruff check src tests\nuv run ruff format --check src tests\ngit diff --check\n```\n\nCI (`.github/workflows/ci.yml`) runs the same checks on pull requests\nand pushes to master across Python 3.11, 3.12, and 3.13, plus JSON\nvalidation of the Codex and Claude plugin manifests and a no-push\nDocker build. `ruff format` in write mode touches Python files: use\n`--check` only and report failures instead of fixing them here.\n\n## Publish and discover\n\nReady in this repo (no secrets committed):\n\n- `server.json`: schema-valid remote Streamable HTTP entry for\n  `io.github.ManuOtel/opencode-mcp-bridge`, safe `/worker-mcp`\n  only, auth as a required secret `Authorization` header. The URL\n  `https://opencode-mcp.manuotel.com/worker-mcp` is the optional community\n  demo endpoint operated by ManuOtel; it supplies no token. Self-host for\n  production with your own token.\n- `glama.json`: maintainer claim for `ManuOtel`, nothing else.\n- Smithery: no checked-in file needed; URL publishing is a\n  dashboard/CLI flow. Full checklist:\n  [docs/registry.md](docs/registry.md).\n\nStill requires a human owner login (not done by this change):\n\n- MCP Registry: `mcp-publisher login github` as `ManuOtel`, then\n  `validate` and `publish` the checked-in `server.json`, which advertises\n  `https://opencode-mcp.manuotel.com/worker-mcp` (`/worker-mcp` only).\n  Start here:\n  [publishing quickstart](https://github.com/modelcontextprotocol/registry/blob/main/docs/modelcontextprotocol-io/quickstart.mdx),\n  [server.json spec](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/generic-server-json.md),\n  [live API docs](https://registry.modelcontextprotocol.io/docs).\n- Glama: add this repo at\n  [glama.ai/mcp/servers](https://glama.ai/mcp/servers), then Claim\n  ownership as `ManuOtel` to pick up `glama.json`. Background:\n  [what is glama.json](https://glama.ai/blog/2025-07-08-what-is-glamajson).\n- Smithery: publish at [smithery.ai/new](https://smithery.ai/new)\n  from your own public HTTPS `/worker-mcp` URL\n  ([docs](https://smithery.ai/docs/build/publish)). This bridge uses\n  a static Bearer token, not OAuth, so an auth-required endpoint\n  needs manual review during the Smithery scan: supply the token out\n  of band. The bridge serves truthful RFC 9728 metadata at\n  `GET /.well-known/oauth-protected-resource` (plus `/mcp` and\n  `/worker-mcp` children, no secrets, no authorization server) and\n  points 401s at it via `WWW-Authenticate`, which fixes the\n  \"not a valid OAuth Protected Resource Metadata response\" scan\n  error without weakening auth. It does not add an OAuth login flow;\n  that needs a real authorization server and is out of scope.\n\nListing versus hosting: a registry entry lists the open-source\nbridge (repo, docs, install). It never grants access or supplies a token.\nThe project includes an optional community demo endpoint operated by\nManuOtel at `https://opencode-mcp.manuotel.com/worker-mcp` (`/worker-mcp`\nonly); production users should self-host with their own HTTPS URL and\ntoken.\n\nEndpoint reminder: `/worker-mcp` (five worker tools, no shell) is\nthe default for all new clients; `/mcp` (full legacy catalog,\n`exec_run` opt-in) is legacy only. Never publish an endpoint you do\nnot operate, and never commit tokens.\n\n## Community and license\n\n- Read [CONTRIBUTING.md](CONTRIBUTING.md) before you change code or docs.\n- Obey the [Code of Conduct](CODE_OF_CONDUCT.md) in all project spaces.\n- Report security faults in private per [SECURITY.md](SECURITY.md).\n- Open a [bug report or feature\n  request](https://github.com/ManuOtel/opencode-mcp-bridge/issues/new/choose)\n  or read [open\n  issues](https://github.com/ManuOtel/opencode-mcp-bridge/issues).\n- Open [pull\n  requests](https://github.com/ManuOtel/opencode-mcp-bridge/pulls) from\n  a feature branch, never directly from `master`.\n\nLicense: PolyForm Noncommercial 1.0.0 - free for noncommercial use and\nmodification, commercial use needs permission. See [LICENSE.md](LICENSE.md).\nFor a commercial license, reach out: manuotel@gmail.com\n",
  "bytes": 27302,
  "sha": "b489a20f5871bc9dd961b06322de71d6be6a827aa5084fa6a5c7de55ea3d28f0",
  "repo_slug": "manuotel/opencode-mcp-bridge",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_manuotel_opencode_mcp_bridge_ae0276c2/readme"
}