Skip to main content

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 install

npm 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 build

This runs the full build pipeline. It does a lot, but it's idempotent — run it as many times as you want:

  1. tsc --build — compiles all platform packages via project references (incremental; use npm run build:force to add --force for a clean rebuild)
  2. Browser tools catalog — generates the static browser tool catalog used by the side panel
  3. Extension bundle — bundles the background script and offscreen document
  4. Side panel — builds the React side panel with Tailwind CSS
  5. Icon generation — creates extension icons from the SVG source
  6. Extension install — copies the built extension to ~/.opentabs/extension/
  7. npm rebuild — rebuilds @opentabs-dev/cli and @opentabs-dev/plugin-tools to link their bin scripts after TypeScript compilation

Load the Chrome Extension

  1. Open chrome://extensions/
  2. Enable Developer mode (toggle in the top right)
  3. Click Load unpacked
  4. 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 dev

This is the main development command. It starts the dev orchestrator (scripts/dev.ts), which runs three processes in parallel:

  • [tsc]tsc --build --watch for 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:

  1. tsc --build --watch detects the change and recompiles
  2. The dev proxy detects the changed files in dist/ and restarts the MCP server worker process
  3. 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:

FeatureProduction (default)Dev mode
Plugin discoveryOnce at startupOnce at startup + file watchers
File watchersNoneWatches local plugin dist/ directories and config.json
POST /reloadAvailableAvailable
Hot reloadNot usedVia 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 dev

Build 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 build

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

Quality 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 browser

Test 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 package

Project 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:

  1. Open chrome://extensions/
  2. Find the "OpenTabs" extension card
  3. Click the refresh icon on the card
  4. Close and reopen the side panel if it was open

Next Steps

Last Updated: 10 Mar, 2026