ts-mcp-durable-browser-automation
ts-mcp-durable-browser-automation
A production-grade Model Context Protocol (MCP) Server built in TypeScript that wraps a resilient Playwright browser engine with an SQLite-backed Exactly-Once (idempotency) lock, purpose-built to automate interactions with legacy AEC (Architecture, Engineering, Construction) portals that expose unpredictable, brittle APIs.
Architecture
Three discrete, independently testable layers:
LLM / MCP Client
│
▼
┌─────────────────────────────┐
│ Layer 1 · MCP Interface │ @modelcontextprotocol/sdk · Zod v4 input validation
└────────────┬────────────────┘
│
▼
┌─────────────────────────────┐
│ Layer 2 · Idempotency Lock │ SQLite state machine: PENDING → SUCCESS | FAILED
└────────────┬────────────────┘ Rejects concurrent duplicate requests
│
▼
┌─────────────────────────────┐
│ Layer 3 · Playwright Engine│ Resilient locators · auto-retry · screenshot capture
└─────────────────────────────┘ Guaranteed browser.close() via try/finallyCore Features
Exactly-Once Execution — Every tool call requires an
idempotencyKey. The SQLite lock engine prevents duplicate executions and returns cached results on replay.Race Condition Protection — Concurrent requests with the same key are rejected while a
PENDINGoperation is in flight.Resilient Browser Automation — Playwright uses
getByRole/getByTextlocators instead of fragile CSS selectors, with explicit auto-waiting for unpredictable DOM mutations.Zero Browser Leaks — All browser and context instances are destroyed in
try/finallyblocks, even on fatal crashes.Strict Type Safety —
strict: trueTypeScript, Zod v4 runtime schema validation, noanytypes.Physical Proof Generation — A CLI script runs a full end-to-end simulation and outputs a markdown artifact containing structured execution logs and Base64-encoded screenshots.
Project Structure
ts-mcp-durable-browser-automation/
├── src/
│ ├── index.ts # MCP Server entry point
│ ├── mcp/ # Zod schemas, tool handlers
│ ├── automation/ # Playwright lifecycle, submitPermit task
│ ├── core/ # SQLite idempotency lock, structured logger
│ └── types/ # Shared TypeScript interfaces
├── scripts/
│ └── generate_proof.ts # CLI — generates automation_proof.md
├── tests/
│ ├── idempotency.test.ts # Proves exactly-once lock behaviour
│ └── browser.test.ts # Proves browser lifecycle + form automation
├── docs/
│ └── mock_portal.html # Offline legacy AEC portal target
└── automation_proof.md # Generated artifact (Base64 screenshots + logs)Prerequisites
Node.js ≥ 20
npm ≥ 10
Setup
git clone https://github.com/irgiaryanda/ts-mcp-durable-browser-automation.git
cd ts-mcp-durable-browser-automation
npm install
npx playwright install chromiumCommands
Run automated tests
Mathematically proves the idempotency lock (SUCCESS cache hit, PENDING race rejection, FAILED retry) and Playwright browser lifecycle:
npm testExpected output:
Tests: 8 passed, 8 totalGenerate physical proof artifact
Runs a full end-to-end simulation against the offline mock AEC portal and writes automation_proof.md with execution logs and a Base64 screenshot:
npm run proveOutput file: automation_proof.md
Type-check (zero errors)
npx tsc --noEmitMCP Tool: submit_planning_permit
Parameter | Type | Description |
|
| Unique key guaranteeing exactly-once execution |
|
| Name of the construction project |
|
|
|
|
| Registered applicant identifier |
|
| Date in |
The tool is safe to retry — replaying a call with an existing idempotencyKey that previously succeeded returns the cached result instantly without re-executing the browser automation.
Key Technical Decisions
Decision | Rationale |
SQLite for idempotency store | Zero-dependency, file-based, ACID-compliant. No external service required. |
Zod v4 for runtime validation | Full compatibility with |
| Immune to CSS class changes in legacy portal markup. |
| Guarantees |
Offline | Eliminates network flakiness — deterministic, reproducible automation proof. |