{
  "markdown": "<div align=\"center\">\n\n# JanusMCP\n\n**One credential broker. Every account. From the CLI or MCP.**\nMulti-account tool access for AI agents, with credentials kept local.\n\n[![CI](https://github.com/bayway/janusmcp/actions/workflows/ci.yml/badge.svg)](https://github.com/bayway/janusmcp/actions/workflows/ci.yml)\n[![Release](https://img.shields.io/github/v/release/bayway/janusmcp?sort=semver)](https://github.com/bayway/janusmcp/releases)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n![Status: alpha](https://img.shields.io/badge/status-alpha-orange)\n[![Website](https://img.shields.io/badge/website-janusmcp.dev-7c8cff)](https://janusmcp.dev)\n\n<br/>\n\n[![Add to Cursor](https://img.shields.io/badge/Add_to-Cursor-0098FF?style=for-the-badge)](cursor://anysphere.cursor-deeplink/mcp/install?name=janusmcp&config=eyJjb21tYW5kIjogIm5weCIsICJhcmdzIjogWyIteSIsICJAYmF5d2F5L2phbnVzbWNwIiwgInNlcnZlIl19)\n[![Install in VS Code](https://img.shields.io/badge/Install-VS_Code-007ACC?style=for-the-badge&logo=visualstudiocode)](https://insiders.vscode.dev/redirect/mcp/install?name=janusmcp&config=%7B%22command%22%3A%20%22npx%22%2C%20%22args%22%3A%20%5B%22-y%22%2C%20%22%40bayway/janusmcp%22%2C%20%22serve%22%5D%7D)\n\n<sub>One-click buttons require the npm package to be published. See <a href=\"RELEASING.md\">RELEASING.md</a>.</sub>\n\n</div>\n\n## The problem\n\nIf you work with more than one company, you use the *same* MCP server (Supabase, GitHub,\nSlack…) with **different identities** — a different account, email and token per client.\nToday most LLM clients hold **one account at a time** per connector: to switch client you\ndisconnect, reconnect, and redo the OAuth login. Every time.\n\nThe MCP protocol has no notion of \"account\": **one session = one identity = one set of\ncredentials.** JanusMCP fills that gap.\n\n## What it does\n\nJanusMCP is a **local multi-account tool broker** for AI agents. It can be used directly\nfrom the CLI or as an MCP server in front of the real upstream servers:\n\n- **Add N accounts once** for the same service and keep them all available.\n- **Switch identity without reconnecting** — no re-login, no fiddling with config.\n- **Works with any LLM client** — it just speaks standard MCP (stdio + Streamable HTTP).\n- **Works without an MCP session too** — agents can drive it **directly from the CLI**\n  ([code-execution mode](#code-execution-mode--context-efficient-tools-from-the-terminal)):\n  `janusmcp tools` / `schema` / `call` invoke tools on demand, with no bulk tool\n  definitions loaded upfront.\n- **Runs locally** — your machine, your keychain, your control.\n- **Keeps the context clean** — it exposes only the *active* account's tools, not N×tools.\n\n```\n                 ┌─────────────────────────────┐   ┌─ Supabase (Client A)\nLLM client ─MCP─▶│   JanusMCP broker           │─▶ ├─ Supabase (Client B)\n(Claude/GPT/     │   active-account · vault ·  │   ├─ GitHub  (Client A)\n Gemini/…)       │   per-session scoping       │   └─ …\n                 └─────────────────────────────┘\n```\n\nYou drive it with three control tools that appear in any client:\n`janus_list_accounts`, `janus_use_account`, `janus_whoami`.\n\n## Choose your mode\n\n### Use from the CLI — Claude Code, Codex, Cursor, scripts\n\n```bash\nnpm install -g @bayway/janusmcp\njanusmcp tools\njanusmcp schema list_tables\njanusmcp call list_tables --args '{\"schemas\":[\"public\"]}' --json --timeout 30s\n```\n\nThe CLI discovers schemas only when needed, accepts JSON through `--args` or stdin,\nsupports explicit accounts/profiles, and provides stable exit codes. See the\n[CLI guide](https://janusmcp.dev/cli/) and [copyable agent instructions](docs/agent-cli.md).\n\n### Connect over MCP — desktop and chat clients\n\n```bash\nnpx @bayway/janusmcp serve\n# or configure a supported client automatically:\njanusmcp install claude-desktop\n```\n\nBoth modes share the same config, OS-keychain vault, OAuth tokens and persisted active\naccount. Use `janusmcp daemon start` to keep upstream sessions warm across repeated CLI calls.\n\n## Install\n\nOnce released, install via your favorite channel (all published automatically on each\ntag — see [RELEASING.md](RELEASING.md)):\n\n```bash\nnpx @bayway/janusmcp serve                       # npm / MCP mode\nbrew install bayway/janusmcp/janusmcp     # Homebrew (macOS/Linux)\nscoop install janusmcp                               # Windows\ndocker run --rm -p 7332:7332 ghcr.io/bayway/janusmcp:latest\n```\n\n…or download a prebuilt binary from [Releases](https://github.com/bayway/janusmcp/releases).\n\n## Build from source (60-second quickstart)\n\n```bash\ngit clone https://github.com/bayway/janusmcp\ncd janusmcp/go\nmake build                       # produces ./bin/janusmcp\ncp config.example.json config.json   # edit with your accounts\n./bin/janusmcp serve             # stdio, for Claude Desktop/Code\n```\n\nTwo Supabase clients, PATs kept in your OS keychain (never in the config):\n\n```bash\n./bin/janusmcp vault set supabase_client_a   # paste the PAT\n./bin/janusmcp vault set supabase_client_b\n```\n\n```jsonc\n// config.json\n{\n  \"bindingMode\": \"session\",\n  \"accounts\": [\n    { \"id\": \"client_a\", \"service\": \"supabase\", \"command\": \"npx\",\n      \"args\": [\"-y\", \"@supabase/mcp-server-supabase@latest\", \"--read-only\", \"--project-ref=REF_A\"],\n      \"env\": { \"SUPABASE_ACCESS_TOKEN\": \"vault:supabase_client_a\" } },\n    { \"id\": \"client_b\", \"service\": \"supabase\", \"command\": \"npx\",\n      \"args\": [\"-y\", \"@supabase/mcp-server-supabase@latest\", \"--read-only\", \"--project-ref=REF_B\"],\n      \"env\": { \"SUPABASE_ACCESS_TOKEN\": \"vault:supabase_client_b\" } }\n  ]\n}\n```\n\nAdd it to Claude Desktop:\n\n```json\n{ \"mcpServers\": { \"janusmcp\": {\n  \"command\": \"/abs/path/janusmcp/go/bin/janusmcp\", \"args\": [\"serve\"],\n  \"env\": { \"JANUS_CONFIG\": \"/abs/path/janusmcp/go/config.json\" } } } }\n```\n\nFor ChatGPT / Gemini / Cursor / Copilot, run HTTP and point them at the URL:\n\n```bash\nJANUS_TRANSPORT=http JANUS_HTTP_PORT=7332 ./bin/janusmcp serve\n# → http://127.0.0.1:7332/mcp\n```\n\n## Commands\n\nRun `janusmcp help` for the full reference. The essentials:\n\n| Command | What it does |\n|---|---|\n| `janusmcp serve` | Run the broker (default). Transports via env: `JANUS_TRANSPORT=stdio\\|http\\|both`, `JANUS_HTTP_HOST`, `JANUS_HTTP_PORT`. |\n| `janusmcp tools [selector]` | Compact tool list for the active (or given) account/profile. `--json` for full definitions; optional `--timeout`. |\n| `janusmcp schema <tool>` | Full JSON definition of one tool. `--account <id\\|profile>` disambiguates; optional `--timeout`. |\n| `janusmcp call <tool>` | Invoke a tool. Supports `--account`, `--args`, stdin, stable `--json`, and optional `--timeout`. |\n| `janusmcp use <account\\|profile>` | Persist the active selector for future CLI commands and new MCP sessions. |\n| `janusmcp daemon start\\|stop\\|restart\\|status` | Manage the optional loopback-only daemon that reuses upstream sessions. |\n| `janusmcp ui` | Open the local control panel — add accounts, log in, set secrets. |\n| `janusmcp add <template> [id]` | Add an account from a template (`janusmcp catalog` lists them). |\n| `janusmcp catalog` | List the built-in account templates. |\n| `janusmcp connect <id>` | Connect an account; for remote OAuth, opens the browser. |\n| `janusmcp status` | Show each account's login/secret status (no secret values). |\n| `janusmcp vault set <name>` / `delete <name>` | Store / remove a secret in the OS keychain. |\n| `janusmcp login <provider> <name>` | OAuth loopback login; token referenced as `oauth:<name>`. |\n| `janusmcp providers` | List built-in OAuth providers. |\n| `janusmcp install <client>` | Configure an LLM client to launch JanusMCP. |\n| `janusmcp uninstall <client>` | Remove JanusMCP from an LLM client's config. |\n| `janusmcp version` · `janusmcp help` | Version · this reference. |\n\nSupported `<client>` values for `install` / `uninstall`: `claude-desktop`, `claude-code`,\n`cursor`, `vscode`, `gemini`, `codex`, `chatgpt`, `print`. Run `janusmcp install list`\n(or `uninstall list`) to see each target and whether it's already configured.\n\n```bash\njanusmcp install claude-desktop      # one-command setup\njanusmcp uninstall claude-desktop    # clean removal (restart the client afterwards)\n```\n\nInside any connected client you also get the control tools `janus_list_accounts`,\n`janus_use_account`, `janus_whoami`, `janus_login`, `janus_use_profile`, and\n`janus_with_account`.\n\n### Profiles — a whole client's stack at once\n\nA **profile** groups accounts of the same client across different services. Activating\nit exposes the tools of *all* its accounts together, and each call is routed to the\nright upstream:\n\n```jsonc\n// config.json\n{\n  \"accounts\": [\n    { \"id\": \"supabase_a\", \"service\": \"supabase\", \"transport\": \"http\", \"url\": \"https://mcp.supabase.com/mcp\", \"auth\": \"oauth\" },\n    { \"id\": \"github_a\",   \"service\": \"github\",   \"transport\": \"http\", \"url\": \"https://api.githubcopilot.com/mcp/\", \"auth\": \"oauth\" }\n  ],\n  \"profiles\": {\n    \"client_a\": [\"supabase_a\", \"github_a\"]\n  }\n}\n```\n\nThen in chat: `janus_use_profile` with `{ \"profile\": \"client_a\" }` → Supabase **and**\nGitHub tools for Client A are available simultaneously. Colliding tool names across\naccounts are namespaced (`<account>_<tool>`).\n\n### One-shot cross-account calls\n\n`janus_with_account` runs a single call on another account **without** changing the\nactive one — e.g. `{ \"account_id\": \"client_b\", \"tool\": \"list_tables\" }`. Omit `tool`\nto list that account's available tools first.\n\n### Code-execution mode — context-efficient tools from the terminal\n\nLoading every MCP tool definition into an LLM context is expensive. In code-execution\nmode an agent (or you) invokes tools **on demand from the shell** instead — à la\n[\"code execution with MCP\"](https://www.anthropic.com/engineering/code-execution-with-mcp) —\nso the context holds only the results it actually asked for:\n\n```bash\njanusmcp tools                        # compact list for the active account/profile\njanusmcp tools client_a               # ...or any account/profile explicitly\njanusmcp schema list_tables           # full input schema of ONE tool, only when needed\njanusmcp call list_tables --args '{\"schemas\":[\"public\"]}'\njanusmcp call ping --account azienda_b          # cross-account without switching\necho '{\"sql\":\"select 1\"}' | janusmcp call db_query   # JSON args via stdin too\njanusmcp call ping --json --timeout 30s         # stable envelope for agents\n```\n\n`call` prints the tool's text content to stdout and exits non-zero on a tool error, so\nit composes with pipes and scripts. Selectors resolve exactly like in the broker: the\npersisted active account by default, or any account id / profile name; a name that\ncollides across a profile's accounts must be disambiguated with `--account`. Secrets\nresolve through the same vault/OAuth stack as `serve` — nothing extra to configure.\n\nThis makes JanusMCP a first-class citizen for **CLI-driven agents** (Claude Code,\nCodex, Cursor agents, or any agent with shell access): instead of registering it as\nan MCP server, just tell the agent that `janusmcp tools` / `schema` / `call` exist.\nDiscovery, schemas and invocation happen on demand, credentials stay in the keychain,\nand multi-account switching works the same as over MCP. Both modes share the config\nand the persisted active account, so you can mix them freely.\n\nFor repeated calls, `janusmcp daemon start` launches an authenticated loopback-only\nbroker. `tools`, `schema`, and `call` auto-detect it and reuse its upstream sessions;\n`--direct` bypasses it and `--daemon` requires it. Set `JANUS_DAEMON=auto|require|off`\nto choose a default policy.\n\n## Key features\n\n| | |\n|---|---|\n| **Multi-account, one endpoint** | N identities for the same service, no reconnecting |\n| **Identity scoping** | per-call → per-session → global, via `bindingMode: global \\| session \\| locked`. Session scope needs a real connection: stdio and legacy HTTP have one; MCP 2026-07-28 removed sessions, so there it is per-call (`janus_with_account`) or global |\n| **Dual transport** | stdio (local-first clients) + Streamable HTTP (remote-first clients), same process. HTTP serves MCP 2026-07-28 and every earlier revision, each on the transport it requires |\n| **Secure vault** | OS keychain (macOS/Windows/Linux) + encrypted-file fallback; secrets as `vault:<name>` |\n| **OAuth loopback** | `janusmcp login` (PKCE), tokens stored in the vault, auto-refresh, `oauth:<name>` |\n| **Context-safe** | only the active account's tools are exposed; switching emits `tools/list_changed` |\n| **MCP *and* CLI** | same broker as an MCP server or via `janusmcp tools` / `schema` / `call` — no bulk tool definitions loaded upfront |\n\n## How it's different\n\nThe MCP gateway space (MetaMCP, mcp-proxy, IBM ContextForge, …) aggregates *different*\nservers behind one endpoint. JanusMCP solves the orthogonal, under-served problem:\n**many identities for the same service**, without saturating the model's context, from any\nLLM, fully local. It's a credential-aware broker, not a flat aggregator.\n\n## Built-in connectors\n\nScaffold an account from a ready-made template with `janusmcp add <template>` (run\n`janusmcp catalog` for the full, up-to-date list). Most use browser OAuth (dynamic client\nregistration); a few need extra setup, noted below.\n\n- **Remote, browser login (OAuth):** `supabase`, `github`, `notion`, `sentry`, `stripe`,\n  `hubspot`, `paypal`, `linear`, `vercel`, `canva`, `neon`, `netlify`, `zapier`.\n- **SSE transport (legacy):** `asana`, `monday`, `intercom`, `webflow`, `wix`, `square`,\n  `globalping`.\n- **Cloudflare (Streamable HTTP):** `cloudflare-bindings`, `cloudflare-observability`,\n  `cloudflare-radar`, `cloudflare-builds`, `cloudflare-browser`.\n- **Google Workspace (bring-your-own OAuth client):** `gmail`, `google-drive`,\n  `google-calendar`, `google-chat` — see [`go/docs/google-workspace.md`](go/docs/google-workspace.md).\n- **Per-account URL:** `activecampaign` (paste your Remote MCP URL).\n- **Figma:** `figma-desktop` (local, recommended) and `figma` (remote, restricted — see below).\n- **Generic building blocks:** `http-oauth`, `sse-oauth`, `supabase-pat`, `stdio`.\n\nMissing one? Add any remote server with `http-oauth` / `sse-oauth`, any local one with\n`stdio`, or define your own template in `~/.config/janusmcp/templates.json`.\n\n## Provider notes\n\n### ActiveCampaign\n\nActiveCampaign ships an **official remote MCP server** with a **unique URL per account**\n(ActiveCampaign → *Settings → Developer → Remote MCP URL*) and browser-based OAuth — a\nnatural fit for the multi-account broker. Add one account per client:\n\n```bash\njanusmcp add activecampaign ac_clientA   # then paste that client's Remote MCP URL in config.json\njanusmcp connect ac_clientA              # browser login\n```\n\nBecause the URL is per-account, the template seeds a `REPLACE_ACTIVECAMPAIGN_MCP_URL`\nplaceholder you must replace with your own URL. Login uses dynamic client registration, so\nno client ID/secret is needed.\n\n### Google Workspace (Gmail / Drive / Calendar / Chat)\n\nGoogle offers **remote MCP servers** for Gmail, Drive, Calendar and Chat, but — unlike most\nproviders here — they require **your own OAuth client** (created in the Google Cloud\nConsole); they don't support dynamic client registration. JanusMCP supports this via the\n`oauthClientId` / `oauthClientSecret` / `scopes` fields, preset by the `gmail`,\n`google-drive`, `google-calendar` and `google-chat` templates:\n\n```bash\nexport GOOGLE_OAUTH_CLIENT_ID=... GOOGLE_OAUTH_CLIENT_SECRET=...\njanusmcp add gmail gmail_clientA\njanusmcp connect gmail_clientA           # browser login as client A\n```\n\nFull one-time Google Cloud setup (enable MCP APIs, consent screen, Desktop OAuth client)\nand scope details are in [`go/docs/google-workspace.md`](go/docs/google-workspace.md).\n\n### Figma\n\nFigma offers two MCP servers, handled differently here:\n\n- **Local Dev Mode server (recommended).** Figma's desktop app hosts an MCP server on\n  `http://127.0.0.1:3845/mcp`. It's local, needs no OAuth, and works out of the box:\n  enable it in the desktop app (Dev Mode → Inspect → *Enable desktop MCP server*) and add it\n  with `janusmcp add figma-desktop figma_work`. Requires a Dev/Full seat on a paid Figma plan.\n\n- **Remote server (`https://mcp.figma.com/mcp`) — restricted.** Figma **allowlists the OAuth\n  `client_name`** during dynamic client registration and returns **403 Forbidden** to any client\n  that isn't in its [MCP catalog](https://www.figma.com/mcp-catalog/) (VS Code, Cursor, Claude\n  Code, …). JanusMCP is not (yet) an approved client.\n\n  > ⚠️ **Workaround — opt-in, use at your own risk.** You can make JanusMCP register under an\n  > approved name by setting `\"clientName\": \"Claude Code\"` on a remote `figma` account in your\n  > `config.json`. This impersonates an approved client and **may violate Figma's Terms of\n  > Service**; it can also break whenever Figma updates its allowlist. It is **not** enabled by\n  > default. Prefer the local Dev Mode server above for real work.\n\n  The proper long-term fix is for JanusMCP to be submitted to and approved for Figma's MCP\n  catalog, so no `client_name` override is needed. This is planned.\n\n## Status & roadmap\n\nAlpha — the core is implemented and tested in Go.\n\n- [x] Active-account model, per-session / global / locked scoping\n- [x] stdio + Streamable HTTP transports\n- [x] MCP 2026-07-28 (stateless core) on both transports, legacy revisions unchanged\n- [x] OS-keychain vault + encrypted-file fallback\n- [x] OAuth loopback (PKCE) with auto-refresh and per-spawn token resolution\n- [x] One-command client install (`janusmcp install …`), Claude Desktop `.mcpb`, registry `server.json`\n- [x] Multi-server \"profiles\" per client (Supabase + GitHub + Slack of Client A at once)\n- [x] `with_account` one-shot cross-account calls\n- [x] CLI / code-execution mode (`janusmcp tools` / `schema` / `call`) — invoke tools on\n      demand instead of loading all definitions, to cut token usage\n- [x] SSE upstream transport (in addition to Streamable HTTP + stdio) for SSE-only servers\n- [x] Pre-registered OAuth clients (bring-your-own client for servers without dynamic client registration, e.g. Google Workspace)\n- [x] Built-in connector catalog (25+ services) via `janusmcp catalog` / `add`\n- [ ] Signed, per-OS release binaries & registry auto-publish in CI\n\nSee [`design-broker-mcp-multi-account.md`](design-broker-mcp-multi-account.md) for the full design.\n\n## Repository layout\n\n- [`go/`](go/) — the broker (Go). This is the real implementation. **[Build & docs →](go/README.md)**\n- [`spike/`](spike/) — the original TypeScript spike, kept as a verified reference of behavior.\n- [`design-broker-mcp-multi-account.md`](design-broker-mcp-multi-account.md) — architecture & rationale.\n- [`docs/`](docs/) — current architecture, compatibility contract, testing, ADRs, and operations.\n\n## Project documentation\n\n- [Documentation index](docs/README.md)\n- [Architecture](docs/architecture.md)\n- [Compatibility contract](docs/compatibility.md)\n- [Architecture Decision Records](docs/adr/README.md)\n- [Testing](docs/testing.md)\n- [Changelog](CHANGELOG.md)\n- [Contributing](CONTRIBUTING.md) and [security policy](SECURITY.md)\n\n## Privacy Policy\n\nJanusMCP runs entirely on your machine. It has **no backend servers, collects no data, and\ncontains no analytics or telemetry** — the developers receive nothing about you or your usage.\nCredentials and tokens are stored in your OS keychain (or, if you opt in, an encrypted local\nfile) and are used only to authenticate to the services you configure; they never pass through\nthe model context. Network connections are made only to the MCP servers and OAuth providers you\nconfigure. Because everything is local, data is retained only on your own device for as long as\nyou keep it, and removing it (`janusmcp vault delete <name>`, or uninstalling) removes it\nentirely.\n\nFull policy: <https://janusmcp.dev/privacy>.\n\n## Contributing\n\nContributions are very welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). New connector\npresets, client integration guides, and packaging help are especially appreciated.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n",
  "bytes": 20113,
  "sha": "7a225bdea1869312d81f5ae90722d2e2dc758449f6410928dc885248c144ecd9",
  "repo_slug": "bayway/janusmcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_bayway_janusmcp_f52b486d/readme"
}