mcpx is an HTTP-first Model Context Protocol (MCP) gateway and cross-client installer. This is a monorepo with two primary packages:
cli/— ThemcpxCLI and core library (@kwonye/mcpx).app/— The macOS desktop app (Electron + React).
cli/ # CLI package
src/cli.ts # CLI entry point and command registration
src/core/ # Core business logic (config, daemon, sync, secrets, etc.)
src/core/index.ts # Barrel export for core modules (consumed by app)
src/gateway/ # HTTP gateway server (JSON-RPC proxy)
src/adapters/ # Client-specific sync adapters (Claude, Cursor, VS Code, etc.)
src/compat/ # Client-native "add" compatibility layer (claude, codex, etc.)
src/types.ts # Shared TypeScript types
test/ # CLI unit and integration tests
app/ # Desktop app
src/main/ # Electron main process (Tray, IPC, Window management)
src/main/daemon-child.ts # Dedicated mode for running the daemon as a child process
src/preload/ # Context bridge (exposes mcpx API to renderer)
src/renderer/ # React UI (Dashboard, Browse Tab, Settings)
src/shared/ # Shared types and IPC channel constants
test/ # Unit/Component tests (Vitest + RTL)
e2e/ # E2E tests (Playwright)
.github/workflows/ # CI/CD (Separate CLI and Desktop release pipelines)
The desktop app is tightly integrated with the CLI's core logic. It does not use npm workspaces; instead, it imports core business logic directly from the cli/ directory via a TypeScript path alias.
- Alias:
@mcpx/core→cli/src/core/index.ts(resolved byelectron-vite). - IPC Bridge: The Electron main process (
app/src/main/ipc-handlers.ts) wraps core functions and exposes them to the renderer. - Shared Secrets: Both CLI and Desktop app share the same macOS Keychain backend for credentials.
- Node.js >= 20
- macOS (required for keychain and desktop app features)
cd cli
npm install
npm run build # Build to dist/
npm run dev -- [args] # Run src/cli.ts via tsx
npm test # Run unit testscd app
npm install
npm run dev # Start Electron dev server with HMR
npm run build # Build Electron app for production
npm test # Run unit/component tests
npm run e2e # Run Playwright E2E testsAll UI verification must be done on the installed app, not the dev server. The dev server (npm run dev) serves content from ELECTRON_RENDERER_URL which differs from the bundled app.
Step-by-step:
-
Kill existing instances:
pkill -9 -f "mcpx" || true; pkill -9 -E "Electron" || true
-
Build and install with DevTools open:
cd app npm run desktop-install:devThis builds the app, installs to
/Applications/mcpx.app, and launches it with DevTools auto-opened on the dashboard. -
Inspect the dashboard in the DevTools panel that appears.
-
To inspect the popover (menubar tray): right-click inside the popover and select "Inspect". DevTools must already be open from the dashboard. The popover does NOT auto-open DevTools.
-
After making code changes, repeat step 2 to rebuild and verify.
For automated inspection with agent-browser:
cd app && npm run build && npx electron-builder --mac --dir
ditto dist/mac-arm64/mcpx.app /Applications/mcpx.app
open /Applications/mcpx.app --args --remoteDebuggingPort 9222 --devThen use agent-browser --cdp 9222 ... commands as described below.
These rules are foundational for any agent working on this project:
- ES Modules: Use ESM throughout. All files should be
.tsor.tsx. - Validation: Always use
zodfor parsing and validating configuration or external data. - Styling: Use Vanilla CSS for the React frontend. Do not add utility-first or heavy CSS frameworks.
- Testing:
- New logic in
cli/src/core/must have tests incli/test/. - UI components in
app/should have tests inapp/test/components/. - Significant user flows should be covered by Playwright in
app/e2e/.
- New logic in
- Secrets Management: Never log or expose secrets. Use the
SecretsManagerclass which interfaces with the macOS Keychain. - State: Core state (servers, auth) is persisted in
~/.config/mcpx/config.json.
The Electron desktop app can be automated and inspected via Chrome DevTools Protocol using agent-browser. Use this for scripted UI verification.
For launching with CDP, see "Testing & Verifying Changes" above. Launch the installed app with --remoteDebuggingPort 9222 as shown there.
Important: Always clean up first:
pkill -9 -f "mcpx" || true; pkill -9 -E "Electron" || true
agent-browser close --all # Close any stale agent-browser sessions
sleep 1Use --cdp flag, NEVER connect: Electron does not support Target.createTarget via CDP, so agent-browser connect 9222 always fails. Use the --cdp flag on standalone commands instead:
agent-browser --cdp 9222 snapshot -i # Accessibility tree with refs
agent-browser --cdp 9222 screenshot dump.png # Full page screenshot
agent-browser --cdp 9222 tab # List Electron windows
agent-browser --cdp 9222 get text @e1 # Get text by ref
agent-browser --cdp 9222 click @e2 # Click by refWorkflow for verifying UI changes:
- Kill existing instances, rebuild, and launch with CDP port (see "Testing & Verifying Changes" → agent-browser section)
- Wait:
sleep 3 - Inspect:
agent-browser --cdp 9222 snapshot -i - Capture:
agent-browser --cdp 9222 screenshot /tmp/before.png - Make changes, rebuild, and relaunch
- Verify:
agent-browser --cdp 9222 screenshot /tmp/after.png
The app has 2 CDP tabs: the dashboard (main window) and the popover (menubar tray). Use agent-browser --cdp 9222 tab to list them, agent-browser --cdp 9222 tab 0 to switch.
The project uses a single monotonic version stream across both components. Every release increments a shared patch version.
- CLI Release: Triggered by
cli/**changes. Publishes to npm and creates a git tag. - Desktop Release: Triggered by
app/**orcli/**changes. Builds signed/notarized macOS artifacts. - Mixed Releases: If both components change, the CLI workflow owns the tag creation, and the Desktop workflow attaches artifacts to that tag.