{"id":"4aa1b97a-4400-4af5-a70f-90b8d1c073eb","slug":"multiplex-mcp","kind":"mcp","name":"multiplex-mcp","summary":"mupx, multiplex MCP: one connector per account. Use several accounts of the same MCP service from claude.ai and Claude Code. A Cloudflare Worker you deploy in one click.","owner":"ergo04","repoUrl":"https://github.com/ergo04/multiplex-mcp","license":"MIT","licenseTier":"permissive","trust":"community","stars":0,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-10-15T14:12:13.000Z","addedAt":"2026-10-29T00:47:14.751Z","logoUrl":"https://avatars.githubusercontent.com/u/41323757?u=00687111859b8b349827294675801ed10f0f9560&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["cloud-infra","developer-tools","memory-knowledge"],"tags":["claude","cloudflare-workers","oauth"],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-29T00:56:04.425Z","sample":false,"url":"https://conduits.dev/tools/multiplex-mcp","language":"TypeScript","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"<picture>\n  <source media=\"(prefers-color-scheme: dark)\" srcset=\"brand/mupx-mark-white.svg\">\n  <img src=\"brand/mupx-mark.svg\" alt=\"\" width=\"72\" height=\"72\">\n</picture>\n\n# mupx\n\n**Multiplex MCP: one connector per account.** Use two Resend accounts, three Linear\nworkspaces, or any other MCP service several times over, from claude.ai (web,\ndesktop, mobile), Claude Code, ChatGPT, Codex, Raycast or any MCP client that can\nsend a header.\n\n[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/ergo04/multiplex-mcp/tree/main/apps/gateway)\n\nDocumentation: **https://mupx.simoneergotino.it**\n\n## The problem\n\nclaude.ai keys custom connectors by URL. Adding a second connector with a URL it\nalready has fails\n([anthropics/claude-ai-mcp#178](https://github.com/anthropics/claude-ai-mcp/issues/178)),\nand the connector form has no field for a header, so you can't tell the two\napart with an API key either. If you work across several accounts of the same\nservice, you get to connect one.\n\nAdding `?account=x` to the URL works for a few OAuth servers and fails for\nothers, and it does nothing for services you reach with an API key.\n\n## How it works\n\nThe gateway is a Cloudflare Worker you deploy to your own account. It gives each\naccount its own URL and swaps your token for that account's API key on the way\nupstream:\n\n```\nclaude.ai, ChatGPT, Codex, Raycast ─ OAuth, approved with your password ──┐\nClaude Code, Cursor, … ───────────── Authorization: Bearer <client token> ┤\n                                                                          ▼\n                              https://<your-gateway>/m/<service>/<account>/mcp\n                                                                          │ your token out,\n                                                                          │ the account's key in\n                                                                          ▼\n                                 https://mcp.resend.com/mcp, https://mcp.linear.app/mcp, …\n```\n\n- **claude.ai**, and ChatGPT, Codex or Raycast once you allow them, find the\n  gateway's own OAuth server and sign in with their Client ID Metadata Document;\n  you approve on a consent page with your password. The token a client gets\n  opens that one connector and nothing else.\n- **Claude Code**, or any MCP client that can send a header, can use a static\n  token instead.\n- Requests are forwarded as they are and responses stream back (SSE included).\n  The upstream's auth challenge and cookies never reach the client.\n\n### One URL for every account\n\nA connector per account adds up when a service has many tools: two Resend\nconnectors are more than 260 tools in the model's context. Set\n`SERVICE_<NAME>_MERGED=true` and the service also gets `/u/<service>/mcp`, one\nconnector for all its accounts:\n\n- Its tools are the union of every account's, each with one more argument,\n  `account` (`workspace` for Linear, or whatever `SERVICE_<NAME>_ACCOUNT_PARAM`\n  says). Its allowed values are the accounts that have that tool, since a plan\n  can hide some.\n- A call names the account; the gateway takes the argument out and forwards\n  the call to that account under the same request id. The answer streams back\n  untouched.\n- The gateway answers `initialize` and `server/discover` itself, for clients of\n  the 2025-06-18 and the 2026-07-28 revision, and adds a `list_accounts` tool\n  (`list_workspaces` for Linear).\n- The tool list is cached for five minutes with the Cache API, per data center\n  and on custom domains only. It's meant for stateless servers like Linear's and\n  Resend's.\n\nWith `SERVICE_LINEAR_EXTRA_TOOLS=true`, Linear's merged connector also gets ten\ntools the gateway runs against Linear's GraphQL API, for what its MCP can't do:\ndeleting and reordering milestones, assigning issues to a milestone in one\ncall, archiving and restoring projects and initiatives, linking projects to\ninitiatives.\n\n## Quick start\n\n1. **Deploy.** Click the button above. Cloudflare copies `apps/gateway` into a\n   new repository of yours, creates the KV namespace, asks for an\n   `OWNER_PASSWORD`, and deploys.\n2. **Add accounts.** In the Cloudflare dashboard open the Worker, then\n   _Settings → Variables and Secrets_, and add one secret per account named\n   `ACCOUNT_<SERVICE>_<ACCOUNT>` holding its API key, for example\n   `ACCOUNT_RESEND_WORK` and `ACCOUNT_RESEND_PERSONAL`. No redeploy needed.\n3. **Get the URLs.** Open your gateway's URL and sign in with the password. It\n   lists one connector URL per account.\n4. **Connect.**\n   - claude.ai: _Settings → Connectors → Add custom connector_, paste a URL,\n     leave _Advanced settings_ empty, approve with your password. Repeat for each\n     account.\n   - Claude Code: add a `CLIENT_TOKEN_<NAME>` secret (32+ random characters) and\n     send it as a header:\n\n     ```bash\n     claude mcp add --transport http resend-work https://<your-gateway>/m/resend/work/mcp --header \"Authorization: Bearer <token>\"\n     ```\n\n   - ChatGPT, Codex and Raycast: add their metadata documents to\n     `ALLOWED_CLIENTS` (see [Configuration](#configuration)), then add the URL\n     as a connector and approve it the same way. In ChatGPT a custom connector\n     needs developer mode; in Raycast use _Install MCP Server_ with the HTTP\n     transport.\n   - Any other MCP client that can send a header (Cursor, VS Code, Gemini CLI,\n     …): use a client token as with Claude Code.\n\n## Services\n\n| Service                      | Built in | Credential                                                   |\n| ---------------------------- | -------- | ------------------------------------------------------------ |\n| Linear                       | yes      | personal API key                                             |\n| Resend                       | yes      | API key                                                      |\n| any MCP server with API keys | no       | set `SERVICE_<NAME>_URL`, optionally `SERVICE_<NAME>_HEADER` |\n\nUpstreams that only speak OAuth (Vercel's MCP, for example) are not supported\nyet.\n\n## Configuration\n\nEverything is a Worker variable or secret, so a deployment is configured from\nthe dashboard and its code never changes.\n\n| Name                           | Kind   | What                                                           |\n| ------------------------------ | ------ | -------------------------------------------------------------- |\n| `OWNER_PASSWORD`               | secret | approves connectors; required                                  |\n| `ACCOUNT_<SERVICE>_<ACCOUNT>`  | secret | one account's API key; letters and digits only                 |\n| `SERVICE_<NAME>_URL`           | var    | MCP endpoint of a service that isn't built in                  |\n| `SERVICE_<NAME>_HEADER`        | var    | send the key in this header instead of `Authorization: Bearer` |\n| `SERVICE_<NAME>_NAME`          | var    | display name                                                   |\n| `SERVICE_<NAME>_MERGED`        | var    | `true` adds `/u/<service>/mcp`, every account behind one URL   |\n| `SERVICE_<NAME>_ACCOUNT_PARAM` | var    | the merged connector's account argument; default `account`     |\n| `SERVICE_<NAME>_EXTRA_TOOLS`   | var    | `true` adds the gateway's own tools for the service (Linear)   |\n| `CLIENT_TOKEN_<CLIENT>`        | secret | static bearer token for a client that can send headers         |\n| `CLIENT_PATHS_<CLIENT>`        | var    | comma-separated connector paths that token may open            |\n| `PUBLIC_URL`                   | var    | pin one origin (otherwise each hostname serves itself)         |\n| `ACCESS_TOKEN_DAYS`            | var    | default 30                                                     |\n| `REFRESH_TOKEN_DAYS`           | var    | default 180, sliding while in use                              |\n| `ALLOWED_CLIENTS`              | var    | Client ID Metadata Document URLs; replaces the default         |\n| `DYNAMIC_REGISTRATION`         | var    | `true` to open RFC 7591 registration (off by default)          |\n\nBy default the gateway allows claude.ai's and Claude Code's metadata documents.\nSetting `ALLOWED_CLIENTS` replaces that list, so name those two again. With\nChatGPT, Codex and Raycast added:\n\n```\nhttps://claude.ai/oauth/mcp-oauth-client-metadata,https://claude.ai/oauth/claude-code-client-metadata,https://chatgpt.com/oauth/client.json,https://chatgpt.com/oauth/codex/client.json,https://www.raycast.com/.well-known/oauth-client-metadata/raycast.json\n```\n\nChatGPT signs in with that one stable document because the gateway returns the\nissuer with the authorization code (RFC 9207).\n\n## Security\n\n- One owner. The consent page asks for `OWNER_PASSWORD`, rate limited per IP.\n- Tokens are bound to one connector (RFC 8707): a Resend token can't open\n  Linear.\n- By default only claude.ai's and Claude Code's metadata documents may start\n  an authorization; add others with `ALLOWED_CLIENTS`. The check runs before\n  anything is fetched. Dynamic registration is off, so nobody can register a\n  client.\n- Access tokens last 30 days, because claude.ai may never refresh a custom\n  connector's token\n  ([anthropics/claude-ai-mcp#228](https://github.com/anthropics/claude-ai-mcp/issues/228)).\n- API keys live only in Worker secrets. The public status page counts\n  connectors and problems and names nothing.\n\n## Repository\n\n| Folder                         | What                                                                 |\n| ------------------------------ | -------------------------------------------------------------------- |\n| [`apps/gateway`](apps/gateway) | the Worker you deploy; self-contained, which the Deploy button needs |\n| [`apps/web`](apps/web)         | the documentation site                                               |\n| [`brand`](brand)               | the mupx mark and icon, as SVG                                       |\n\nThe gateway runs on the Workers free plan: 100,000 requests a day and 10 ms of\nCPU per request, which Cloudflare lets an isolate exceed now and then (it stops\none that does so consistently, with error 1102). On my deployment a request\ntakes 4 to 7 ms on a running isolate and 10 to 15 ms on a fresh one; building a\nmerged tool list from four Linear workspaces takes 18 to 20 ms. claude.ai calls\nfrom many data centers, so fresh isolates are common and the per-data-center\ncache of the tool list rarely hits. So far no request has been stopped.\n\n## Credits\n\nBuilt by [Simone Ergotino](https://simoneergotino.it). It generalises\n[linear-mcp-gateway](https://github.com/ergo04/linear-mcp-gateway), which did\nthe same for Linear workspaces only. MIT licensed.\n"}