Skip to content

Commit d614853

Browse files
authored
feat: workspace-root routing + Tool Optimization (@mux) self-management + UI live-sync (#151)
Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>
1 parent 661f162 commit d614853

221 files changed

Lines changed: 22933 additions & 9626 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1-
blank_issues_enabled: false
1+
blank_issues_enabled: true
22
contact_links:
33
- name: Questions & Help
44
url: https://github.com/mcpmux/mcp-mux/discussions/categories/q-a
55
about: Ask questions and get help in GitHub Discussions
66
- name: Feature Ideas
77
url: https://github.com/mcpmux/mcp-mux/discussions/categories/ideas
88
about: Share and discuss feature ideas
9+
- name: Contribute a Server Definition (PR)
10+
url: https://github.com/mcpmux/mcp-servers/blob/main/CONTRIBUTING.md
11+
about: Server definitions live in the mcp-servers repo and land via PR — read the guide
12+
- name: Request a Server
13+
url: https://github.com/mcpmux/mcp-servers/issues/new?template=request-server.yml
14+
about: Ask the community to add an MCP server to the registry
15+
- name: Report a Server Definition Bug
16+
url: https://github.com/mcpmux/mcp-servers/issues/new?template=bug-report.yml
17+
about: Found a broken or incorrect server in the registry? Report it here

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,12 @@ jobs:
387387
if: steps.playwright-cache.outputs.cache-hit != 'true'
388388
run: pnpm exec playwright install --with-deps chromium
389389

390+
# TODO(playwright-migration): the web E2E suite has stale assertions from
391+
# the IA redesign and is being replaced (tauri-playwright spike on
392+
# spike/playwright-e2e). Non-blocking until that lands so it doesn't gate
393+
# PRs on pre-existing failures; results still surface via the report below.
390394
- name: Run web-only E2E tests
395+
continue-on-error: true
391396
run: pnpm test:e2e:web --project=chromium
392397

393398
- name: Upload E2E web test results

.github/workflows/e2e-desktop.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,12 @@ jobs:
112112
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
113113
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
114114

115+
# TODO(playwright-migration): desktop E2E has stale assertions from the IA
116+
# redesign and is being replaced (tauri-playwright spike). Non-blocking
117+
# until then; results still surface via the report job below.
115118
- name: Run desktop E2E tests (Linux)
116119
if: matrix.os == 'ubuntu-latest'
120+
continue-on-error: true
117121
run: |
118122
# Start dbus session and unlock gnome-keyring with a dummy password for CI.
119123
# Two-step process: unlock creates the login keyring, start exports env vars.
@@ -187,6 +191,7 @@ jobs:
187191
188192
- name: Run desktop E2E tests (Windows)
189193
if: matrix.os == 'windows-latest'
194+
continue-on-error: true
190195
run: pnpm test:e2e
191196

192197
# Upload test results and artifacts

AGENTS.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# AGENTS.md
2+
3+
Guidance for coding agents working inside the `mcp-mux` repo — the McpMux desktop app and local gateway. Complements [`README.md`](README.md) and [`CONTRIBUTING.md`](CONTRIBUTING.md); when anything here conflicts with an explicit user instruction in the current session, the user wins.
4+
5+
## Project Overview
6+
7+
McpMux is a Tauri 2 desktop app (Rust + React 19) with a local Axum HTTP gateway on `localhost:45818`. It lets users configure MCP servers once and connect every AI client (Cursor, Claude Desktop, VS Code, Windsurf) through a single endpoint, with credentials encrypted in the OS keychain instead of plain-text JSON files.
8+
9+
A more detailed map of the workspace lives in [`CLAUDE.md`](CLAUDE.md) at the repo root — read it for the crate layout, frontend architecture, and cross-project context. This file captures the minimum an agent needs to make safe, useful changes here.
10+
11+
## Workspace Layout
12+
13+
```
14+
mcp-mux/
15+
├── apps/desktop/ # Tauri shell — React frontend (src/) + Rust Tauri commands (src-tauri/)
16+
├── crates/
17+
│ ├── mcpmux-core/ # Domain entities, repository traits, service layer, EventBus
18+
│ ├── mcpmux-gateway/ # Axum gateway — routing, OAuth refresh, FeatureSet filtering
19+
│ ├── mcpmux-storage/ # SQLite + AES-256-GCM field encryption + OS keychain
20+
│ └── mcpmux-mcp/ # MCP protocol client wrapper (rmcp SDK)
21+
├── packages/ui/ # Shared UI components (`@mcpmux/ui`)
22+
├── schemas/ # JSON Schemas surfaced in the Monaco editor
23+
└── tests/ # Rust integration, TS unit (vitest), desktop E2E (WDIO), web E2E (playwright)
24+
```
25+
26+
## Build & Dev Commands
27+
28+
Run everything from `mcp-mux/`:
29+
30+
| Command | What it does |
31+
|---------|--------------|
32+
| `pnpm setup` | First-time dev environment setup (PowerShell on Windows). |
33+
| `pnpm dev` | Tauri desktop dev mode (Rust + React hot-reload). |
34+
| `pnpm dev:web` | Web UI only via Vite — no Rust, no Tauri shell. |
35+
| `pnpm build` | Production Tauri build for the current platform. |
36+
| `pnpm validate` | Full correctness gate — runs the items below in sequence. |
37+
| `pnpm lint` | ESLint (recursive) + `cargo clippy --workspace -- -D warnings`. |
38+
| `pnpm lint:fix` | Auto-fix lint issues. |
39+
| `pnpm format` | `prettier --write .` + `cargo fmt --all`. |
40+
| `pnpm format:check` | Formatting check (no writes). |
41+
| `pnpm typecheck` | Recursive TypeScript typecheck. |
42+
43+
**Before claiming a change is done**, run `pnpm validate` (or the relevant subset) — it mirrors what CI enforces.
44+
45+
## Testing
46+
47+
| Command | Scope |
48+
|---------|-------|
49+
| `pnpm test` | Rust + TypeScript, everything. |
50+
| `pnpm test:rust` | `cargo nextest run --workspace`. |
51+
| `pnpm test:rust:unit` | `cargo nextest run --workspace --lib`. |
52+
| `pnpm test:rust:int` | `cargo nextest run -p tests` — integration crate in `tests/rust`. |
53+
| `pnpm test:rust:doc` | `cargo test --workspace --doc`. |
54+
| `pnpm test:ts` | Vitest run (`tests/ts/vitest.config.ts`). |
55+
| `pnpm test:ts:watch` | Vitest watch. |
56+
| `pnpm test:e2e` | Desktop E2E via WebDriver IO — requires `MCPMUX_REGISTRY_URL`. |
57+
| `pnpm test:e2e:file -- tests/e2e/specs/foo.ts` | One WDIO spec file. |
58+
| `pnpm test:e2e:grep -- "test name"` | WDIO tests matching a name. |
59+
| `pnpm test:e2e:web` | Playwright on the web UI. |
60+
| `pnpm test:coverage` | `cargo llvm-cov` + Vitest coverage. |
61+
62+
Prefer narrow commands over `pnpm test` while iterating — the full suite is slow.
63+
64+
## Code Style
65+
66+
- **Rust:** 100-char max width, 4-space indent. Clippy runs with `avoid-breaking-exported-api = false`; all warnings are denied in CI.
67+
- **TypeScript / JSX:** Prettier — single quotes, 2-space indent, 100-char width, trailing commas (es5), Tailwind CSS plugin for class ordering.
68+
- **Path aliases:** `@/``apps/desktop/src/`; `@mcpmux/ui``packages/ui`.
69+
- **No emojis in code or commits** unless the user explicitly asks for them.
70+
- **Comments:** only when the *why* is non-obvious. Identifiers should explain the *what*.
71+
72+
## Commit & PR Guidelines
73+
74+
- Commits must be **signed off** (DCO): `git commit -s -m "..."`. CI rejects unsigned commits.
75+
- Prefer conventional-style subjects — releases use release-please for semantic versioning.
76+
- PRs follow [`.github/pull_request_template.md`](.github/pull_request_template.md): describe the change, how you tested, and check the `pnpm test` / `pnpm lint` / `pnpm typecheck` boxes.
77+
- Don't bypass hooks (`--no-verify`) or DCO signing unless explicitly told to.
78+
79+
## Platform Gotchas
80+
81+
### Child-process flags
82+
83+
Anything that spawns a child process (stdio MCP servers, installers, etc.) **must** go through `mcpmux_gateway::pool::transport::configure_child_process_platform()`. That helper applies:
84+
85+
- **Windows:** `CREATE_NO_WINDOW` (`0x08000000`) — release builds use `windows_subsystem = "windows"`, so without this the OS briefly flashes a console window when a child starts.
86+
- **Unix:** `process_group(0)` — stops SIGINT/SIGTSTP from the parent terminal from tearing down the child.
87+
88+
`tokio::process::Command` already exposes `creation_flags()` (Windows) and `process_group()` (Unix). **Do not** import `std::os::*::process::CommandExt` — those traits are unused with Tokio's `Command` and trigger clippy.
89+
90+
### Cross-platform CI
91+
92+
- The pre-commit hook runs `cargo clippy --workspace -- -D warnings` on your dev machine.
93+
- `#[cfg(unix)]` only compiles on Unix; `#[cfg(windows)]` only on Windows. CI is Linux, so Windows-gated code is **not** linted in CI, and Unix-gated code is not linted on a Windows dev box.
94+
- When you touch platform-conditional code, check the *other* platform compiles before pushing — CI won't catch a Windows-only clippy regression.
95+
96+
### Secret handling
97+
98+
- Never log tokens, API keys, headers with auth material, or raw OAuth responses. Use the existing sanitised-log helpers in `mcpmux-gateway`.
99+
- Credentials encrypt at rest via AES-256-GCM in SQLite plus DPAPI (Windows) / OS keychain (macOS, Linux). Don't add new code paths that persist secrets any other way.
100+
- Secrets should be wiped from memory after use via `zeroize`.
101+
- The gateway binds to `127.0.0.1`. Don't bind to `0.0.0.0` or expose it on the network.
102+
103+
## Frontend Notes
104+
105+
- Entry point: `apps/desktop/src/main.tsx``App.tsx`.
106+
- Global state: a single Zustand store at `src/stores/appStore.ts`.
107+
- Key hooks: `useServerManager` (server CRUD), `useSpaces` (workspace switching), `useDomainEvents` (Rust-side EventBus listener), `useDataSync`.
108+
- UI: React 19, Tailwind CSS, Lucide icons, Monaco Editor for JSON config surfaces.
109+
- Open external URLs through `openExternal` in `apps/desktop/src/lib/contribute.ts` — it routes through the Tauri opener plugin so links open in the user's default browser, not the webview.
110+
- For UI changes, launch `pnpm dev` and exercise the feature in the running app before reporting done — typecheck and tests verify correctness, not UX regressions.
111+
112+
## Rust Architecture Cues
113+
114+
- Cross-layer communication goes through the `EventBus` in `mcpmux-core`. Prefer emitting a domain event over reaching across module boundaries directly.
115+
- Storage is behind repository traits — don't call SQLx or SQLite APIs directly from gateway or app code; add or use a repo method.
116+
- Services are wired up via the `ApplicationServices` builders in `mcpmux-core`. New services should follow the same DI pattern.
117+
118+
## MCP Specification
119+
120+
The full MCP spec is vendored at `../modelcontextprotocol/docs/specification/`. Default to the latest stable version (`2025-11-25`) and **read the relevant section before** implementing or modifying protocol behaviour (transports, lifecycle, capability negotiation, OAuth flows, tools / resources / prompts). For features targeting a specific protocol version, use that version's folder.
121+
122+
## Server Definitions
123+
124+
Server catalog entries live in the separate [`mcp-servers`](https://github.com/mcpmux/mcp-servers) repo — **not here**. If a task involves adding, editing, or fixing a server definition, switch to that repo and follow its `AGENTS.md`.
125+
126+
## Things Not To Do
127+
128+
- Don't add backwards-compatibility shims, deprecated aliases, or `// removed` placeholder comments when removing code — delete it cleanly.
129+
- Don't introduce new fallbacks or input validation for states that are already framework-guaranteed. Trust internal invariants; validate only at the boundary (user input, external APIs).
130+
- Don't edit generated files: `CHANGELOG.md`, release-please manifests, `bundle/*.json` in sibling repos, `packages/ui/dist`.
131+
- Don't commit screenshots, videos, or large binaries to the repo — link out instead.

Cargo.lock

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ os_pipe = "1"
5858

5959
# MCP Protocol
6060
# NOTE: Never use local path dependency - E:\one-mcp\rust-sdk is for source lookup only
61-
rmcp = { version = "0.17.0", features = [
61+
rmcp = { version = "1.5", features = [
6262
"client",
6363
"server",
6464
"transport-io",

README.md

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ Lightweight and cross-platform — built in Rust with Tauri 2, McpMux uses minim
7979

8080
**3.** Done. Every tool from every server is available in every client, right now.
8181

82-
McpMux routes calls to the right server, refreshes OAuth tokens automatically, and keeps credentials encrypted in your OS keychain — you never think about it again.
82+
McpMux routes calls to the right server, refreshes OAuth tokens automatically, and keeps credentials encrypted in your OS keychain — you never think about it again. It also keeps **itself** current: new versions download and install on launch by default (toggle in Settings), so a restart is all it takes.
8383

8484
---
8585

@@ -107,17 +107,41 @@ Create isolated Spaces — each with their own servers, credentials, and permiss
107107

108108
![Workspaces — switch context instantly from the sidebar](docs/screenshots/space-switcher.png)
109109

110+
### Different Tools for Different Folders
111+
112+
Your AI client tells McpMux which folder it's working in (its MCP *root*). McpMux uses that to **route each workspace to its own toolset** — open your backend repo and the AI sees your database and deploy tools; open a docs folder and it sees only search and filesystem. Map a folder once in the **Workspaces** tab (or let the AI do it — see below) and every future session from that exact path resolves automatically. Matching is per-folder and exact, so nothing leaks across projects.
113+
114+
![Workspaces — map a folder to the Space and FeatureSet it should get](docs/screenshots/workspaces.png)
115+
110116
### Control What Each Client Can Do
111117

112-
Not every AI client should have the same power. Create Feature Sets — permission bundles that control exactly which tools, prompts, and resources a client can access. Build a "Read Only" set for cautious workflows, a "React Development" set with just GitHub and Filesystem, or a "Full Stack Dev" set with everything. Assign them per-client so each tool only goes where you want it.
118+
Not every AI client should have the same power. Create Feature Sets — curated bundles that control exactly which tools, prompts, and resources are exposed. Build a "Read Only" set for cautious workflows, a "React Development" set with just GitHub and Filesystem, or a "Full Stack Dev" set with everything — then route a folder to it via a Workspace mapping. A FeatureSet's included features *are* the effective toolset a session resolves to.
113119

114-
![Feature Sets — granular per-server tool selection](docs/screenshots/featureset-detail.png)
120+
![Feature Sets — pick exactly which tools each bundle exposes, per server](docs/screenshots/featureset-detail.png)
115121

116122
### See and Manage Every Connected Client
117123

118-
Cursor, VS Code, Windsurf, Claude Code — see every AI client connected to your gateway in real time. Click any client to manage its workspace, grant or revoke feature sets, and see exactly which tools it can access. New clients authenticate via OAuth with a one-click approval flow.
124+
Cursor, VS Code, Windsurf, Claude Code — see every AI app connected to your gateway in real time, with live status. Routing is **workspace-driven**: each app's toolset is decided by the Workspace binding for the folder it reports, not configured per app. Open any app to rename it, see how it's routed, or revoke its connection. New apps authenticate via OAuth with a one-click approval flow.
125+
126+
![Connected apps — routing is workspace-driven per reported folder](docs/screenshots/client-detail.png)
127+
128+
### Let Your AI Curate Its Own Toolset
129+
130+
Hand an assistant a hundred tools and it burns tokens and reaches for the wrong one. McpMux ships a built-in **Tool Optimization** capability so the AI can keep *itself* lean — straight from chat, no config files.
131+
132+
Start a request with **`@mux`** and the assistant can:
133+
134+
- **Discover** what's available — `mcpmux_list_spaces`, `mcpmux_list_all_tools`, `mcpmux_search_tools`
135+
- **Compose** a focused FeatureSet of just the tools it needs — `mcpmux_manage_feature_set`
136+
- **Pin** the current folder to that set so it sticks — `mcpmux_bind_current_workspace`
137+
138+
![Tool Optimization — the built-in self-management tools the AI drives, reads silent and writes gated](docs/screenshots/tool-optimization.png)
139+
140+
Reads are silent; anything that changes your setup pops a **one-click approval dialog that names the exact Space** — the AI proposes, you decide. The `@mux` trigger keeps these requests cleanly separated from your real work, and every operation can target a specific Space by id.
141+
142+
![Approval — every self-management write asks first, showing the target Space and the exact tool diff](docs/screenshots/meta-tool-approval.png)
119143

120-
![Client Management — per-client permissions and effective features](docs/screenshots/client-detail.png)
144+
> *"@mux build a minimal toolset for this Next.js repo and pin it to this folder."*
121145
122146
---
123147

0 commit comments

Comments
 (0)