ContextUI is an Electron desktop app with a React (Vite + TypeScript) renderer. It dynamically loads workflow components from the filesystem, manages Python virtual environments for backend servers, and exposes tools via the Model Context Protocol (MCP).
┌─────────────────────────────────────────────────────┐
│ Electron App │
│ │
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Main Process │◄── IPC ──► Renderer Process │ │
│ │ (electron/) │ │ (src/) │ │
│ │ │ │ │ │
│ │ • Window mgmt│ │ • React UI │ │
│ │ • File system│ │ • Workflow tabs │ │
│ │ • Python mgmt│ │ • Module loader │ │
│ │ • MCP server │ │ • Tool registry │ │
│ │ • Tool reg. │ │ • Theme manager │ │
│ └──────────────┘ └──────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Python Venvs │ │ Workflow Modules │ │
│ │ (per workflow) │ │ (TSX on filesystem) │ │
│ └──────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ MCP Server │ (stdio transport)
│ Port 8800 │ Tool Registry (HTTP)
└─────────────────┘
contextui/
├── electron/ # Main process (Node.js/Electron)
│ ├── main.cjs # App lifecycle, window management, IPC handlers
│ ├── preload.cjs # Context bridge — exposes IPC to renderer
│ ├── module-bundler.cjs # TSX → JS bundling via esbuild
│ ├── python-manager.cjs # Python/venv lifecycle management
│ ├── npm-manager.cjs # npm package management for workflows
│ ├── tool-registry-server.cjs # HTTP tool registry (port 8800)
│ ├── mcp-server-standalone.cjs # MCP server (stdio transport)
│ ├── mcp-registration.cjs # MCP tool registration
│ ├── external-mcp-client.cjs # Connect to external MCP servers
│ ├── mcp-app-security.cjs # Security policies for MCP apps
│ ├── import-parser.cjs # Parse local imports in TSX files
│ ├── dependency-resolver.cjs # Resolve workflow dependencies
│ ├── bundle-mcp-server.cjs # Bundle MCP server for distribution
│ ├── user-paths.cjs # User data directory management
│ └── defaults/ # Default configs (html_apps, local_servers)
│
├── src/ # Renderer process (React + TypeScript)
│ ├── main.tsx # Entry point
│ ├── App.tsx # Root component
│ ├── components/ # Shared UI components
│ │ ├── WindowContainer.tsx # Tab/window container
│ │ ├── WindowManagerComponent.tsx
│ │ ├── DockingContainer.tsx # Dockable layout system
│ │ ├── MenuBar.tsx # Application menu bar
│ │ ├── MCPAppRenderer.tsx # Renders MCP app content
│ │ ├── MCPAppSecurityDialog.tsx
│ │ ├── WelcomeModal.tsx # First-run welcome screen
│ │ ├── LicenseAgreement.tsx
│ │ ├── PinWorkflowDialog.tsx
│ │ └── SetIconDialog.tsx
│ ├── modules/ # Built-in app modules (settings/management UIs)
│ │ ├── WorkflowsWindow.tsx # Workflow browser & launcher
│ │ ├── PythonManagerWindow.tsx # Python/venv management UI
│ │ ├── ToolManagerWindow.tsx # Tool registry UI
│ │ ├── MCPServersWindow.tsx # External MCP server management
│ │ ├── LocalServersWindow.tsx # Local server management
│ │ ├── NpmManagerWindow.tsx # npm package management
│ │ ├── HtmlAppsWindow.tsx # HTML app launcher
│ │ ├── LayoutManagerWindow.tsx # Layout save/restore
│ │ └── DynamicNpmWindow.tsx # Dynamic npm module loader
│ ├── managers/ # State & lifecycle managers
│ │ ├── DynamicModuleLoader.ts # Loads TSX workflows at runtime
│ │ ├── ModuleManager.ts # Module registration & tracking
│ │ ├── WindowManager.ts # Window/tab lifecycle
│ │ ├── LayoutManager.ts # Tab layout persistence
│ │ ├── ToolRegistry.ts # Client-side tool registry
│ │ ├── ToolClient.ts # Tool invocation client
│ │ ├── ToolBridge.ts # Bridge between tools and UI
│ │ ├── MCPBridge.ts # MCP file-based command bridge
│ │ ├── MCPAppManager.ts # MCP app lifecycle
│ │ ├── ThemeManager.ts # Theme/appearance management
│ │ ├── EventBus.ts # Cross-component event system
│ │ └── UITestBridge.ts # UI automation for MCP tools
│ ├── errors/ # Error handling system
│ │ ├── ErrorContext.tsx # Error state provider
│ │ ├── ErrorLogger.ts # Error logging
│ │ ├── ErrorConsolePanel.tsx # Error console UI
│ │ └── ErrorToast.tsx # Error notifications
│ ├── types/ # TypeScript type definitions
│ └── utils/
│ └── ipc.ts # IPC helper utilities
│
├── example_modules/ # Built-in example workflows
├── docs/ # Documentation
├── scripts/ # Build & publish scripts
├── mcp-config.json # MCP server configuration
├── vite.config.ts # Vite bundler config
├── electron-builder.json # Electron Builder config
└── package.json
The main process handles everything that needs Node.js or OS-level access.
The core of the application. Handles:
- Window management — creating and configuring the BrowserWindow
- IPC handlers — all
ipcMain.handle()registrations for renderer communication - Workflow scanning — discovers
.tsx/.jsxfiles in workflow directories - File watching — monitors workflow folders for changes (via chokidar) and triggers hot-reload
- Profile management — multiple user profiles with separate workflow directories
- First-run setup — copies bundled example workflows to user directory
Compiles workflow TSX files into executable JavaScript using esbuild. Handles:
- Local
./ui/imports — resolves and bundles sub-components - React globals injection — makes
useState,useEffect, etc. available without imports - Caching — only re-bundles when source files change
Manages the full Python lifecycle:
- Detection — finds system Python installations
- Installation — downloads and installs Python if needed
- Virtual environments — creates per-workflow venvs in
~/ContextUI/<profile>/python_venvs/ - Package management — pip install with GPU-aware builds (CUDA/Metal detection)
- Server lifecycle — start, stop, and monitor Python backend servers
- Script execution — run one-off Python scripts
An HTTP server (port 8800) that acts as the central registry for tools. Workflows and MCP servers register their tools here, and other components can discover and invoke them.
Implements the Model Context Protocol over stdio transport. Exposes ContextUI's capabilities as tools that AI agents can call:
- Workflow management (list, read, launch, close)
- Python server management (start, stop, status)
- UI automation (screenshot, click, type, DOM inspection)
- Tab management (list, switch)
Securely exposes IPC channels from the main process to the renderer. Uses a whitelist of allowed channels for both invoke (request/response) and send (fire-and-forget) patterns.
The renderer is a React app built with Vite and TypeScript, styled with Tailwind CSS.
The DynamicModuleLoader is the heart of the workflow system:
- Scan — main process discovers
.tsx/.jsxfiles in workflow directories - Bundle —
module-bundler.cjscompiles TSX → JS with esbuild, resolving local imports - Load — renderer evaluates the bundled code with React globals in scope
- Render — component is mounted in a tab via
WindowContainer
This enables hot-reload during development — edit a TSX file and the tab updates automatically.
Managers in src/managers/ are singleton services that handle specific concerns:
| Manager | Responsibility |
|---|---|
DynamicModuleLoader |
Runtime TSX loading and evaluation |
ModuleManager |
Module registration and metadata |
WindowManager |
Tab/window lifecycle |
LayoutManager |
Save/restore tab layouts |
ToolRegistry |
Client-side tool discovery |
ToolClient |
Tool invocation |
MCPBridge |
File-based command bridge for MCP |
UITestBridge |
UI automation (click, type, screenshot) for MCP tools |
ThemeManager |
Theme and appearance |
EventBus |
Cross-component event system |
The src/modules/ directory contains management UIs that ship with the app — the Workflows browser, Python Manager, Tool Manager, MCP Servers panel, etc. These are distinct from user workflows in example_modules/.
Filesystem (.tsx files)
│
▼
main.cjs (scan + watch)
│
▼
module-bundler.cjs (esbuild compile)
│
▼ IPC
DynamicModuleLoader (evaluate JS)
│
▼
WindowContainer (render in tab)
useServerLauncher (React hook)
│
▼ IPC
python-manager.cjs
│
├── Create venv
├── Install packages (GPU-aware)
├── Start uvicorn server
│
▼
Python server on localhost:<port>
│
▼ HTTP (fetch)
React workflow UI
AI Agent
│
▼ stdio
mcp-server-standalone.cjs
│
├── Workflow tools → IPC → renderer
├── Python tools → python-manager.cjs
├── UI tools → UITestBridge → DOM
│
▼
Tool result returned to agent
Workflows run with full Node.js access. This is intentional — workflows need filesystem access, Python server management, and direct IPC to the main process. ContextUI is a local development tool, not a web browser. See the Security section in the README for details.
Workflows are compiled with esbuild rather than Vite/webpack. esbuild is fast enough for real-time bundling on file change, and handles the TSX → JS + local import resolution that workflows need.
The MCP bridge (~/ContextUI/.mcp-bridge/) uses JSON files for communication between external processes and the Electron app. A process writes a command file, the app processes it and writes a response file. This avoids the complexity of maintaining persistent connections.
Each workflow with a Python backend gets its own virtual environment. This prevents dependency conflicts between workflows and makes cleanup straightforward — delete the venv folder.
| Port | Service | Description |
|---|---|---|
| 5173 | Vite dev server | Development only — serves the renderer |
| 8800 | Tool Registry | HTTP API for tool registration and discovery |
Python backend servers use workflow-specified ports (typically 8800+).