This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This repository is indexed for semantic code search via the claude-context MCP server. Prefer mcp__claude-context__search_code (with path D:\mcpmux) over Grep/Glob when looking for implementations, understanding how features work, or finding related code across the codebase. Use Grep/Glob for exact string matches or filename patterns. If search returns an indexing error, re-index with mcp__claude-context__index_codebase first.
McpMux is a desktop app + local gateway that lets users configure MCP servers once and connect every AI client (Cursor, Claude Desktop, VS Code, Windsurf) through a single localhost:45818 endpoint. Credentials are encrypted in the OS keychain instead of plain-text JSON files.
This is a multi-project workspace with 6 independent projects (not a unified monorepo):
| Project | Tech | Purpose |
|---|---|---|
mcp-mux/ |
Tauri 2 (Rust + React 19), pnpm workspace | Desktop app + local MCP gateway |
mcpmux.bundler/ |
Cloudflare Worker | GitHub webhook receiver that processes server definitions into D1/R2 |
mcpmux.serverhub.api/ |
Cloudflare Worker (Hono) | REST API for server registry discovery (KV -> D1 -> R2 fallback chain) |
mcpmux.discover.ui/ |
Next.js 16, shadcn/ui, Tailwind 4 | Web UI for browsing the server registry |
mcp-servers/ |
JSON + AJV validation | Community MCP server definitions repository |
mcpmux.space/ |
Docs | Documentation and design space |
All commands run from mcp-mux/:
pnpm setup # First-time dev environment setup (PowerShell)
pnpm dev # Tauri desktop app dev mode (Rust + React hot-reload)
pnpm dev:web # Web UI only (Vite, no Rust)
pnpm build # Production Tauri build (all platforms)pnpm test # All tests (Rust + TypeScript)
pnpm test:rust # cargo nextest run --workspace
pnpm test:rust:unit # cargo nextest run --workspace --lib
pnpm test:rust:int # cargo nextest run -p tests
pnpm test:rust:doc # cargo test --workspace --doc
pnpm test:ts # vitest run -c tests/ts/vitest.config.ts
pnpm test:ts:watch # vitest watch mode
pnpm test:e2e # WebDriver IO desktop E2E (needs MCPMUX_REGISTRY_URL)
pnpm test:e2e:file # Single E2E spec: pnpm test:e2e:file -- tests/e2e/specs/foo.ts
pnpm test:e2e:grep # E2E by name: pnpm test:e2e:grep -- "test name"
pnpm test:e2e:web # Playwright web UI E2E
pnpm test:coverage # cargo llvm-cov + vitest coveragepnpm validate # Full check: cargo fmt + clippy + check + eslint + typecheck
pnpm lint # ESLint (recursive) + cargo clippy --workspace -- -D warnings
pnpm lint:fix # Auto-fix lint issues
pnpm format # prettier --write . && cargo fmt --all
pnpm format:check # Check formatting without modifying
pnpm typecheck # TypeScript type checking (recursive)The Cargo workspace has 4 library crates + 1 app crate + 1 test crate:
- mcpmux-core (
crates/mcpmux-core/) - Domain layer: entities (Space, InstalledServer, FeatureSet, Client), repository traits, domain services, application services with event emission, and the central EventBus - mcpmux-gateway (
crates/mcpmux-gateway/) - Axum HTTP gateway: routes MCP calls to correct servers, manages OAuth 2.1+PKCE token refresh, filters tools/resources/prompts based on FeatureSets, per-client access key auth, server connection pooling - mcpmux-storage (
crates/mcpmux-storage/) - SQLite persistence with AES-256-GCM field-level encryption via ring, typed credential rows (per-token encryption), DPAPI key storage on Windows (keychain_dpapi.rs), OS keychain on macOS/Linux via keyring crate, zeroize for secure memory clearing - mcpmux-mcp (
crates/mcpmux-mcp/) - MCP protocol client management using rmcp SDK - apps/desktop/src-tauri - Tauri 2 app shell, Tauri commands, system tray, deep-link handler (
mcpmux://) - tests/rust - Integration test crate
Key patterns: event-driven architecture (EventBus), repository pattern (trait-based storage abstraction), service layer pattern with DI via ApplicationServices builders.
- Entry:
apps/desktop/src/main.tsx->App.tsx - State: Zustand store (
stores/appStore.ts) - Hooks:
useServerManager(server CRUD),useSpaces(workspace switching),useDomainEvents(Rust event listeners),useDataSync(data synchronization) - UI: React 19 + Tailwind CSS + Lucide icons + Monaco Editor (config editing)
- Path aliases:
@/->src/,@mcpmux/ui-> shared UI package
AI Clients -> McpMux Gateway (localhost:45818/mcp) -> MCP Servers (stdio/HTTP)
|
Authenticates (access keys)
Routes (per-space server config)
Filters (FeatureSet permissions)
OAuth token refresh (automatic)
Credentials (DPAPI files on Windows / OS Keychain on macOS+Linux + encrypted SQLite)
Rust 1.75+, Node.js 20+, pnpm 9+. Linux: gnome-keyring libsecret-1-dev librsvg2-dev pkg-config.
- Rust: 100 char max width, 4-space indent,
clippywithavoid-breaking-exported-api = false - TypeScript/JSX: Prettier with single quotes, 2-space indent, 100 char width, trailing commas (es5), Tailwind CSS plugin
- Commits require
Signed-off-byline (usegit commit -s)
All commands run from mcp-servers/ (sibling repo):
pnpm install # Install dependencies (vitest, ajv, glob)
pnpm validate:all # Validate all server definitions against JSON schema
pnpm validate <file> # Validate specific server definition file(s)
pnpm build # Build registry bundle (bundle/bundle.json)
pnpm test # Run all tests (schema validation, consistency, categories, bundle)The JSON schema at schemas/server-definition.schema.json defines the structure for server definitions in servers/. Input definitions support: id, label, type, required, secret, description, default, placeholder, and obtain (with url, instructions, button_label).
Each worker is an independent project with its own package.json:
mcpmux.serverhub.api/ - Hono-based registry API:
cd mcpmux.serverhub.api && pnpm dev # wrangler dev
cd mcpmux.serverhub.api && pnpm test # vitest (cloudflare pool)mcpmux.bundler/ - Webhook-triggered bundle processor:
cd mcpmux.bundler && pnpm dev # wrangler dev
cd mcpmux.bundler && pnpm test # vitest runcd mcpmux.discover.ui && pnpm dev # next dev
cd mcpmux.discover.ui && pnpm test # vitest
cd mcpmux.discover.ui && pnpm test:e2e # playwrightWhen spawning child processes (e.g., stdio MCP servers), always use configure_child_process_platform() from mcpmux_gateway::pool::transport. This applies:
- Windows:
CREATE_NO_WINDOW(0x08000000) — prevents visible console windows in release builds (wherewindows_subsystem = "windows"means the app is a GUI subsystem process) - Unix:
process_group(0)— isolates child from parent terminal signals (SIGINT, SIGTSTP)
Note: tokio::process::Command already exposes creation_flags() (Windows) and process_group() (Unix) natively — do not import std::os::unix::process::CommandExt or std::os::windows::process::CommandExt as the traits are unused with Tokio's Command.
The pre-commit hook runs cargo clippy --workspace -- -D warnings locally, but #[cfg(unix)] / #[cfg(windows)] blocks are only compiled on the matching platform. CI runs on Linux, so:
#[cfg(unix)]code is only linted in CI, not on a Windows dev machine#[cfg(windows)]code is only linted locally on Windows, not in CI- Always validate that platform-conditional code compiles correctly on both platforms before pushing
GitHub Actions runs on push/PR to main: Rust format + clippy + check, ESLint + typecheck, cargo nextest, vitest, desktop E2E (Windows/macOS/Linux), web E2E (Playwright). Releases use release-please for semantic versioning with multi-platform Tauri builds.