wende/macbeth
Playwright for macOS native apps
Platform-specific configuration:
{
"mcpServers": {
"macbeth": {
"command": "npx",
"args": [
"-y",
"macbeth"
]
}
}
}Add the config above to .claude/settings.json under the mcpServers key.
Macbeth automates any macOS application through the Accessibility API. It provides a TypeScript client with chainable locators, auto-waiting, and screenshot capture — the same patterns you know from Playwright, applied to native macOS UI elements instead of the browser DOM.
It also ships as an MCP server, so LLM agents can drive macOS apps through tool calls.
┌──────────────┐ JSON-RPC ┌──────────────┐ AX API ┌─────────────┐
│ TypeScript │◄──── over ───────►│ macbethd │◄─────────────►│ macOS App │
│ Client │ Unix socket │(Swift daemon)│ │ (any app) │
└──────────────┘ └──────────────┘ └─────────────┘
▲
│
┌──────────────┐
│ MCP Server │ ← Claude, or any MCP-compatible agent
└──────────────┘A Swift daemon (macbethd) holds the Accessibility and Screen Recording permissions and communicates with apps via the macOS AX API. A TypeScript client talks to the daemon over a Unix domain socket using JSON-RPC 2.0. The client auto-spawns the daemon — no manual setup needed.
// script.mjs
import { connect } from "macbeth";
const app = await connect("TextEdit");
await app.window("Untitled").textField().fill("Hello from macbeth");
await app.pressKey("s", ["cmd"]);
await app.pressKeys([{ key: "return" }, { key: "tab", delayMs: 100 }]);
// process exits cleanly — no cleanup needednode script.mjsScripts exit automatically when the work is done. The daemon stays warm in the background for fast subsequent runs.
npm install macbeth> macOS 14 (Sonoma) or later required. On first run, macOS will prompt for Accessibility permissions.
# Build the Swift daemon (universal binary: arm64 + x86_64)
./scripts/build-daemon.sh
# Build the TypeScript client
cd clientLoading reviews...