Development Setup
Thanks for wanting to contribute — let me get you set up. By the end of this page, you'll have the MCP server, Chrome extension, and a test plugin running with hot reload.
Prerequisites
- Node.js 22+ (runtime, package manager, test runner)
- Google Chrome (for loading the extension)
- Git
Clone and Install
git clone https://github.com/opentabs-dev/opentabs.git
cd opentabs
npm installnpm install resolves all platform packages via the workspaces field in the root package.json. Plugins in plugins/ are deliberately standalone — they have their own node_modules and are not part of the workspace. This separation matters: plugins depend on published SDK packages, not workspace links, so the development experience matches what real plugin authors get.
Build Everything
npm run buildThis runs the full build pipeline. It does a lot, but it's idempotent — run it as many times as you want:
tsc --build— compiles all platform packages via project references (incremental; usenpm run build:forceto add--forcefor a clean rebuild)- Browser tools catalog — generates the static browser tool catalog used by the side panel
- Extension bundle — bundles the background script and offscreen document
- Side panel — builds the React side panel with Tailwind CSS
- Icon generation — creates extension icons from the SVG source
- Extension install — copies the built extension to
~/.opentabs/extension/ npm rebuild— rebuilds@opentabs-dev/cliand@opentabs-dev/plugin-toolsto link their bin scripts after TypeScript compilation
Load the Chrome Extension
- Open
chrome://extensions/ - Enable Developer mode (toggle in the top right)
- Click Load unpacked
- Select the
~/.opentabs/extension/folder
That's it — the extension connects to the MCP server automatically when the server starts.
Start the Dev Server
npm run devThis is the main development command. It starts the dev orchestrator (scripts/dev.ts), which runs three processes in parallel:
[tsc]—tsc --build --watchfor incremental TypeScript compilation across all platform packages[mcp]— the MCP server via the dev proxy, which hot-reloads when compiled files change[ext]— extension rebuild pipeline, triggered on each tsc recompilation
All output is labeled with prefixes so you can see which process is speaking:
[tsc] Found 0 errors. Watching for file changes.
[ext] Rebuilding extension...
[ext] Extension built and installed.
[mcp] MCP server running on http://localhost:9515
How Hot Reload Works
When you edit a source file:
tsc --build --watchdetects the change and recompiles- The dev proxy detects the changed files in
dist/and restarts the MCP server worker process - The dev orchestrator rebuilds the extension and sends a reload signal via
POST /extension/reload
MCP server changes take effect immediately after tsc finishes. Chrome extension changes require the extension to receive the reload signal — the side panel reconnects automatically, but you may need to close and reopen it if it was open during the reload.
Dev Mode vs Production Mode
The MCP server has two modes:
| Feature | Production (default) | Dev mode |
|---|---|---|
| Plugin discovery | Once at startup | Once at startup + file watchers |
| File watchers | None | Watches local plugin dist/ directories and config.json |
POST /reload | Available | Available |
| Hot reload | Not used | Via dev proxy (restarts worker on dist/ changes) |
npm run dev uses the dev proxy for server hot reload. To enable dev mode file watchers, set OPENTABS_DEV=1 or pass --dev to the server:
OPENTABS_DEV=1 npm run devBuild a Test Plugin
Plugins are standalone projects outside the workspace — this is intentional. To test your changes against a real plugin:
cd plugins/e2e-test
npm install
npm run buildThe opentabs-plugin build command auto-registers the plugin in ~/.opentabs/config.json (under localPlugins) and calls POST /reload to notify the running MCP server. No restart needed.
For a real plugin with more tools, try the Slack plugin:
cd plugins/slack
npm install
npm run buildQuality Checks
Run all of these before committing. I mean all of them — not just the ones you think are relevant to your change:
npm run build # Full production build
npm run type-check # TypeScript (tsc --build)
npm run lint # Biome lint check
npm run format:check # Biome format check
npm run knip # Unused code detection
npm run test # Unit tests (Vitest)
npm run test:e2e # E2E tests (Playwright)Every single one must exit 0. The pre-commit hook catches some of this via lint-staged, but run the full suite yourself — don't rely on the hook to catch everything.
E2E Tests
E2E tests use Playwright with Chromium. Each test gets its own MCP server instance, test web server, and isolated config directory — so tests run fully in parallel.
npm run test:e2e # Run all E2E tests
npx playwright test tool-dispatch # Run a specific test file
npx playwright test --headed # Run with visible browserTest files live in e2e/ and follow the *.e2e.ts naming convention. Fixtures in e2e/fixtures.ts handle server lifecycle, extension loading, and test server setup.
Unit Tests
Unit tests use Vitest:
npm run test # Run all unit tests
npx vitest run platform/mcp-server/ # Run tests for a specific packageProject Structure
The platform/ packages are linked via npm workspaces. Changes to any platform package are immediately visible to other packages after tsc recompiles.
Plugins in plugins/ are fully standalone — they depend on published @opentabs-dev/* npm packages, not workspace links. When you change the SDK or plugin tools, you need to publish new versions and update plugin dependencies (see Publishing).
Reloading the Extension After Code Changes
The Chrome extension does not auto-reload from chrome://extensions/. After npm run build (or after the dev orchestrator's [ext] rebuild), the dev orchestrator sends a reload signal via POST /extension/reload. If you're not using npm run dev, reload manually:
- Open
chrome://extensions/ - Find the "OpenTabs" extension card
- Click the refresh icon on the card
- Close and reopen the side panel if it was open
Next Steps
- Architecture — understand how the MCP server, extension, and plugins fit together
- Publishing — publish platform packages to npm
- Plugin Development — build a plugin using the SDK
Last Updated: 10 Mar, 2026