OLTestStack — AI Browser Testing Framework

MCP server that exposes high-level browser automation tools for AI agents. Internally drives Chromium via Puppeteer/CDP; externally presents flat, stateless MCP command payloads.
git clone https://github.com/openlearnia/OLTestStack.git
cd OLTestStack
Requirements
- Bun 1.0+ (or Node.js 20+)
- Chromium (bundled with Puppeteer, or set
CHROMIUM_EXECUTABLE_PATH) - Docker (optional, for PostgreSQL persistence)
Ports
| Service | Host port | Container port | Notes | |---------|-----------|----------------|-------| | PostgreSQL | 5433 | 5432 | Non-default; avoids local Postgres conflicts | | App health HTTP (Docker) | 8091 | 8081 | APP_HOST_PORT → HEALTH_PORT; dashboard at /dashboard | | MCP HTTP (Docker) | 8092 | 8082 | MCP_HOST_PORT → MCP_HTTP_PORT; local dev:http uses 8082 |
Local MCP uses stdio by default (no TCP port). bun run dev:http listens on 8081 / 8082 on the host (dashboard at http://localhost:8081/dashboard).
Quick start (local MCP)
bun install
bun run typecheck
bun run dev
Docker + PostgreSQL quickstart
Persistence is optional. Active browser/page sessions stay in-memory for speed; recordings and test reports flush to Postgres on browser close when enabled.
# 1. Start Postgres (host port 5433)
cp .env.example .env
bun run docker:up
# 2. Apply migrations
bun run db:migrate
# 3. Enable persistence and start MCP server
export DATABASE_URL=postgresql://oltest:oltest@localhost:5433/olteststack
bun run dev
Sessions persist automatically when DATABASE_URL is set. Unsaved sessions expire after SESSION_TTL_HOURS (default 24h); call save_session or use the dashboard to keep them.
Stop infrastructure:
bun run docker:down
Optional: run the app container (health on host 8091, MCP on 8092). Run migrations first, then start the full stack:
docker compose run --rm migrate
bun run docker:app
curl http://localhost:8091/health
open http://localhost:8091/dashboard
If the app container restarts in a loop with column "saved" does not exist, apply pending migrations to the existing Postgres volume:
docker compose run --rm migrate
docker compose up -d --build
Override host ports in .env via APP_HOST_PORT and MCP_HOST_PORT if 8091/8092 are taken.
Run migrations inside Docker:
docker compose run --rm migrate
Production warning: Default credentials in
.env.example(oltest/oltest) are for local development only. ChangePOSTGRES_USER,POSTGRES_PASSWORD, andDATABASE_URLbefore deploying.
Run the MCP server
bun run dev
Or after building:
bun run build
bun run start
The server communicates over stdio — do not pipe logs to stdout (stderr only for diagnostics).
When DATABASE_URL is set, the server validates the connection at startup and writes reports/events to PostgreSQL on browser_close unless PERSIST_RECORDING=false. Ephemeral sessions auto-delete after SESSION_TTL_HOURS unless promoted via save_session.
Cursor MCP configuration
Add to your Cursor MCP settings (.cursor/mcp.json or Cursor Settings → MCP):
{
"mcpServers": {
"olteststack": {
"command": "bun",
"args": ["run", "dev"],
"cwd": "/Users/kartikbazzad/OLTestStack",
"env": {
"PERSIST_RECORDING": "false"
}
}
}
}
Replace cwd with the absolute path to this project on your machine. Set DATABASE_URL for Postgres persistence (default on when set). Use PERSIST_RECORDING=false to disable writes.
Available tools (V1.3 — 35)
| Category | Tools | |----------|-------| | Browser | browser_launch, browser_close | | Page | page_create, page_navigate, page_reload, page_close | | Elements | page_elements, page_find | | Actions | page_click, page_click_query, page_type, page_type_query, page_select, page_upload, page_press, page_scroll | | Inspection | page_screenshot, page_snapshot, page_text, page_html | | Monitoring | page_network, page_console | | Waiting | page_wait | | Assertions | assert_exists, assert_text, assert_url, assert_network | | Session | session_status, session_get, session_list, session_export, save_session, script_lint, test_run | | Debug | send_report |
Example flow
browser_launch → page_create → page_navigate → page_find → page_type → page_click → page_wait → page_screenshot → browser_close
Environment variables
| Variable | Default | Description | |----------|---------|-------------| | BROWSER_HEADLESS | true | Default headless mode | | CHROMIUM_EXECUTABLE_PATH | auto | Custom Chromium binary | | DEFAULT_TIMEOUT_MS | 30000 | General operation timeout | | DEFAULT_NAVIGATION_TIMEOUT_MS | 30000 | Navigation/reload timeout | | SCREENSHOT_DIR | ./screenshots | Screenshot output directory | | UPLOAD_DIR | ./uploads | Allowed server-local paths for page_upload | | DATABASE_URL | — | PostgreSQL connection string (localhost:5433 in dev) | | PERSIST_RECORDING | true when DATABASE_URL set | Set false to opt out of persisting reports | | SESSION_TTL_HOURS | 24 | Hours until unsaved sessions are auto-deleted | | DB_PORT | 5433 | Documented default host port for local Docker Postgres | | HEALTH_PORT | — | App listen port for health + dashboard (8081; container side in Docker) | | DASHBOARD_ENABLED | true when HEALTH_PORT or HTTP MCP | Session dashboard at /dashboard | | APP_HOST_PORT | 8091 | Docker host port mapped to HEALTH_PORT | | MCP_HTTP_PORT | 8082 | App listen port for MCP HTTP | | MCP_HOST_PORT | 8092 | Docker host port mapped to MCP_HTTP_PORT | | POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB | oltest / oltest / olteststack | Docker Compose Postgres credentials |
Project structure
src/
├── core/ # Types, errors, registry, config, recording
├── cdp/ # Puppeteer CDP adapter
├── db/ # Drizzle schema, migrations runner, persistence
├── dashboard/ # Session dashboard UI + REST API
├── domain/ # Business logic (browser, page, elements)
├── health/ # Optional HTTP health endpoint
└── mcp/ # MCP server, tool registration
Scripts
| Script | Description | |--------|-------------| | bun run dev:http | Start MCP server (HTTP) + dashboard on 8081 | | bun run dashboard | Dashboard + health only (no MCP) on 8081 | | bun run dev | Start MCP server (stdio) | | bun run build | Compile TypeScript to dist/ | | bun run typecheck | Type-check without emit | | bun run test | Run tests | | bun run smoke | End-to-end MCP smoke test (HTTP transport) | | bun run test:mcp | Full MCP tool-flow test via SDK client (no curl) | | bun run test:mcp:docker | Same as test:mcp against Docker on port 8092 | | bun run docker:up | Start Postgres via Docker Compose | | bun run docker:app | Build and start MCP app container (HTTP on host 8091/8092) | | bun run docker:down | Stop Docker Compose services | | bun run db:migrate | Apply Drizzle SQL migrations | | bun run db:generate | Generate migrations from schema | | bun run db:studio | Open Drizzle Studio (DB GUI) |
Documentation
Agent-focused guides for MCP setup, tool reference, workflows, and Cursor skills:
- Guides index
- Session Dashboard — browse persisted test reports and timelines
- MCP Server Setup — install, configure Cursor/Claude, troubleshoot
- MCP Tools Reference — schemas, examples, error codes
- Agent Workflows — recommended patterns for AI agents
- Skills — Cursor Agent Skills for browser testing
Cursor setup: project skills (.cursor/skills/) and subagents (.cursor/agents/) ship with the repo; OLTestStack rules live at user level (~/.cursor/rules/olteststack-mcp-usage.mdc, olteststack-typescript.mdc) — see Guides index.
Smoke test
Verify MCP connectivity and core browser flow:
bun run smoke # quick: launch → navigate → elements → close
bun run test:mcp # full tool flow via MCP SDK (no curl)
Uses HTTP transport (spawns a local server if none is running). Set CHROMIUM_EXECUTABLE_PATH if Puppeteer's bundled Chromium is unavailable.
What's next
V1 is feature-complete (26 MCP tools, dashboard, session TTL, script export/playback). CI runs on push/PR via .github/workflows/ci.yml. Remaining: push uncommitted work to GitHub, Docker image publish, and V1.2 enhancements (query capture at record time, variable substitution). See docs/plans/v1-implementation-plan.md and docs/plans/session-script-playback.md.






