@humanjs/mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +241 -0
- package/dist/index.cjs +1102 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1099 -0
- package/dist/index.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/env.ts","../src/session.ts","../src/tools/browser.ts","../src/tools/config.ts","../src/output.ts","../src/tools/inspection.ts","../src/tools/targets.ts","../src/tools/primitives.ts","../src/tools/recording.ts","../src/tools/sessions.ts","../src/index.ts"],"names":["browser","context","page","join","require","z","basename","sessionArg"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Environment-variable configuration for `@humanjs/mcp`. Every option is\n * read once at startup; runtime changes don't take effect until the MCP\n * server restarts. The `set_personality` tool is the one exception —\n * personality can flip per-session at runtime.\n */\n\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { PresetName } from '@humanjs/core';\nimport type { Speed } from '@humanjs/playwright';\n\nconst VALID_PRESETS: readonly PresetName[] = ['careful', 'fast', 'distracted', 'precise'] as const;\nconst VALID_SPEEDS: readonly Speed[] = ['human', 'fast', 'instant'] as const;\n\nexport interface McpEnv {\n /**\n * Default personality applied to every new session. Per-session overrides\n * (via `human_create_session({ personality })`) and runtime changes\n * (via `human_set_personality`) take precedence.\n */\n readonly personality: PresetName;\n /**\n * Humanization pace for new sessions. Per-session overrides (via\n * `human_create_session({ speed })`) and runtime changes (via\n * `human_set_speed`) take precedence. Defaults to `'human'` — the full\n * realistic pace. `'fast'` keeps humanized motion but quicker; `'instant'`\n * bypasses humanization entirely (straight Playwright, no visible motion).\n *\n * Note: speed changes how long each action takes to *execute* — it does\n * not affect the wait *between* actions, which is the MCP client's\n * per-call model inference, outside this server's control.\n */\n readonly speed: Speed;\n /**\n * Whether the browser launches in headless mode. Defaults to `false`\n * (visible window) because the MCP audience — Claude Desktop, Cursor,\n * Codex — runs locally where seeing the browser is the point. Override\n * with `HUMANJS_HEADLESS=true` for CI or headless workflows.\n */\n readonly headless: boolean;\n /**\n * Directory recordings, screenshots, and PDFs land in. Defaults to the\n * MCP server's working directory at startup time (which clients usually\n * set to the user's home or workspace dir). Tools that produce files\n * accept a basename only — they never honor absolute paths.\n */\n readonly outputDir: string;\n /**\n * Default viewport for new sessions. Per-session overrides (via\n * `human_create_session`) and runtime resizes (via `human_set_viewport`)\n * take precedence. Defaults to 1440×900 — a comfortable desktop size\n * that fits any screen in headed mode; bump to `1920x1080` for crisper\n * recordings.\n */\n readonly viewport: { readonly width: number; readonly height: number };\n /**\n * Whether to auto-download the Chromium browser binary on first launch if\n * it's missing (the binary can't ship via npm). Defaults to `true` so\n * `npx -y @humanjs/mcp` works with zero manual setup. Set\n * `HUMANJS_AUTO_INSTALL=false` in locked-down environments where the\n * server shouldn't trigger a download — the first action then errors with\n * the manual `npx playwright install chromium` instruction instead.\n */\n readonly autoInstall: boolean;\n /**\n * How the browser is obtained, resolved from the browser-mode env vars.\n * A discriminated union so each variant carries exactly the data it needs\n * (no optional-everywhere / casts at the use sites):\n *\n * - `cdp` — attach to an already-running browser over CDP (`HUMANJS_CDP_URL`).\n * Uses its existing context. Single-session; never closed on shutdown.\n * - `persistent` — launch with a persistent profile dir\n * (`HUMANJS_USER_DATA_DIR`, or an auto dir when `HUMANJS_PERSIST=true`)\n * so logins survive across runs. Single-session.\n * - `ephemeral` (default) — a fresh throwaway profile each run, with\n * isolated multi-session support.\n */\n readonly browser: BrowserConfig;\n /**\n * Playwright browser channel — e.g. `'chrome'`, `'msedge'`. Launches that\n * installed browser's binary instead of bundled Chromium. NOTE: this alone\n * does NOT reuse your existing profile/logins — it's a fresh profile unless\n * combined with a persistent dir or CDP attach.\n */\n readonly channel: string | undefined;\n}\n\n/** How the browser is obtained — see {@link McpEnv.browser}. */\nexport type BrowserConfig =\n | { readonly mode: 'ephemeral' }\n | { readonly mode: 'persistent'; readonly userDataDir: string }\n | { readonly mode: 'cdp'; readonly cdpUrl: string };\n\n/**\n * Reads environment variables once and freezes the result. Call from the\n * bin entry before constructing the server so any parse errors surface\n * immediately (and on stderr, where MCP clients can show them).\n */\nexport function readEnv(): McpEnv {\n return {\n personality: parsePersonality(process.env.HUMANJS_PERSONALITY),\n speed: parseSpeed(process.env.HUMANJS_SPEED),\n headless: parseBool(process.env.HUMANJS_HEADLESS, false),\n outputDir: process.env.HUMANJS_OUTPUT_DIR ?? process.cwd(),\n viewport: parseViewport(process.env.HUMANJS_VIEWPORT),\n autoInstall: parseBool(process.env.HUMANJS_AUTO_INSTALL, true),\n browser: resolveBrowserConfig(),\n channel: process.env.HUMANJS_CHANNEL?.trim() || undefined,\n };\n}\n\n/** Default persistent profile dir when `HUMANJS_PERSIST=true` without an explicit path. */\nexport const DEFAULT_PERSIST_DIR = join(homedir(), '.humanjs', 'profile');\n\n/**\n * Resolves the browser-config precedence: CDP wins (you explicitly pointed at\n * a running browser), then a persistent profile (explicit dir or the\n * `HUMANJS_PERSIST` auto-dir), else ephemeral.\n */\nfunction resolveBrowserConfig(): BrowserConfig {\n const cdpUrl = process.env.HUMANJS_CDP_URL?.trim() || undefined;\n if (cdpUrl) return { mode: 'cdp', cdpUrl };\n const explicitDir = process.env.HUMANJS_USER_DATA_DIR?.trim() || undefined;\n if (explicitDir) return { mode: 'persistent', userDataDir: explicitDir };\n if (parseBool(process.env.HUMANJS_PERSIST, false)) {\n return { mode: 'persistent', userDataDir: DEFAULT_PERSIST_DIR };\n }\n return { mode: 'ephemeral' };\n}\n\nfunction parsePersonality(raw: string | undefined): PresetName {\n if (!raw) return 'careful';\n const lower = raw.toLowerCase() as PresetName;\n if (VALID_PRESETS.includes(lower)) return lower;\n throw new Error(\n `HUMANJS_PERSONALITY=\"${raw}\" is not a known preset. Expected one of: ${VALID_PRESETS.join(', ')}.`,\n );\n}\n\nfunction parseSpeed(raw: string | undefined): Speed {\n if (!raw) return 'human';\n const lower = raw.toLowerCase() as Speed;\n if (VALID_SPEEDS.includes(lower)) return lower;\n throw new Error(\n `HUMANJS_SPEED=\"${raw}\" is not valid. Expected one of: ${VALID_SPEEDS.join(', ')}.`,\n );\n}\n\nfunction parseBool(raw: string | undefined, fallback: boolean): boolean {\n if (raw === undefined) return fallback;\n const lower = raw.toLowerCase();\n if (lower === 'true' || lower === '1' || lower === 'yes') return true;\n if (lower === 'false' || lower === '0' || lower === 'no') return false;\n throw new Error(`Expected a boolean (\"true\"/\"false\"), got \"${raw}\".`);\n}\n\nfunction parseViewport(raw: string | undefined): { width: number; height: number } {\n if (!raw) return { width: 1440, height: 900 };\n const match = /^\\s*(\\d+)\\s*[x×]\\s*(\\d+)\\s*$/i.exec(raw);\n if (!match) {\n throw new Error(\n `HUMANJS_VIEWPORT=\"${raw}\" is invalid. Expected \"WIDTHxHEIGHT\", e.g. \"1920x1080\".`,\n );\n }\n return { width: Number(match[1]), height: Number(match[2]) };\n}\n","/**\n * Browser session management for `@humanjs/mcp`.\n *\n * One `Browser` process backs the whole MCP server. Each named session\n * gets its own `BrowserContext` + `Page` + `Human` instance so sessions\n * are isolated (cookies, storage, viewport) without paying the cost of\n * a separate browser per session.\n *\n * The default session (`'default'`) is created lazily on first tool call\n * — clients that don't care about multi-session never see session IDs in\n * their tool args. Explicit sessions land via `human_create_session`.\n */\n\nimport { spawn } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { basename, dirname, join } from 'node:path';\nimport type { PersonalityConfig, PresetName } from '@humanjs/core';\nimport {\n createHuman,\n type Human,\n installMouseHelper,\n type Recording,\n type RecordingQuality,\n type Speed,\n} from '@humanjs/playwright';\nimport { type Browser, type BrowserContext, chromium, type Page } from 'playwright';\nimport { type BrowserConfig, DEFAULT_PERSIST_DIR, type McpEnv } from './env';\n\nexport const DEFAULT_SESSION_ID = 'default';\n\n/** Public-facing view of a session. */\nexport interface SessionInfo {\n readonly id: string;\n readonly personality: PresetName;\n readonly speed: Speed;\n readonly createdAt: number;\n}\n\n/** Options accepted by {@link SessionManager.create}. */\nexport interface CreateSessionOptions {\n readonly personality?: PresetName;\n readonly speed?: Speed;\n readonly viewport?: { readonly width: number; readonly height: number };\n}\n\n/** Options accepted by {@link SessionManager.startRecording}. */\nexport interface StartRecordingOptions {\n readonly name?: string;\n readonly video?: boolean;\n readonly quality?: RecordingQuality;\n}\n\n/**\n * Open-recording state held on a session. `human.record(fn)` is\n * callback-based, but MCP actions arrive as independent tool calls — so we\n * keep the callback alive by having it await `stop()`'s signal. Capture\n * (frames + timeline) runs the whole time; `done` resolves with the\n * finished `Recording` once `stop()` fires.\n */\ninterface RecordingState {\n readonly name: string;\n readonly startedAt: number;\n /** Whether video frames are being captured (false = timeline-only). */\n readonly video: boolean;\n readonly stop: () => void;\n readonly done: Promise<Recording>;\n}\n\ntype BrowserMode = 'cdp' | 'persistent' | 'ephemeral';\n\ninterface InternalSession {\n readonly id: string;\n readonly context: BrowserContext;\n readonly page: Page;\n human: Human;\n personality: PresetName;\n speed: Speed;\n /** The browser mode this session was created under (drives cleanup). */\n readonly mode: BrowserMode;\n recording: RecordingState | null;\n readonly createdAt: number;\n}\n\n/** Read-only snapshot of how the browser is (or will be) obtained. */\nexport interface BrowserInfo {\n readonly mode: BrowserMode;\n readonly userDataDir: string | null;\n readonly cdpUrl: string | null;\n readonly channel: string | null;\n /** True when a persistence toggle is set but a restart is needed to apply it. */\n readonly persistPendingRestart: boolean;\n readonly browserRunning: boolean;\n}\n\n/**\n * Manages the shared browser process plus the registry of named sessions.\n * Construct once at server startup; pass the same instance to every tool\n * registration so tools can resolve sessions consistently.\n */\nexport class SessionManager {\n /** Backing browser for `ephemeral` and `cdp` modes. */\n private browser: Browser | null = null;\n /** Backing context for `persistent` mode (launchPersistentContext returns a context, no Browser). */\n private persistentContext: BrowserContext | null = null;\n /** True when `browser` was obtained via connectOverCDP — must NOT be closed on teardown. */\n private cdpConnected = false;\n /** Runtime persistence toggle (from human_enable_persistence); overrides env mode on next launch. */\n private persistOverride: { userDataDir: string } | null = null;\n private readonly sessions = new Map<string, InternalSession>();\n private readonly env: McpEnv;\n\n constructor(env: McpEnv) {\n this.env = env;\n }\n\n /** Effective browser config, honoring the runtime persistence override. */\n private effectiveConfig(): BrowserConfig {\n if (this.persistOverride) {\n return { mode: 'persistent', userDataDir: this.persistOverride.userDataDir };\n }\n return this.env.browser;\n }\n\n /**\n * Resolves the session named by `id`, creating the default session\n * lazily if `id` is omitted or `'default'` and the session doesn't\n * exist yet. Throws if an explicit non-default session ID hasn't been\n * created — that case is a caller bug, not a missing-default UX\n * problem, and a clear error helps the AI agent recover.\n */\n async get(id: string = DEFAULT_SESSION_ID): Promise<InternalSession> {\n const existing = this.sessions.get(id);\n if (existing) return existing;\n if (id === DEFAULT_SESSION_ID) return this.create(DEFAULT_SESSION_ID, {});\n throw new Error(\n `Session \"${id}\" does not exist. Use human_create_session to create it first, or omit the session argument to use the default session.`,\n );\n }\n\n /**\n * Creates a new named session. Throws if the ID is already in use —\n * the caller (an AI agent) should close the old one first if they\n * want to recreate.\n */\n async create(id: string, options: CreateSessionOptions): Promise<InternalSession> {\n if (this.sessions.has(id)) {\n throw new Error(\n `Session \"${id}\" already exists. Close it first with human_close_session if you want to recreate it.`,\n );\n }\n\n const config = this.effectiveConfig();\n if (config.mode !== 'ephemeral' && id !== DEFAULT_SESSION_ID) {\n throw new Error(\n `In ${config.mode} mode HumanJS drives a single shared browser, so named/parallel sessions aren't available. Omit the session argument to use the default session.`,\n );\n }\n\n const viewport = options.viewport ?? this.env.viewport;\n const { context, page } = await this.acquireContext(config, viewport);\n const personality = options.personality ?? this.env.personality;\n const speed = options.speed ?? this.env.speed;\n const human = await createHuman(page, { personality, speed });\n\n const session: InternalSession = {\n id,\n context,\n page,\n human,\n personality,\n speed,\n mode: config.mode,\n recording: null,\n createdAt: Date.now(),\n };\n this.sessions.set(id, session);\n return session;\n }\n\n /**\n * Obtains a `{ context, page }` for the given mode:\n *\n * - `cdp` — reuse the attached browser's existing context + page (the\n * user's real session); only make a new one if there's none.\n * - `persistent` — the single persistent context; reuse its page.\n * - `ephemeral` — a fresh isolated context + page per session.\n *\n * The visible cursor overlay is installed on the context in every mode.\n */\n private async acquireContext(\n config: BrowserConfig,\n viewport: { width: number; height: number },\n ): Promise<{ context: BrowserContext; page: Page }> {\n if (config.mode === 'cdp') {\n const browser = await this.ensureCdpBrowser(config.cdpUrl);\n const context = browser.contexts()[0] ?? (await browser.newContext());\n await installMouseHelper(context);\n const page = context.pages()[0] ?? (await context.newPage());\n return { context, page };\n }\n if (config.mode === 'persistent') {\n const context = await this.ensurePersistentContext(config.userDataDir, viewport);\n const page = context.pages()[0] ?? (await context.newPage());\n return { context, page };\n }\n const browser = await this.ensureEphemeralBrowser();\n const context = await browser.newContext({ viewport });\n // Install the visible cursor overlay before any page exists so every\n // page (including ones opened later by navigation) shows the cursor.\n await installMouseHelper(context);\n const page = await context.newPage();\n return { context, page };\n }\n\n /**\n * Starts a recording on a session. Holds `human.record()` open across\n * tool calls by awaiting an internal stop-signal — capture (frames +\n * action timeline) runs until {@link stopRecording} fires it.\n */\n async startRecording(id: string | undefined, options: StartRecordingOptions): Promise<void> {\n const session = await this.get(id);\n if (session.recording) {\n throw new Error(\n `Session \"${session.id}\" is already recording. Stop it first with human_stop_recording.`,\n );\n }\n let stop!: () => void;\n const signal = new Promise<void>((resolve) => {\n stop = resolve;\n });\n const video = options.video ?? true;\n const done = session.human.record({ video, quality: options.quality ?? 'high' }, () => signal);\n session.recording = {\n name: options.name ?? 'recording',\n startedAt: Date.now(),\n video,\n stop,\n done,\n };\n }\n\n /**\n * Stops the active recording, returns the finished {@link Recording} for\n * export, and recreates the session's `Human` so it can record again\n * (`human.record()` is single-use per instance; page/context/cookies are\n * preserved).\n */\n async stopRecording(id?: string): Promise<Recording> {\n const session = await this.get(id);\n const rec = session.recording;\n if (!rec) {\n throw new Error(\n `Session \"${session.id}\" is not recording. Start one with human_start_recording first.`,\n );\n }\n rec.stop();\n const recording = await rec.done;\n session.recording = null;\n session.human = await createHuman(session.page, {\n personality: session.personality,\n speed: session.speed,\n });\n return recording;\n }\n\n /**\n * Replaces the `Human` instance on an existing session with one bound\n * to a new personality. Browser context, page, cookies, and scroll\n * position are preserved — only the humanization profile changes.\n */\n async setPersonality(\n id: string = DEFAULT_SESSION_ID,\n personality: PersonalityConfig,\n ): Promise<SessionInfo> {\n const session = await this.get(id);\n assertNotRecording(session, 'change personality');\n session.human = await createHuman(session.page, { personality, speed: session.speed });\n // `personality` on InternalSession tracks the *preset name* for the\n // SessionInfo view. When a non-preset PersonalityConfig is passed\n // (a custom blend), we lose the preset name — that's intentional;\n // the public info downgrades to whatever name the resolved\n // personality carries.\n session.personality = (session.human.personality.name ?? 'careful') as PresetName;\n return toSessionInfo(session);\n }\n\n /**\n * Changes the humanization pace for a session at runtime. Recreates the\n * `Human` (speed is fixed at creation); browser context, page, cookies,\n * and scroll position are preserved.\n */\n async setSpeed(id: string = DEFAULT_SESSION_ID, speed: Speed): Promise<SessionInfo> {\n const session = await this.get(id);\n assertNotRecording(session, 'change speed');\n session.speed = speed;\n session.human = await createHuman(session.page, {\n personality: session.personality,\n speed,\n });\n return toSessionInfo(session);\n }\n\n /** Lists all currently-open sessions, including the default if active. */\n list(): SessionInfo[] {\n return [...this.sessions.values()].map(toSessionInfo);\n }\n\n /** Closes a single session and frees its browser context. */\n async close(id: string): Promise<void> {\n const session = this.sessions.get(id);\n if (!session) return;\n // Graceful finalize: if a recording is open, stop and save it to a\n // default-named file so an in-progress clip isn't silently dropped on\n // disconnect. Best-effort — on a hard crash this never runs, and the\n // captured frames are left in the OS temp dir (swept by the recorder's\n // own exit handler / OS tmp cleanup).\n if (session.recording) {\n const rec = session.recording;\n session.recording = null;\n try {\n rec.stop();\n const recording = await rec.done;\n // Save video when frames were captured, else the JSON timeline —\n // toVideo() would throw on a timeline-only recording, losing it.\n // basename() keeps the AI-supplied name from escaping outputDir,\n // matching the policy resolveOutputPath enforces elsewhere.\n const ext = rec.video ? '.mp4' : '.json';\n const path = join(this.env.outputDir, basename(`${rec.name}-${rec.startedAt}${ext}`));\n if (rec.video) await recording.toVideo(path);\n else await recording.toTimeline(path);\n } catch {\n // Nothing more we can do during teardown; don't block the close.\n }\n }\n this.sessions.delete(id);\n // Mode-aware teardown. Ephemeral contexts are ours to close. The\n // persistent context owns its browser, so closing it shuts that down.\n // In CDP mode we attached to the user's running browser — never close\n // their context or browser; just drop our reference on closeAll.\n if (session.mode === 'ephemeral') {\n await session.context.close();\n } else if (session.mode === 'persistent') {\n await this.persistentContext?.close();\n this.persistentContext = null;\n }\n }\n\n /**\n * Tears down every session and the backing browser. Called from the bin\n * entry's shutdown handlers (SIGINT / SIGTERM) so we don't leak chrome\n * processes — and by {@link restartBrowser}. A CDP-attached browser is\n * never closed (it's the user's), only disconnected by dropping the ref.\n */\n async closeAll(): Promise<void> {\n for (const id of [...this.sessions.keys()]) {\n await this.close(id);\n }\n if (this.browser && !this.cdpConnected) {\n await this.browser.close();\n }\n this.browser = null;\n this.cdpConnected = false;\n this.persistentContext = null;\n }\n\n /**\n * Tears the browser down so the next action relaunches it in the current\n * (possibly newly-toggled) mode. Backs `human_restart_browser` — the way\n * to apply a persistence change without restarting the whole MCP server.\n * Discards open pages/tabs.\n */\n async restartBrowser(): Promise<void> {\n await this.closeAll();\n }\n\n /**\n * Turns on a persistent profile for subsequent browser starts (backs\n * `human_enable_persistence`). Takes effect on the next browser launch —\n * call {@link restartBrowser} to apply it to an already-running browser.\n */\n setPersistOverride(userDataDir?: string): void {\n this.persistOverride = { userDataDir: userDataDir ?? DEFAULT_PERSIST_DIR };\n }\n\n /** Read-only snapshot of the browser configuration (backs `human_browser_info`). */\n browserInfo(): BrowserInfo {\n const config = this.effectiveConfig();\n const running = this.browserRunning();\n return {\n mode: config.mode,\n userDataDir: config.mode === 'persistent' ? config.userDataDir : null,\n cdpUrl: config.mode === 'cdp' ? config.cdpUrl : null,\n channel: this.env.channel ?? null,\n // A toggle is \"pending restart\" only when a browser is already up:\n // before any browser exists, the new mode just applies on next start.\n persistPendingRestart: this.persistOverride !== null && running,\n browserRunning: running,\n };\n }\n\n private browserRunning(): boolean {\n return this.browser !== null || this.persistentContext !== null;\n }\n\n private async ensureEphemeralBrowser(): Promise<Browser> {\n if (this.browser) return this.browser;\n this.browser = await this.withBrowserInstall(() =>\n chromium.launch({ headless: this.env.headless, channel: this.env.channel }),\n );\n return this.browser;\n }\n\n private async ensureCdpBrowser(url: string): Promise<Browser> {\n if (this.browser) return this.browser;\n try {\n this.browser = await chromium.connectOverCDP(url);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Could not attach to a browser at ${url} (HUMANJS_CDP_URL). Start your browser with ` +\n `--remote-debugging-port and a matching URL, then retry. (${message})`,\n );\n }\n this.cdpConnected = true;\n return this.browser;\n }\n\n private async ensurePersistentContext(\n userDataDir: string,\n viewport: { width: number; height: number },\n ): Promise<BrowserContext> {\n if (this.persistentContext) return this.persistentContext;\n this.persistentContext = await this.withBrowserInstall(() =>\n chromium.launchPersistentContext(userDataDir, {\n headless: this.env.headless,\n channel: this.env.channel,\n viewport,\n }),\n );\n await installMouseHelper(this.persistentContext);\n return this.persistentContext;\n }\n\n /**\n * Runs a browser-launch thunk, auto-installing Chromium once and retrying\n * if the binary is missing (the common first-run failure — binaries can't\n * ship via npm). Honors `HUMANJS_AUTO_INSTALL=false`. CDP attach doesn't\n * need a local binary, so it doesn't go through here.\n */\n private async withBrowserInstall<T>(launch: () => Promise<T>): Promise<T> {\n try {\n return await launch();\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (!/executable doesn't exist|playwright install/i.test(message)) throw error;\n\n if (!this.env.autoInstall) {\n throw new Error(\n \"Chromium isn't installed and HUMANJS_AUTO_INSTALL is off. Run \" +\n '`npx playwright install chromium` once, then retry.',\n );\n }\n\n await installChromium();\n try {\n return await launch();\n } catch (retryError) {\n const retryMessage = retryError instanceof Error ? retryError.message : String(retryError);\n throw new Error(\n 'Auto-install of Chromium ran but the browser still failed to launch. ' +\n 'Try `npx playwright install chromium` manually. ' +\n `(Original error: ${retryMessage})`,\n );\n }\n }\n }\n}\n\n/**\n * Downloads the Chromium browser binary via Playwright's own CLI. Resolves\n * the CLI from the bundled `playwright` dependency (not a global `npx`, so\n * the version matches) and runs `<cli> install chromium`.\n *\n * Child stdout/stderr are both routed to *our* stderr (fd 2) — never stdout,\n * which is reserved for the MCP JSON-RPC stream and would be corrupted by\n * the installer's progress output.\n */\nasync function installChromium(): Promise<void> {\n process.stderr.write(\n '[humanjs-mcp] Chromium not found — installing once (~150MB, may take a minute)…\\n',\n );\n const require = createRequire(import.meta.url);\n const pkgPath = require.resolve('playwright/package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { bin?: { playwright?: string } };\n const binRel = pkg.bin?.playwright;\n if (!binRel) {\n throw new Error(\"Could not locate Playwright's CLI to install Chromium.\");\n }\n const cli = join(dirname(pkgPath), binRel);\n\n await new Promise<void>((resolve, reject) => {\n const child = spawn(process.execPath, [cli, 'install', 'chromium'], {\n stdio: ['ignore', 2, 2],\n });\n child.on('error', reject);\n child.on('exit', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`playwright install exited with code ${code}.`));\n });\n });\n process.stderr.write('[humanjs-mcp] Chromium installed.\\n');\n}\n\nfunction toSessionInfo(session: InternalSession): SessionInfo {\n return {\n id: session.id,\n personality: session.personality,\n speed: session.speed,\n createdAt: session.createdAt,\n };\n}\n\n/**\n * Guards operations that recreate the `Human` (personality / speed changes)\n * against an in-flight recording — the recording holds the *old* `Human`'s\n * `record()` call open, so swapping in a new instance would silently stop\n * capturing subsequent actions.\n */\nfunction assertNotRecording(session: InternalSession, action: string): void {\n if (session.recording) {\n throw new Error(\n `Cannot ${action} while session \"${session.id}\" is recording. Stop the recording first with human_stop_recording.`,\n );\n }\n}\n","/**\n * Browser-lifecycle tools — inspect how the browser is obtained, toggle a\n * persistent profile at runtime, and restart the browser to apply changes.\n *\n * Browser *mode* (ephemeral / persistent / CDP-attach) is otherwise an\n * up-front config decision via env vars (HUMANJS_PERSIST,\n * HUMANJS_USER_DATA_DIR, HUMANJS_CDP_URL, HUMANJS_CHANNEL). These tools\n * cover the in-chat conveniences; switching to the user's *real* browser\n * stays env-only by design (it's a consent decision the agent shouldn't\n * escalate into).\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { ToolContext } from '../context';\n\nexport function registerBrowserTools(server: McpServer, { sessions }: ToolContext): void {\n server.registerTool(\n 'human_browser_info',\n {\n title: 'Browser configuration',\n description:\n 'Reports how the browser is obtained (ephemeral fresh profile, persistent profile, or attached over CDP), the channel, and whether logins persist. Use it to explain to the user why they are or are not signed in, and how to change it.',\n inputSchema: {},\n },\n async () => {\n const info = sessions.browserInfo();\n const lines: string[] = [];\n if (info.mode === 'cdp') {\n lines.push(`Mode: attached to your running browser over CDP (${info.cdpUrl}).`);\n lines.push(\"Uses that browser's existing logins, tabs, and extensions.\");\n } else if (info.mode === 'persistent') {\n lines.push(`Mode: persistent profile at ${info.userDataDir}.`);\n lines.push('Logins persist across runs (sign in once; it sticks).');\n } else {\n lines.push('Mode: ephemeral — a fresh, empty profile each run (no saved logins).');\n lines.push(\n 'To keep logins across runs: call human_enable_persistence, or set HUMANJS_PERSIST=true in the MCP config for a permanent default.',\n );\n }\n lines.push(`Channel: ${info.channel ?? 'bundled Chromium'}.`);\n lines.push(`Browser running: ${info.browserRunning ? 'yes' : 'no'}.`);\n if (info.persistPendingRestart) {\n lines.push(\n 'A persistence change is set but not yet applied — call human_restart_browser to apply it now.',\n );\n }\n return { content: [{ type: 'text', text: lines.join('\\n') }] };\n },\n );\n\n server.registerTool(\n 'human_enable_persistence',\n {\n title: 'Enable a persistent profile',\n description:\n 'Switches HumanJS to a persistent browser profile so logins/cookies survive across runs. Takes effect on the next browser start; pass restartNow:true to apply immediately (restarting discards the current page — re-navigate after). For a permanent default, set HUMANJS_PERSIST=true in the MCP config instead. Note: this does NOT use your real Chrome profile (that stays an env-only, opt-in setting).',\n inputSchema: {\n userDataDir: z\n .string()\n .optional()\n .describe('Optional profile directory. Defaults to ~/.humanjs/profile.'),\n restartNow: z\n .boolean()\n .optional()\n .describe(\n 'Restart the browser immediately to apply (discards the current page). Default false.',\n ),\n },\n },\n async ({ userDataDir, restartNow }) => {\n sessions.setPersistOverride(userDataDir);\n const info = sessions.browserInfo();\n let text = `Persistence enabled (profile: ${info.userDataDir}).`;\n if (info.persistPendingRestart) {\n if (restartNow) {\n await sessions.restartBrowser();\n text += ' Browser restarted — re-navigate to your page; logins will now persist.';\n } else {\n text +=\n ' Active on the next browser start. Call human_restart_browser to apply now (discards the current page).';\n }\n } else {\n text += ' It will apply on the next action.';\n }\n text += ' For a permanent default, set HUMANJS_PERSIST=true in your MCP config.';\n return { content: [{ type: 'text', text }] };\n },\n );\n\n server.registerTool(\n 'human_restart_browser',\n {\n title: 'Restart the browser',\n description:\n 'Closes the browser and all sessions; the next action launches a fresh one in the current mode. Use to apply a persistence change, or to recover a wedged browser. Discards open pages/tabs — re-navigate afterward. (Does not affect a CDP-attached browser beyond disconnecting.)',\n inputSchema: {},\n },\n async () => {\n await sessions.restartBrowser();\n return {\n content: [\n {\n type: 'text',\n text: 'Browser restarted. The next action launches a fresh browser in the current mode — re-navigate to your page.',\n },\n ],\n };\n },\n );\n}\n","/**\n * Config tools — runtime tweaks to how a session behaves: personality\n * (env var sets the default, this changes it mid-session), humanization\n * speed, and viewport size (resize the live page for a bigger/crisper\n * recording or to test responsive layouts).\n */\n\nimport { blend } from '@humanjs/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { ToolContext } from '../context';\n\nconst preset = z.enum(['careful', 'fast', 'distracted', 'precise']);\n\nexport function registerConfigTools(server: McpServer, { sessions }: ToolContext): void {\n server.registerTool(\n 'human_set_personality',\n {\n title: 'Set session personality',\n description:\n 'Changes the humanization personality for a session at runtime. Pass a preset, or a blend of two presets (e.g. mostly careful with a touch of distracted). The browser, cookies, and scroll position are preserved — only the motion/typing/reading profile changes.',\n inputSchema: {\n personality: preset\n .optional()\n .describe('A preset to apply. Provide this OR `blend`, not both.'),\n blend: z\n .object({\n a: preset.describe('First personality.'),\n b: preset.describe('Second personality.'),\n ratio: z\n .number()\n .min(0)\n .max(1)\n .describe('Weight toward `b` (0 = all a, 1 = all b). e.g. 0.3 = mostly a.'),\n })\n .optional()\n .describe('Blend two presets. Provide this OR `personality`, not both.'),\n session: z.string().optional().describe('Session ID. Omit for the default session.'),\n },\n },\n async ({ personality, blend: blendArg, session }) => {\n if (personality && blendArg) {\n throw new Error('Provide either `personality` or `blend`, not both.');\n }\n if (!personality && !blendArg) {\n throw new Error('Provide a `personality` preset or a `blend`.');\n }\n\n const config = blendArg ? blend(blendArg.a, blendArg.b, blendArg.ratio) : personality;\n // `config` is defined here: exactly one branch ran (validated above).\n const info = await sessions.setPersonality(session, config as NonNullable<typeof config>);\n const label = blendArg\n ? `blend(${blendArg.a}, ${blendArg.b}, ${blendArg.ratio})`\n : (personality as string);\n return {\n content: [{ type: 'text', text: `set \"${info.id}\" personality to ${label}` }],\n };\n },\n );\n\n server.registerTool(\n 'human_set_speed',\n {\n title: 'Set humanization speed',\n description:\n 'Changes a session\\'s humanization pace at runtime. \"human\" = full realistic motion (best for recordings); \"fast\" = humanized but quicker; \"instant\" = no humanized motion (straight Playwright). Note: this changes how long each action takes to execute, not the wait between actions. Cannot change while recording.',\n inputSchema: {\n speed: z.enum(['human', 'fast', 'instant']).describe('The pace to switch to.'),\n session: z.string().optional().describe('Session ID. Omit for the default session.'),\n },\n },\n async ({ speed, session }) => {\n const info = await sessions.setSpeed(session, speed);\n return { content: [{ type: 'text', text: `set \"${info.id}\" speed to ${speed}` }] };\n },\n );\n\n server.registerTool(\n 'human_set_viewport',\n {\n title: 'Resize the viewport',\n description:\n \"Resizes a session's browser viewport at runtime. Use for a bigger/crisper recording or to test responsive layouts. The default size for new sessions is set by HUMANJS_VIEWPORT (default 1440×900).\",\n inputSchema: {\n width: z.number().int().positive().describe('Viewport width in CSS px.'),\n height: z.number().int().positive().describe('Viewport height in CSS px.'),\n session: z.string().optional().describe('Session ID. Omit for the default session.'),\n },\n },\n async ({ width, height, session }) => {\n const { human } = await sessions.get(session);\n await human.setViewportSize({ width, height });\n return { content: [{ type: 'text', text: `viewport set to ${width}×${height}` }] };\n },\n );\n}\n","import { basename, join } from 'node:path';\n\n/**\n * Resolves a user/AI-supplied filename to a safe absolute path inside\n * `outputDir`. Rejects anything with path components (`../`, `sub/dir`,\n * absolute paths) so a prompt-injected filename can't write outside the\n * configured output directory.\n *\n * The AI picks the name; the env (HUMANJS_OUTPUT_DIR) picks the directory.\n */\nexport function resolveOutputPath(outputDir: string, filename: string): string {\n const base = basename(filename);\n if (base !== filename || base.length === 0) {\n throw new Error(\n `filename must be a plain name with no path components, got \"${filename}\". Files are always written to HUMANJS_OUTPUT_DIR.`,\n );\n }\n return join(outputDir, base);\n}\n","/**\n * Inspection tools — read page state without modifying it. Without these\n * an AI agent is flying blind between humanized actions; with them, a\n * single MCP server covers the common \"act + observe\" loop without\n * needing to layer Playwright MCP alongside.\n *\n * Deliberately no arbitrary-`evaluate` tool — that's a prompt-injection\n * cliff (a malicious page could trick the agent into running JS that\n * exfiltrates data). These read-only tools cover the legitimate need:\n * see the page text, discover an element's real selector / attributes,\n * grab a region's HTML. The internal `locator.evaluate` calls below run\n * fixed functions, never AI-supplied code.\n */\n\nimport { writeFile } from 'node:fs/promises';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { ToolContext } from '../context';\nimport { resolveOutputPath } from '../output';\n\nconst sessionArg = z\n .string()\n .optional()\n .describe('Session ID to act on. Omit to use the default session.');\n\nexport function registerInspectionTools(server: McpServer, ctx: ToolContext): void {\n server.registerTool(\n 'human_screenshot',\n {\n title: 'Screenshot the current page',\n description:\n 'Captures the current page (or a specific element if `selector` is given) as a PNG and returns it as image content the AI can view directly. Pass `filename` to also save it to disk (HUMANJS_OUTPUT_DIR); omit it for an ephemeral look-at-the-page capture.',\n inputSchema: {\n selector: z\n .string()\n .optional()\n .describe('Optional selector. If omitted, captures the entire viewport.'),\n fullPage: z\n .boolean()\n .optional()\n .describe(\n 'Capture the full scrollable page instead of just the viewport. Ignored if `selector` is set.',\n ),\n filename: z\n .string()\n .optional()\n .describe(\n 'Optional plain filename (e.g. \"homepage.png\"). When set, the screenshot is saved to HUMANJS_OUTPUT_DIR. Path components are rejected for safety.',\n ),\n session: sessionArg,\n },\n },\n async ({ selector, fullPage, filename, session }) => {\n const { human, page } = await ctx.sessions.get(session);\n const buffer = selector\n ? await page.locator(selector).screenshot()\n : await human.screenshot({ fullPage: fullPage ?? false });\n\n const content: Array<\n { type: 'image'; data: string; mimeType: string } | { type: 'text'; text: string }\n > = [{ type: 'image', data: buffer.toString('base64'), mimeType: 'image/png' }];\n\n if (filename) {\n const path = resolveOutputPath(ctx.env.outputDir, filename);\n await writeFile(path, buffer);\n content.push({ type: 'text', text: `saved screenshot to ${path}` });\n }\n\n return { content };\n },\n );\n\n server.registerTool(\n 'human_page_text',\n {\n title: 'Get visible page text',\n description:\n \"Returns the page's visible text (document.body.innerText). The fastest way to understand what's on screen without parsing HTML — prefer this over human_get_html unless you need element structure or attributes.\",\n inputSchema: { session: sessionArg },\n },\n async ({ session }) => {\n const { human } = await ctx.sessions.get(session);\n const text = await human.pageText();\n return { content: [{ type: 'text', text }] };\n },\n );\n\n server.registerTool(\n 'human_get_text',\n {\n title: \"Get an element's text\",\n description:\n 'Returns the visible innerText of the first element matching `selector`. Use to read a specific label, price, status, or message.',\n inputSchema: {\n selector: z.string().describe('Selector of the element to read.'),\n session: sessionArg,\n },\n },\n async ({ selector, session }) => {\n const { page } = await ctx.sessions.get(session);\n const text = await page.locator(selector).innerText();\n return { content: [{ type: 'text', text }] };\n },\n );\n\n server.registerTool(\n 'human_get_attribute',\n {\n title: \"Get an element's attribute\",\n description:\n \"Returns the value of an attribute on the first element matching `selector` (or reports it is absent). Handy for reading aria-label, data-*, href, value, disabled state, etc. — often how you confirm an icon-only button's purpose.\",\n inputSchema: {\n selector: z.string().describe('Selector of the element.'),\n attribute: z.string().describe('Attribute name, e.g. \"aria-label\", \"href\", \"data-state\".'),\n session: sessionArg,\n },\n },\n async ({ selector, attribute, session }) => {\n const { page } = await ctx.sessions.get(session);\n const value = await page.locator(selector).getAttribute(attribute);\n const text =\n value === null ? `${selector} has no attribute \"${attribute}\"` : `${attribute}=\"${value}\"`;\n return { content: [{ type: 'text', text }] };\n },\n );\n\n server.registerTool(\n 'human_get_html',\n {\n title: \"Get an element's HTML\",\n description:\n 'Returns the outerHTML of the first element matching `selector` — the element plus its children, including its own attributes (class, aria-label, etc.). The go-to tool for discovering the real selector of a control with no obvious text. Target a specific region; full-page HTML is large.',\n inputSchema: {\n selector: z.string().describe('Selector of the region to dump. Target narrowly.'),\n session: sessionArg,\n },\n },\n async ({ selector, session }) => {\n const { page } = await ctx.sessions.get(session);\n // Fixed function, not AI-supplied — outerHTML isn't a Playwright\n // locator method, so we read it via a constrained evaluate.\n const html = await page.locator(selector).evaluate((el) => el.outerHTML);\n return { content: [{ type: 'text', text: html }] };\n },\n );\n}\n","/**\n * Shared schema + resolver for tools whose target can be either a selector\n * or raw coordinates. Keeping this in one place means click, rightClick,\n * move, and each drag endpoint all describe coordinates to the AI the same\n * way, and the \"exactly one of selector / (x,y)\" validation lives once.\n */\n\nimport type { MouseTarget } from '@humanjs/playwright';\nimport { z } from 'zod';\n\n/** Flat schema fields for a single selector-or-point target. */\nexport const targetFields = {\n selector: z\n .string()\n .optional()\n .describe(\n 'Playwright-compatible selector. Provide this OR x/y — not both. Prefer role/text selectors over brittle CSS.',\n ),\n x: z\n .number()\n .optional()\n .describe(\n 'X coordinate (CSS px from viewport left). Use x+y when there is no clean selector — e.g. an icon-only button you can see in a screenshot. Requires y.',\n ),\n y: z.number().optional().describe('Y coordinate (CSS px from viewport top). Requires x.'),\n};\n\n/**\n * Resolves the flat selector / x / y fields into a `MouseTarget`. Throws a\n * clear error if neither or both are supplied — an AI agent recovers\n * better from \"provide exactly one\" than from a silent wrong default.\n */\nexport function resolveTarget(input: { selector?: string; x?: number; y?: number }): MouseTarget {\n const hasSelector = input.selector !== undefined;\n const hasPoint = input.x !== undefined && input.y !== undefined;\n if (hasSelector && hasPoint) {\n throw new Error('Provide either a selector or x/y coordinates, not both.');\n }\n if (hasSelector) return input.selector as string;\n if (hasPoint) return { x: input.x as number, y: input.y as number };\n if (input.x !== undefined || input.y !== undefined) {\n throw new Error('Coordinate targets need both x and y.');\n }\n throw new Error('Provide a selector or x/y coordinates.');\n}\n","/**\n * Primitive tools — the humanized actions a user / AI agent performs in\n * the browser. Each wraps a single `human.*` method, exposes a focused Zod\n * schema, and returns a short text confirmation so the agent has something\n * to reason about.\n *\n * Mouse targets (click, rightClick, move, drag endpoints) accept a selector\n * OR raw x/y coordinates — see `targets.ts`. Coordinates are the fallback\n * for controls with no clean selector (icon-only buttons, canvas, SVG)\n * that the AI can see in a screenshot.\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { ToolContext } from '../context';\nimport { resolveTarget, targetFields } from './targets';\n\nconst sessionArg = z\n .string()\n .optional()\n .describe(\n 'Session ID to act on. Omit to use the default session (created lazily on first call). Use human_create_session for parallel browsers.',\n );\n\nexport function registerPrimitiveTools(server: McpServer, { sessions }: ToolContext): void {\n server.registerTool(\n 'human_goto',\n {\n title: 'Navigate to URL',\n description:\n 'Navigates the session\\'s page to a URL. Plugins observe a \"goto\" action. Equivalent to a user typing a URL in the address bar.',\n inputSchema: {\n url: z.string().url().describe('Absolute URL to navigate to.'),\n session: sessionArg,\n },\n },\n async ({ url, session }) => {\n const { human } = await sessions.get(session);\n await human.goto(url);\n return { content: [{ type: 'text', text: `navigated to ${url}` }] };\n },\n );\n\n server.registerTool(\n 'human_click',\n {\n title: 'Click (humanized)',\n description:\n 'Moves the cursor to the target along a humanized Bezier path and clicks. Target is a selector OR x/y coordinates — use coordinates for icon-only buttons or anything with no clean selector that you can see in a screenshot.',\n inputSchema: { ...targetFields, session: sessionArg },\n },\n async ({ selector, x, y, session }) => {\n const { human } = await sessions.get(session);\n const target = resolveTarget({ selector, x, y });\n await human.click(target);\n return { content: [{ type: 'text', text: `clicked ${describeTarget(selector, x, y)}` }] };\n },\n );\n\n server.registerTool(\n 'human_rightClick',\n {\n title: 'Right-click (humanized)',\n description:\n 'Right-clicks the target to open a context menu. Same motion as human_click; only the dispatched button differs. Target is a selector OR x/y coordinates.',\n inputSchema: { ...targetFields, session: sessionArg },\n },\n async ({ selector, x, y, session }) => {\n const { human } = await sessions.get(session);\n const target = resolveTarget({ selector, x, y });\n await human.rightClick(target);\n return {\n content: [{ type: 'text', text: `right-clicked ${describeTarget(selector, x, y)}` }],\n };\n },\n );\n\n server.registerTool(\n 'human_hover',\n {\n title: 'Hover an element (humanized)',\n description:\n 'Moves the cursor to an element and settles on it (no click), letting hover-triggered UI fire — tooltips, dropdowns. Element-bound only; for positioning the cursor at coordinates without an element, use human_move.',\n inputSchema: {\n selector: z.string().describe('Selector of the element to hover.'),\n session: sessionArg,\n },\n },\n async ({ selector, session }) => {\n const { human } = await sessions.get(session);\n await human.hover(selector);\n return { content: [{ type: 'text', text: `hovered ${selector}` }] };\n },\n );\n\n server.registerTool(\n 'human_move',\n {\n title: 'Move the cursor (humanized)',\n description:\n 'Moves the cursor to a target along a Bezier path with no click and no settle dwell — pure positioning. Useful before a keyboard action, for canvas work, or cinematic beats. Target is a selector OR x/y coordinates.',\n inputSchema: { ...targetFields, session: sessionArg },\n },\n async ({ selector, x, y, session }) => {\n const { human } = await sessions.get(session);\n const target = resolveTarget({ selector, x, y });\n await human.move(target);\n return { content: [{ type: 'text', text: `moved to ${describeTarget(selector, x, y)}` }] };\n },\n );\n\n server.registerTool(\n 'human_drag',\n {\n title: 'Drag (humanized)',\n description:\n 'Drags from one location to another — cursor → source, mousedown, source → destination, mouseup, all humanized. Each endpoint is a selector OR x/y coordinates (use coordinates for sliders, canvas, SVG handles).',\n inputSchema: {\n fromSelector: z\n .string()\n .optional()\n .describe('Source selector. Provide this OR fromX/fromY.'),\n fromX: z.number().optional().describe('Source X coordinate. Requires fromY.'),\n fromY: z.number().optional().describe('Source Y coordinate. Requires fromX.'),\n toSelector: z\n .string()\n .optional()\n .describe('Destination selector. Provide this OR toX/toY.'),\n toX: z.number().optional().describe('Destination X coordinate. Requires toY.'),\n toY: z.number().optional().describe('Destination Y coordinate. Requires toX.'),\n session: sessionArg,\n },\n },\n async ({ fromSelector, fromX, fromY, toSelector, toX, toY, session }) => {\n const { human } = await sessions.get(session);\n const from = resolveTarget({ selector: fromSelector, x: fromX, y: fromY });\n const to = resolveTarget({ selector: toSelector, x: toX, y: toY });\n await human.drag(from, to);\n return {\n content: [\n {\n type: 'text',\n text: `dragged ${describeTarget(fromSelector, fromX, fromY)} → ${describeTarget(toSelector, toX, toY)}`,\n },\n ],\n };\n },\n );\n\n server.registerTool(\n 'human_type',\n {\n title: 'Type text (humanized)',\n description:\n 'Clicks the element to focus it, then types with humanized per-key rhythm. The current personality controls speed, typo probability, and corrections (HUMANJS_PERSONALITY / human_set_personality). If this types into a search/filter, the results re-render (often debounced) — use a specific selector for the result, as the list shifts as it filters.',\n inputSchema: {\n selector: z.string().describe('Selector of the input/textarea/contenteditable.'),\n value: z.string().describe('Text to type. May contain newlines.'),\n session: sessionArg,\n },\n },\n async ({ selector, value, session }) => {\n const { human } = await sessions.get(session);\n await human.type(selector, value);\n return { content: [{ type: 'text', text: `typed ${value.length} chars into ${selector}` }] };\n },\n );\n\n server.registerTool(\n 'human_paste',\n {\n title: 'Paste text (one shot)',\n description:\n 'Inserts text in one shot (the Cmd-V semantic) — focuses the field, then sets the whole value via insertText with no per-key timing. Use for long strings where humanized typing would be slow. Does not fire the page paste event.',\n inputSchema: {\n selector: z.string().describe('Selector of the field to paste into.'),\n value: z.string().describe('Text to insert.'),\n session: sessionArg,\n },\n },\n async ({ selector, value, session }) => {\n const { human } = await sessions.get(session);\n await human.paste(selector, value);\n return { content: [{ type: 'text', text: `pasted ${value.length} chars into ${selector}` }] };\n },\n );\n\n server.registerTool(\n 'human_press',\n {\n title: 'Press a key or chord',\n description:\n 'Presses a single key (Enter, Tab, Escape, ArrowDown, …) or a chord (Mod+S, Cmd+Shift+P, Ctrl+C). \"Mod\" maps to Meta on Mac and Control elsewhere. Dispatches against focus — does not move the cursor; compose with human_click/human_move when you need both.',\n inputSchema: {\n key: z.string().describe('Key or chord, e.g. \"Enter\", \"Tab\", \"Mod+S\", \"Ctrl+Shift+K\".'),\n session: sessionArg,\n },\n },\n async ({ key, session }) => {\n const { human } = await sessions.get(session);\n // The library types `key` as a KeyOrChord template-literal union for\n // IDE autocomplete; any string still typechecks through its escape\n // hatch, and the library validates modifiers at runtime. MCP input is\n // a plain string, so the cast just selects that escape-hatch arm.\n await human.press(key as Parameters<typeof human.press>[0]);\n return { content: [{ type: 'text', text: `pressed ${key}` }] };\n },\n );\n\n server.registerTool(\n 'human_scroll',\n {\n title: 'Scroll (humanized)',\n description:\n 'Scrolls the page or a container with a natural velocity profile. Default scrolls one viewport down. Use `target` for presets (\"natural\"/\"end\"/\"top\") or an element selector to scroll into view; `by` for a relative pixel delta; `to` for an absolute position.',\n inputSchema: {\n target: z\n .string()\n .optional()\n .describe(\n 'One of \"natural\" (one viewport), \"end\", \"top\", or an element selector to scroll until visible. Defaults to \"natural\". Ignored if `by` or `to` is set.',\n ),\n by: z.number().optional().describe('Relative pixel delta (negative = up/left).'),\n to: z.number().optional().describe('Absolute scroll position on the chosen axis.'),\n axis: z.enum(['x', 'y']).optional().describe('Axis to scroll. Defaults to \"y\".'),\n within: z\n .string()\n .optional()\n .describe('Selector of a scrollable container to scope the scroll to.'),\n session: sessionArg,\n },\n },\n async ({ target, by, to, axis, within, session }) => {\n const { human } = await sessions.get(session);\n const scrollTarget =\n by !== undefined ? { by } : to !== undefined ? { to } : (target ?? 'natural');\n const result = await human.scroll(scrollTarget, { axis, within });\n return {\n content: [\n { type: 'text', text: `scrolled ${result.from} → ${result.to} (${result.distance}px)` },\n ],\n };\n },\n );\n\n server.registerTool(\n 'human_read',\n {\n title: 'Read dwell (humanized)',\n description:\n 'Dwells as if reading the target — pause time derived from word count and the personality\\'s reading speed, with a visible cursor scan across the text. Models the \"user pauses to read\" beat. Provide a selector OR literal text.',\n inputSchema: {\n selector: z\n .string()\n .optional()\n .describe('Selector of the text to read. Provide this OR text.'),\n text: z\n .string()\n .optional()\n .describe('Literal text to \"read\" (no DOM lookup). Provide this OR selector.'),\n kind: z\n .enum(['prose', 'code', 'scan'])\n .optional()\n .describe('Reading style. Auto-detected as \"code\" for <pre>/<code> when omitted.'),\n session: sessionArg,\n },\n },\n async ({ selector, text, kind, session }) => {\n const { human } = await sessions.get(session);\n if (selector === undefined && text === undefined) {\n throw new Error('Provide a selector or text to read.');\n }\n const readTarget = text !== undefined ? { text } : (selector as string);\n const result = await human.read(readTarget, { kind });\n return {\n content: [\n {\n type: 'text',\n text: `read ${result.words} words (${result.kind}) over ${result.durationMs}ms`,\n },\n ],\n };\n },\n );\n}\n\n/** Short human-readable description of a selector-or-point target. */\nfunction describeTarget(selector?: string, x?: number, y?: number): string {\n if (selector !== undefined) return selector;\n if (x !== undefined && y !== undefined) return `(${x}, ${y})`;\n return 'target';\n}\n","/**\n * Recording tools — capture a humanized session to video / gif / timeline.\n *\n * `human.record()` is callback-based, so these reshape it into start/stop:\n * `human_start_recording` opens capture, every humanized action in between\n * is recorded, `human_stop_recording` finalizes and writes the file. The\n * stop-signal plumbing lives in SessionManager; these tools just drive it\n * and pick the output format from the filename extension.\n */\n\nimport { extname } from 'node:path';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { ToolContext } from '../context';\nimport { resolveOutputPath } from '../output';\n\nexport function registerRecordingTools(server: McpServer, { sessions, env }: ToolContext): void {\n server.registerTool(\n 'human_start_recording',\n {\n title: 'Start recording',\n description:\n 'Begins recording the session. Every humanized action until human_stop_recording is captured (frames + action timeline). The visible cursor is in the video. One recording per session at a time. For a natural-looking take: explore the flow first to find correct selectors, then dispatch the whole run — start_recording + every action + stop_recording — in a SINGLE turn (one batch of tool calls), so there are no model-thinking pauses between actions to leave dead air in the video.',\n inputSchema: {\n name: z\n .string()\n .optional()\n .describe('Label for the recording (used in the timeline + the fallback filename).'),\n video: z\n .boolean()\n .optional()\n .describe('Capture video frames. Default true. Set false for a timeline-only recording.'),\n quality: z\n .enum(['fast', 'standard', 'high', 'lossless'])\n .optional()\n .describe('Capture/encode quality. Default \"high\" (1080p, visually lossless).'),\n session: z.string().optional().describe('Session ID. Omit for the default session.'),\n },\n },\n async ({ name, video, quality, session }) => {\n await sessions.startRecording(session, { name, video, quality });\n return {\n content: [{ type: 'text', text: `recording started${name ? ` (\"${name}\")` : ''}` }],\n };\n },\n );\n\n server.registerTool(\n 'human_stop_recording',\n {\n title: 'Stop recording and save',\n description:\n 'Stops the active recording and writes it to one or more files in HUMANJS_OUTPUT_DIR. Each filename\\'s extension picks its format: .mp4/.webm = video, .gif = animated gif, .json = action timeline. Pass several to export the same recording multiple ways, e.g. [\"demo.mp4\", \"demo.json\"] for video + timeline. Path components are rejected for safety.',\n inputSchema: {\n filenames: z\n .array(z.string())\n .min(1)\n .describe(\n 'One or more output filenames. The recording is saved to each, format chosen by extension. e.g. [\"demo.mp4\"] or [\"demo.mp4\", \"demo.gif\", \"demo.json\"].',\n ),\n session: z.string().optional().describe('Session ID. Omit for the default session.'),\n },\n },\n async ({ filenames, session }) => {\n // Resolve + validate every path/format BEFORE stopping, so a bad\n // filename doesn't leave the recording stopped-but-unsaved.\n const targets = filenames.map((filename) => ({\n path: resolveOutputPath(env.outputDir, filename),\n ext: extname(filename).toLowerCase(),\n }));\n for (const { ext } of targets) {\n if (ext !== '.mp4' && ext !== '.webm' && ext !== '.gif' && ext !== '.json') {\n throw new Error(\n `Unsupported output extension \"${ext}\". Use .mp4, .webm, .gif, or .json.`,\n );\n }\n }\n\n const recording = await sessions.stopRecording(session);\n try {\n const saved: string[] = [];\n for (const { path, ext } of targets) {\n // Video/gif read the captured frames; timeline reads in-memory\n // events. All are repeatable and interleavable until dispose().\n if (ext === '.gif') saved.push(await recording.toGif(path));\n else if (ext === '.json') saved.push(await recording.toTimeline(path));\n else saved.push(await recording.toVideo(path));\n }\n return { content: [{ type: 'text', text: `saved recording to:\\n${saved.join('\\n')}` }] };\n } finally {\n // Free the captured-frames temp dir now that all exports are done.\n await recording.dispose();\n }\n },\n );\n}\n","/**\n * Session tools — multi-session control. Most agents never touch these:\n * the default session is created lazily and every other tool defaults to\n * it. They exist for the parallel-browser case (e.g. comparing two flows\n * side by side, or isolating cookies between accounts).\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { ToolContext } from '../context';\n\nconst personalityArg = z\n .enum(['careful', 'fast', 'distracted', 'precise'])\n .optional()\n .describe('Personality preset for this session. Defaults to HUMANJS_PERSONALITY.');\n\nconst speedArg = z\n .enum(['human', 'fast', 'instant'])\n .optional()\n .describe(\n 'Humanization pace. \"human\" (default) = full realistic motion; \"fast\" = humanized but quick; \"instant\" = no humanized motion. Defaults to HUMANJS_SPEED.',\n );\n\nexport function registerSessionTools(server: McpServer, { sessions }: ToolContext): void {\n server.registerTool(\n 'human_create_session',\n {\n title: 'Create a browser session',\n description:\n 'Opens a new isolated session (its own browser context, cookies, viewport) under the given ID. Only needed for parallel browsers — for a single browser, just omit the session arg on other tools and the default session is used.',\n inputSchema: {\n id: z.string().describe('Unique session ID, e.g. \"buyer\", \"seller\".'),\n personality: personalityArg,\n speed: speedArg,\n width: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Viewport width in CSS px. Defaults to HUMANJS_VIEWPORT. Requires height.'),\n height: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Viewport height in CSS px. Requires width.'),\n },\n },\n async ({ id, personality, speed, width, height }) => {\n if ((width === undefined) !== (height === undefined)) {\n throw new Error('Provide both width and height, or neither.');\n }\n const viewport = width !== undefined && height !== undefined ? { width, height } : undefined;\n const session = await sessions.create(id, { personality, speed, viewport });\n return {\n content: [\n {\n type: 'text',\n text: `created session \"${session.id}\" (personality: ${session.personality}, speed: ${session.speed})`,\n },\n ],\n };\n },\n );\n\n server.registerTool(\n 'human_close_session',\n {\n title: 'Close a browser session',\n description:\n 'Closes a session and frees its browser context. Closing the default session is allowed — it will be recreated lazily on the next call.',\n inputSchema: {\n id: z.string().describe('Session ID to close.'),\n },\n },\n async ({ id }) => {\n await sessions.close(id);\n return { content: [{ type: 'text', text: `closed session \"${id}\"` }] };\n },\n );\n\n server.registerTool(\n 'human_list_sessions',\n {\n title: 'List open sessions',\n description:\n 'Lists every currently-open session with its personality. Use to orient before acting on a specific session.',\n inputSchema: {},\n },\n async () => {\n const list = sessions.list();\n const text =\n list.length === 0\n ? 'no open sessions (the default session is created on first action)'\n : list\n .map((s) => `${s.id} (personality: ${s.personality}, speed: ${s.speed})`)\n .join('\\n');\n return { content: [{ type: 'text', text }] };\n },\n );\n}\n","/**\n * @humanjs/mcp — Model Context Protocol server for HumanJS.\n *\n * Exposes humanized browser automation primitives as MCP tools so AI\n * agents (Claude Desktop, Claude Code, Cursor, Codex, Cline, …) can drive\n * a Playwright browser with realistic motion, typing, reading dwell, and\n * everything else `@humanjs/playwright` provides.\n *\n * The bin entry (`humanjs-mcp` after install) speaks stdio MCP — the\n * lingua franca every desktop AI client supports.\n *\n * Configuration (e.g. in `~/.claude.json`, `.mcp.json`, `.cursor/mcp.json`):\n *\n * ```jsonc\n * {\n * \"mcpServers\": {\n * \"humanjs\": {\n * \"command\": \"npx\",\n * \"args\": [\"-y\", \"@humanjs/mcp\"],\n * \"env\": { \"HUMANJS_PERSONALITY\": \"careful\" }\n * }\n * }\n * }\n * ```\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport type { ToolContext } from './context';\nimport { readEnv } from './env';\nimport { SessionManager } from './session';\nimport { registerBrowserTools } from './tools/browser';\nimport { registerConfigTools } from './tools/config';\nimport { registerInspectionTools } from './tools/inspection';\nimport { registerPrimitiveTools } from './tools/primitives';\nimport { registerRecordingTools } from './tools/recording';\nimport { registerSessionTools } from './tools/sessions';\n\nconst SERVER_NAME = 'humanjs-mcp';\nconst SERVER_VERSION = '0.1.0';\n\n/**\n * Standing guidance surfaced to the agent at connect time (MCP `instructions`).\n * Encodes the workflow and edge-case handling that otherwise the user has to\n * spell out every time — especially for recordings, which only look natural\n * when the agent explores first and runs a clean pass.\n */\nconst SERVER_INSTRUCTIONS = `HumanJS drives a real browser with humanized motion, typing, and reading dwell. Motion is already realistic at the default speed — do NOT switch to 'fast'/'instant' or change personality to make a flow \"look natural\"; it already does.\n\nDISPATCH KNOWN STEPS TOGETHER. When you already know the full sequence (a recording, or any flow you've mapped out), emit ALL the tool calls in a SINGLE turn, back-to-back, WITHOUT pausing to reason between them. This matters a lot: each model turn between actions is a multi-second gap, which is slow in general and shows up as dead air in a recording. The humanized motion paces the actions on its own — don't add thinking gaps on top. Only go one tool at a time when a step genuinely needs the previous step's result (exploring, or reacting to something you can't predict).\n\nRecording a flow (the natural-looking way):\n1. EXPLORE FIRST (un-recorded). Navigate the flow once to discover correct, unambiguous selectors (human_screenshot / human_get_html / human_get_attribute). Do this by default whenever the selectors aren't already known — no need for the user to ask. Skip it only if the selectors are already known or the user tells you not to explore.\n2. THEN RECORD ONE CLEAN RUN AS A SINGLE BATCH: human_start_recording + every action + human_stop_recording, all emitted in one turn. Keep selector-guessing and fumbles out of the take.\n\nDynamic UI: prefer specific selectors (role, aria-label) over text — the same visible text often matches several cards before a filter, or the wrong one after. If a click reports multiple matches, narrow the selector.\n\nBrowser state: by default each run is a fresh, signed-out browser. If a flow needs a login, tell the user to enable persistence (human_enable_persistence or HUMANJS_PERSIST) or CDP attach — see human_browser_info.`;\n\nasync function main(): Promise<void> {\n const env = readEnv();\n const sessions = new SessionManager(env);\n const ctx: ToolContext = { sessions, env };\n\n const server = new McpServer(\n { name: SERVER_NAME, version: SERVER_VERSION },\n { instructions: SERVER_INSTRUCTIONS },\n );\n\n registerPrimitiveTools(server, ctx);\n registerInspectionTools(server, ctx);\n registerRecordingTools(server, ctx);\n registerSessionTools(server, ctx);\n registerConfigTools(server, ctx);\n registerBrowserTools(server, ctx);\n\n // Shutdown: when the MCP client disconnects (stdio EOF) or the process\n // gets a signal, tear down browsers cleanly so we don't leak chrome\n // processes on the user's machine.\n const shutdown = async (): Promise<void> => {\n try {\n await sessions.closeAll();\n } finally {\n process.exit(0);\n }\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\nmain().catch((error) => {\n // MCP servers communicate over stdout — never log there. stderr is the\n // only safe channel for diagnostics; clients surface it as server-side\n // errors.\n console.error('[humanjs-mcp] fatal:', error);\n process.exit(1);\n});\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@humanjs/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Model Context Protocol server for HumanJS — drive a Playwright browser with humanized motion from Claude Desktop, Claude Code, Cursor, Codex, and any other MCP client.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"humanjs",
|
|
7
|
+
"playwright",
|
|
8
|
+
"mcp",
|
|
9
|
+
"model-context-protocol",
|
|
10
|
+
"claude",
|
|
11
|
+
"cursor",
|
|
12
|
+
"codex",
|
|
13
|
+
"ai-agent",
|
|
14
|
+
"browser-automation",
|
|
15
|
+
"humanize"
|
|
16
|
+
],
|
|
17
|
+
"author": "Gonzalo Muñoz <toti@eventurex.com.ar>",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"homepage": "https://humanjs.dev",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/totigm/humanjs.git",
|
|
23
|
+
"directory": "packages/mcp"
|
|
24
|
+
},
|
|
25
|
+
"bugs": "https://github.com/totigm/humanjs/issues",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"main": "./dist/index.cjs",
|
|
28
|
+
"module": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"bin": {
|
|
31
|
+
"humanjs-mcp": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"import": {
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"default": "./dist/index.js"
|
|
38
|
+
},
|
|
39
|
+
"require": {
|
|
40
|
+
"types": "./dist/index.d.cts",
|
|
41
|
+
"default": "./dist/index.cjs"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"./package.json": "./package.json"
|
|
45
|
+
},
|
|
46
|
+
"files": [
|
|
47
|
+
"dist",
|
|
48
|
+
"README.md",
|
|
49
|
+
"LICENSE"
|
|
50
|
+
],
|
|
51
|
+
"sideEffects": false,
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=20"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
57
|
+
"playwright": "^1.60.0",
|
|
58
|
+
"zod": "^3.23.0",
|
|
59
|
+
"@humanjs/core": "0.6.0",
|
|
60
|
+
"@humanjs/playwright": "0.6.0",
|
|
61
|
+
"@humanjs/recorder": "0.2.0"
|
|
62
|
+
},
|
|
63
|
+
"publishConfig": {
|
|
64
|
+
"access": "public"
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"build": "tsup",
|
|
68
|
+
"dev": "tsup --watch",
|
|
69
|
+
"test": "vitest run --passWithNoTests",
|
|
70
|
+
"test:watch": "vitest",
|
|
71
|
+
"typecheck": "tsc --noEmit",
|
|
72
|
+
"lint": "biome check .",
|
|
73
|
+
"clean": "rm -rf dist .turbo"
|
|
74
|
+
}
|
|
75
|
+
}
|