OLTestStack
by openlearnia
README.md
# OLTestStack — AI Browser Testing Framework
[](https://github.com/openlearnia)
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.
```bash
git clone https://github.com/openlearnia/OLTestStack.git
cd OLTestStack
```
## Requirements
- [Bun](https://bun.sh) 1.0+ (or Node.js 20+)
- Chromium (bundled with Puppeteer, or set `CHROMIUM_EXECUTABLE_PATH`)
- [Docker](https://www.docker.com/) (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](http://localhost:8081/dashboard)).
## Quick start (local MCP)
```bash
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.
```bash
# 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:
```bash
bun run docker:down
```
Optional: run the app container (health on host **8091**, MCP on **8092**). Run migrations first, then start the full stack:
```bash
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:
```bash
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:
```bash
docker compose run --rm migrate
```
> **Production warning:** Default credentials in `.env.example` (`oltest`/`oltest`) are for local development only. Change `POSTGRES_USER`, `POSTGRES_PASSWORD`, and `DATABASE_URL` before deploying.
## Run the MCP server
```bash
bun run dev
```
Or after building:
```bash
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):
```json
{
"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](docs/guides/README.md)
- [Session Dashboard](docs/guides/dashboard.md) — browse persisted test reports and timelines
- [MCP Server Setup](docs/guides/mcp-server-setup.md) — install, configure Cursor/Claude, troubleshoot
- [MCP Tools Reference](docs/guides/mcp-tools-reference.md) — schemas, examples, error codes
- [Agent Workflows](docs/guides/agent-workflows.md) — recommended patterns for AI agents
- [Skills](docs/guides/skills.md) — 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](docs/guides/README.md#project-cursor-setup).
## Smoke test
Verify MCP connectivity and core browser flow:
```bash
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`.
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues