mcp-mux
Enables using multiple Gmail accounts/inboxes through one MCP server, with per-account OAuth sessions and an account argument to route tool calls to the intended inbox.
Enables using multiple Linear workspaces through one MCP server, with per-account OAuth sessions and an account argument to route Linear tool calls to the desired workspace.
Enables using multiple Notion workspaces through one MCP server, with per-account OAuth sessions and an account argument to route Notion tool calls to the desired workspace.
Enables using multiple Slack workspaces/accounts, such as work and client Slack, through one MCP server with per-account OAuth sessions and account selection.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-muxcheck unread mail in my work and personal Gmail"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-mux: multiple accounts for any MCP server
mcp-mux lets Claude Code and Codex use multiple accounts of the same MCP server at once: two Gmail inboxes, a work and a client Slack, several Notion or Linear workspaces. It runs as one local MCP server. Every tool gets a required account argument, each account signs in with its own OAuth session, and tokens are kept in the macOS Keychain.

Today, Claude connectors take one account per connector (anthropics/claude-code#27302, 422 👍, no official answer). Slack takes one workspace (#44243). Codex added multiple accounts only for Gmail, Calendar and Contacts (openai/codex#20500). mcp-mux works with any MCP server you can run or reach locally.
Quick start
bun add -g github:majiayu000/mcp-mux # needs Bun ≥ 1.3Write notion.mux.json. Accounts share the upstream and override only what differs:
{
"name": "notion",
"upstream": { "url": "https://mcp.notion.com/mcp", "oauth": {} },
"accounts": {
"work": { "description": "Acme workspace", "oauth": { "authorizeParams": { "login_hint": "me@acme.com" } } },
"personal": { "description": "personal notes" }
}
}Sign in each account once, check them, and add the server to your client:
mcp-mux login notion.mux.json work
mcp-mux login notion.mux.json personal
mcp-mux status notion.mux.json
claude mcp add notion -- mcp-mux serve /abs/path/notion.mux.json # Claude Code
codex mcp add notion -- mcp-mux serve /abs/path/notion.mux.json # CodexThe model now sees each Notion tool once, with account: "work" | "personal" required.
Related MCP server: Multi-Gmail Connector
What it looks like
This run uses the bundled mock OAuth server (examples/mock-oauth-server.ts): two fake users behind one URL, told apart only by their tokens, the same way Gmail or Notion work.
$ mcp-mux login mail.mux.json work
[mcp-mux] logged in "work" (2 tools available)
$ mcp-mux login mail.mux.json home
[mcp-mux] logged in "home" (2 tools available)
$ mcp-mux status mail.mux.json
work ok (2 tools) http: http://127.0.0.1:47821/mcp
home ok (2 tools) http: http://127.0.0.1:47821/mcp
# what the client sees after `mcp-mux serve mail.mux.json`
tools: whoami, search_mail
account: {"type":"string","enum":["work","home"],"description":"Which account to use: work (alice@work.example), home (alice@home.example)"}
whoami({"account":"work"}) -> alice@work.example
whoami({"account":"home"}) -> alice@home.example
search_mail({"account":"work","query":"e"}) -> ["Q3 budget review moved to Friday","Invoice #4411 from Acme"]
search_mail({"account":"home","query":"e"}) -> ["Dentist appointment reminder","Your library books are due"]
whoami({"account":"nope"}) -> error -32602: unknown account "nope"; expected one of: work, homeThe same flow ran in Claude Code: claude mcp list reported ✔ Connected for both a filesystem mux and this OAuth mux.
Features
One toolset, many accounts. The client lists each upstream tool once, with a required
accountenum. Optionaldescriptionlabels (an email address, a workspace name) are shown to the model next to each account.Fails closed. A missing or unknown account is an error. A logged-out account returns an error naming the
mcp-mux logincommand to run. mcp-mux never falls back to another account or returns an empty result in its place.Per-account OAuth 2.1 for remote servers: protected resource discovery, dynamic client registration or a pre-registered client, PKCE, RFC 8707
resource, RFC 9207isscheck, and automatic refresh.authorizeParamspins a login to one identity, for example Googlelogin_hintor Slackteam.Isolated credentials. Each account gets its own Keychain entry (
mcp-mux/<name>/<account>), or an AES-256-GCM encrypted file on other platforms. A stdio account sees only its own environment variables, never another account's secrets.Self-healing. If an upstream crashes, or you log an account in while the client is running, the next call reconnects. No client restart needed.
stdio and Streamable HTTP upstreams, with
${ENV}expansion that fails loudly when a variable is unset.
Compared with
mcp-mux | mcp-remote ×N | Claude Code natively | Codex natively | ||
One toolset + | ✅ | ✅ | ✗ tools duplicated per account | ✗ one server per account | ✗ |
Per-account OAuth login | ✅ | ✗ static headers / env only | ✅ | ◐ one login per endpoint | ◐ Gmail / Calendar / Contacts only |
Pin the identity at login ( | ✅ | ✗ | ✅ | ✗ | ✗ |
Encrypted or keychain token storage | ✅ | ✗ | ✗ not documented | ✅ | cloud |
stdio upstreams | ✅ | ✅ | ✗ | ✅ | ✅ |
Live check of every account | ✅ | ✗ | ◐ one server | ◐ | ✗ |
Full comparison, including the self-hosted gateways: docs/comparison.md.
Configuration
One file describes one upstream server and its accounts. upstream is shared by all accounts, and each account overrides only what differs. env, headers, oauth and oauth.authorizeParams are merged one level deep.
Local (stdio) server, where each account gets different arguments or environment variables:
{
"name": "fs",
"upstream": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem"] },
"accounts": {
"work": { "args": ["-y", "@modelcontextprotocol/server-filesystem", "${MUX_WORK_DIR}"] },
"personal": { "args": ["-y", "@modelcontextprotocol/server-filesystem", "${MUX_PERSONAL_DIR}"],
"env": { "API_TOKEN": "${PERSONAL_TOKEN}" } }
}
}Field | Meaning |
| Server name, also the credential key prefix. |
| stdio upstream. |
| Streamable HTTP upstream. |
| Present means the upstream uses OAuth. Optional |
| Same fields as |
|
|
Some servers don't support dynamic client registration; Slack is one. For those, register an OAuth app yourself and set oauth.clientId, oauth.clientSecret, and a fixed oauth.callbackPort whose redirect URI http://127.0.0.1:<port>/callback is registered with the app.
Secrets: ${VAR} is read from mcp-mux's own environment. MCP clients start servers with only the variables you configure, so put secrets (and MCP_MUX_STORE_KEY when using the file store) in the client's env for this server, for example claude mcp add notion -e MCP_MUX_STORE_KEY=... -- mcp-mux serve ....
Client config files
Claude Code .mcp.json:
{ "mcpServers": { "notion": { "command": "mcp-mux", "args": ["serve", "/abs/path/notion.mux.json"] } } }Codex ~/.codex/config.toml:
[mcp_servers.notion]
command = "mcp-mux"
args = ["serve", "/abs/path/notion.mux.json"]Commands
mcp-mux serve <config.json> run as a stdio MCP server
mcp-mux login <config.json> <account> [--no-browser] OAuth login for one account
mcp-mux logout <config.json> <account> delete one account's stored credentials
mcp-mux status <config.json> connect to every account and report; exit 1 if any failsTry it without real accounts
git clone https://github.com/majiayu000/mcp-mux && cd mcp-mux && bun install
bun examples/mock-oauth-server.ts # http://127.0.0.1:47821/mcp
bun src/cli.ts login examples/mock-mail.mux.json work # login_hint pins alice@work.example
bun src/cli.ts login examples/mock-mail.mux.json home # pick alice@home.example on the consent page
claude mcp add mail -- bun "$PWD/src/cli.ts" serve "$PWD/examples/mock-mail.mux.json"Limitations
OAuth has only been tested against the bundled mock provider, not real Gmail, Slack or Notion. Reports from real providers are welcome.
Local clients only: Claude Code, Codex, Claude Desktop. claude.ai on the web, the mobile apps and cloud routines connect only to remote URLs.
Only tools are proxied. Resources, prompts and
tools/list_changedaren't passed through yet.All accounts must expose the same tools. mcp-mux refuses to start otherwise and lists the difference.
The MCP TypeScript SDK supports protocol versions up to 2025-11-25. Upstreams that only speak 2026-07-28 won't connect yet.
Development
bun install
bun test # config, stores (incl. a throwaway macOS keychain), real filesystem server, OAuth end to end
bun run typecheckDesign and research notes: docs/design.md, docs/research.md, docs/comparison.md.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Hosted Slack MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
Hosted MCP server with managed OAuth for 15+ toolkits: Google Workspace, Fitbit, Oura, Kalshi, etc.
Hosted Airtable MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
One MCP endpoint for Claude, GPT & Gemini: 100+ tools + no-code connectors + agent workers.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI clients to manage multiple accounts per provider (e.g., Notion workspaces, GitHub identities) through a single MCP endpoint, with sticky account selection and context switching.1MIT
- AlicenseNot gradedqualityAmaintenanceEnables Claude to search and read multiple Gmail or Google Workspace mail accounts at once through a local, read-only MCP server, with every result labeled by the account it came from. Tokens stay in the OS keychain, no server is run by the authors, and write actions such as sending, deleting, or archiving are not supported.8 npm1AGPL 3.0
- AlicenseNot gradedqualityCmaintenanceEnables Claude Code and Claude Desktop to search, read, and manage multiple named Gmail inboxes from a self-hosted MCP server, keeping each account's results separate and authenticated through user-owned OAuth tokens.11 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables clients such as Claude, Cursor, VS Code, and Windsurf to manage workspaces, projects, tasks, and AI agents through a hosted OAuth endpoint or a local stdio package, and to generate MCP tools from OpenAPI specs.1,264 npmMIT