Skip to main content

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:
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)
Key Files:
  • server/app.ts (createHonoApp, the dev branch) - Development mode routing
  • client/vite.config.ts - Vite configuration
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)
Key Files:
  • server/app.ts (createHonoApp, the serveStatic mounts) - Production static serving
  • server/index.ts - Standalone server entry point
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
Key Files:
  • src/main.ts (startHonoServer) - Server startup
  • src/main.ts (createMainWindow’s loadURL) - Vite dev server URL loading
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
Key Files:
  • src/main.ts (startHonoServer, the process.env assignments) - Environment setup
  • server/app.ts (createHonoApp, the serveStatic mounts) - 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 server
  • src/main.ts (startHonoServer’s dynamic import("../server/app.js")) - Electron embedded server

Request Lifecycle

Every HTTP request flows through multiple layers:

API Routes Structure

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 Electron

Server 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 taken

Window Creation

createMainWindow in src/main.ts creates the main BrowserWindow with security settings

IPC Setup

src/ipc/listeners-register.ts registers all IPC event handlers

The 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 the webContents alive, because React owns the element. Destroying it would tear a live DOM node out from under the renderer.
  • A webContentsId is a capability, so it is checked like one. webContents.fromId will happily return the app’s own UI renderer. Before attaching, the provider proves the id names a live webview, on the WEBMCP_WEBVIEW_PARTITION partition, hosted by one of our own windows.
The main process’s part of this is small and all in 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
Quick Overview: Key Files:
  • src/main.ts (setAsDefaultProtocolClient) - Protocol registration
  • src/main.ts (handleOAuthCallbackUrl) - Deep link handler
  • client/src/hooks/useElectronOAuth.ts - React OAuth hook

MCP Client Management

MCPClientManager Architecture

The MCPClientManager 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

For detailed MCP client implementation, see MCP Client Manager Architecture

State Management

Frontend State Architecture

The application uses a hybrid state management approach:
Purpose: Manage server-side data with caching and auto-refetchUsed for:
  • MCP server lists
  • Tool/resource/prompt data
  • Eval results
  • Real-time data synchronization
Key features:
  • Automatic background refetching
  • Optimistic updates
  • Request deduplication
  • Stale-while-revalidate
Purpose: Manage client-side UI stateUsed for:
  • User preferences (theme, layout)
  • UI state (modals, sidebars)
  • Form state
  • Temporary local data
Key features:
  • Simple API
  • No boilerplate
  • TypeScript support
  • Middleware (persist, devtools)
Purpose: Provide scoped state to component treesUsed for:
  • Authentication (WorkOS AuthKit)
  • Theme provider
  • Feature flags
Key features:
  • 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:
  1. MCPClientManager calls a tool
  2. RPC logger callback fires
  3. Publishes to rpcLogBus
  4. Bus emits to all SSE connections
  5. Frontend EventSource receives event
  6. React components update UI
Key Files:
  • server/services/rpc-log-bus.ts - Event bus implementation
  • server/app.ts (createHonoApp’s rpcLogger) - RPC logger setup
  • client/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

Production Build:
Artifacts:
  • dist/client/ - Frontend static files
  • dist/server/ - Backend Node.js files
Server: Hono serves both API and static 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

The application handles sensitive data including API keys, OAuth tokens, and MCP server access.

Security Layers

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 OAuth
WorkOS AuthKit: OAuth 2.0Token Storage: Secure localStorage with expirationPKCE Flow: Proof Key for Code Exchange in ElectronConvex Integration: Server-side token 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
Performance Monitoring:
  • 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.