Overview
MCPJam Inspector runs in three modes: Web Application, Electron Desktop App, and Docker Container. This guide explains how the system adapts to each deployment mode while sharing one codebase.Web App
Standalone web application with separate client and server
Desktop App
Electron application with embedded Hono server
Container
Dockerized deployment for cloud hosting
High-Level Architecture
The application consists of distinct layers that work together across all deployment modes:Deployment Modes
Mode Detection Flow
The application automatically detects its runtime environment and configures itself accordingly:Web Development Mode
Web Development Mode
When:
NODE_ENV=development (no Electron)Characteristics:- Backend: Hono server on
localhost:6274 - Frontend: Vite dev server on
localhost:5173 - CORS enabled for cross-origin requests
- Hot module replacement (HMR)
- API-only server (no static file serving)
server/app.ts(createHonoApp, the dev branch) - Development mode routingclient/vite.config.ts- Vite configuration
Web Production Mode
Web Production Mode
When:
NODE_ENV=production (no Electron)Characteristics:- Backend: Hono server on
0.0.0.0:6274 - Frontend: Served from
dist/client - SPA fallback to
index.html - Optimized production bundles
- No CORS (same-origin)
server/app.ts(createHonoApp, theserveStaticmounts) - Production static servingserver/index.ts- Standalone server entry point
Electron Development Mode
Electron Development Mode
When:
ELECTRON_APP=true and IS_PACKAGED=falseCharacteristics:- Embedded Hono server on
localhost:6274 - Frontend: Vite dev server redirects
- Resources from
app.getAppPath() - DevTools enabled
- Renderer edits hot-reload; main and preload edits rebuild and restart the app
src/main.ts(startHonoServer) - Server startupsrc/main.ts(createMainWindow’sloadURL) - Vite dev server URL loading
Electron Production Mode
Electron Production Mode
When:
ELECTRON_APP=true and IS_PACKAGED=trueCharacteristics:- Embedded Hono server on
127.0.0.1:6274 - Frontend: Bundled in
resources/client - Resources from
process.resourcesPath - Code signing enabled
- Single .app/.exe bundle
src/main.ts(startHonoServer, theprocess.envassignments) - Environment setupserver/app.ts(createHonoApp, theserveStaticmounts) - Packaged static serving
Server Architecture
Hono Application Factory
The server uses a factory pattern to create the Hono app, allowing it to be reused across different contexts: Key Implementation:server/app.ts (createHonoApp)
The factory function createHonoApp() is called from:
server/index.ts- Standalone web serversrc/main.ts(startHonoServer’s dynamicimport("../server/app.js")) - Electron embedded server
Request Lifecycle
Every HTTP request flows through multiple layers:API Routes Structure
- MCP Routes
- File Locations
Electron Integration
Process Architecture
Electron uses a multi-process architecture for security and stability:Security Note: The renderer process has no direct access to Node.js APIs.
All privileged operations must go through the preload script and IPC.
Startup Sequence
When you launch the Electron app:Environment Setup
startHonoServer in src/main.ts sets critical environment variables that tell the server it’s running in ElectronServer Start
startHonoServer in src/main.ts starts the embedded Hono server on port 6274 by
default, probing the next free port when that one is takenWindow Creation
createMainWindow in src/main.ts creates the main BrowserWindow with security settingsIPC Setup
src/ipc/listeners-register.ts registers all IPC event handlersThe embedded WebMCP browser surface
One feature reaches across the process boundary in the opposite direction from everything else here, and it is worth knowing about before reading either half. The WebMCP Inspector normally starts a browser: the server launches Chromium through Playwright and the client watches it. In the desktop app it does the reverse. The renderer mounts a real<webview>, and the server — which runs in
the SAME process, because startHonoServer serves the Hono app from the Electron
main process — reaches the guest directly through webContents.fromId and
attaches a CDP debugger to it. No IPC bridge, no remote debugging port, no
frame stream: the pixels are already on the viewer’s screen and the surface takes
their real mouse and keyboard.
Two consequences shape the code:
- The server never owns the surface.
dispose()detaches and leaves thewebContentsalive, because React owns the element. Destroying it would tear a live DOM node out from under the renderer. - A
webContentsIdis a capability, so it is checked like one.webContents.fromIdwill happily return the app’s own UI renderer. Before attaching, the provider proves the id names a livewebview, on theWEBMCP_WEBVIEW_PARTITIONpartition, hosted by one of our own windows.
src/main.ts: the
enable-features=WebMCP switch (appended before whenReady, because switches
freeze there), webviewTag on the main window, a will-attach-webview guard
that refuses any guest not on that partition and strips preload/node/isolation
from the ones it allows, and deny-all permission handlers on the partition’s
session. docs/webmcp-inspector.md has the rest.
OAuth Deep Linking
The Electron app handles OAuth callbacks through a custom protocol handler:OAuth Architecture
Learn about the complete OAuth flow including deep linking, state management,
and security
src/main.ts(setAsDefaultProtocolClient) - Protocol registrationsrc/main.ts(handleOAuthCallbackUrl) - Deep link handlerclient/src/hooks/useElectronOAuth.ts- React OAuth hook
MCP Client Management
MCPClientManager Architecture
TheMCPClientManager handles MCP server integration:
STDIO Transport
Spawns child processes for local MCP servers
SSE Transport
EventSource connections for remote servers
HTTP Transport
Fetch-based requests with streaming support
Client Lifecycle
State Management
Frontend State Architecture
The application uses a hybrid state management approach:TanStack Query (Server State)
TanStack Query (Server State)
Purpose: Manage server-side data with caching and auto-refetchUsed for:
- MCP server lists
- Tool/resource/prompt data
- Eval results
- Real-time data synchronization
- Automatic background refetching
- Optimistic updates
- Request deduplication
- Stale-while-revalidate
Zustand (Client State)
Zustand (Client State)
Purpose: Manage client-side UI stateUsed for:
- User preferences (theme, layout)
- UI state (modals, sidebars)
- Form state
- Temporary local data
- Simple API
- No boilerplate
- TypeScript support
- Middleware (persist, devtools)
Context API (Scoped State)
Context API (Scoped State)
Purpose: Provide scoped state to component treesUsed for:
- Authentication (WorkOS AuthKit)
- Theme provider
- Feature flags
- React-native
- Component composition
- Clean separation of concerns
Real-time Communication
SSE Event Bus
Real-time RPC logging uses Server-Sent Events for live updates: Flow:- MCPClientManager calls a tool
- RPC logger callback fires
- Publishes to rpcLogBus
- Bus emits to all SSE connections
- Frontend EventSource receives event
- React components update UI
server/services/rpc-log-bus.ts- Event bus implementationserver/app.ts(createHonoApp’srpcLogger) - RPC logger setupclient/src/hooks/useRPCLogs.ts- Frontend subscription
Environment Configuration
The application adapts to its environment through a series of configuration steps:Required Environment Variables
Build & Deployment
Build Process Flow
- Web Deployment
- Electron Deployment
- Docker Deployment
Production Build:Artifacts:
dist/client/- Frontend static filesdist/server/- Backend Node.js files
Performance Considerations
Caching Strategy
Key Optimizations:- Query cache reduces API calls by 80%+
- Stale-while-revalidate provides instant UI updates
- Background refetching keeps data fresh
- Mutation invalidation ensures consistency
Connection Pooling
The MCPClientManager maintains a pool of connections to avoid repeated handshakes:Security Architecture
Security Layers
Electron Security
Electron Security
Context Isolation: Renderer has no direct Node.js accessSecure Preload:
src/preload.ts exposes only safe APIsNo Remote Module: Disabled for securityProtocol Registration: Custom mcpjam:// protocol for OAuthAuthentication
Authentication
WorkOS AuthKit: OAuth 2.0Token Storage: Secure localStorage with expirationPKCE Flow: Proof Key for Code Exchange in ElectronConvex Integration: Server-side token validation
Input Validation
Input Validation
Zod Schemas: Runtime type validationSanitization: All user inputs cleanedRate Limiting: Prevent abuseError Handling: No sensitive data in error messages
Monitoring & Observability
Telemetry Pipeline
Error Tracking:- Sentry integration in both main and renderer processes
- Automatic error reporting in production
- Source maps for stack traces
- User context and breadcrumbs
- React Query DevTools for cache inspection
- Browser DevTools for profiling
- Network tab for API timing
- Electron process manager for memory
Next Steps
MCP Client Manager
Deep dive into MCP protocol implementation
OAuth Architecture
Learn about authentication and OAuth flow
Playground Architecture
Understand the LLM playground system
Evals Architecture
Explore the evaluation framework
Ready to contribute? Check out the Contributing Guide.

