feat(integrations): fx harness example (MCP config) - #2776
Conversation
|
There was a problem hiding this comment.
2 issues found across 4 files
Confidence score: 2/5
packages/integrations/fx/mcp.jsonhas noenvironmentallowlist, so agent-provider credentials from the shell can be passed to the MCP child and consumed by the facade, weakening the intended credential boundary — explicitly allowlist only the required variables.packages/integrations/fx/README.mddocuments a no-environmentsetup that forwards all shell variables, including OpenAI, Anthropic, and Google provider keys, which could encourage unintended credential exposure — update the example to use the same restricted environment configuration.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/integrations/fx/README.md">
<violation number="1" location="packages/integrations/fx/README.md:106">
P2: With the documented no-`environment` setup, fx passes every shell variable to the facade, and `stagehandFacadeConfigFromEnv` reads provider keys such as `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, and Google keys. Correct this security claim and direct users to configure the MCP child with `STAGEHAND_MODEL_NAME`/`STAGEHAND_MODEL_API_KEY`, separate from fx's `AI_GATEWAY_API_KEY`, so unrelated host credentials are not silently consumed.</violation>
</file>
<file name="packages/integrations/fx/mcp.json">
<violation number="1" location="packages/integrations/fx/mcp.json:3">
P2: When the shell contains agent-provider credentials, this entry passes them into the MCP child because it has no `environment` allowlist. The facade can consume those credentials, contradicting the MCP credential boundary; provide an explicit Stagehand/Browserbase allowlist while preserving `PATH` and `HOME`.
(Based on your team's feedback about explicit credentials for MCP children.)</violation>
</file>
Architecture diagram
sequenceDiagram
participant User as User / Terminal
participant FX as fx CLI (v0.0.3)
participant Skill as stagehand-facade Skill
participant MCPCfg as ~/.fx/mcp.json
participant FXConfig as .fx.json
participant Permission as ~/.fx/settings.json
participant MCP as MCP Server (stdio-server.mjs)
participant Facade as Stagehand Facade
participant Browser as Browserbase Browser
Note over User,Browser: fx + Stagehand MCP Integration Flow
User->>FX: cd packages/integrations/fx
User->>FX: fx ask --json "browser instructions"
Note over FX: Loads project config
FX->>FXConfig: Read max_agent_steps: 60, max_tool_result_bytes: 262144
Note over FX: Loads skill guidance
FX->>Skill: Parse SKILL.md
alt Tool discovery phase
FX->>MCPCfg: Read MCP server config
MCPCfg-->>FX: stagehand: stdio server definition
FX->>MCP: Spawn node /path/to/stdio-server.mjs
Note over FX,MCP: 10s startup timeout enforced by fx
FX->>MCP: mcp_search_tools()
Note over FX: v0.0.3 bug: returns empty for this server
alt Skill provides exact tool names
FX->>Skill: mcp_select_tool("mcp_stagehand_run")
Skill-->>FX: Tool selected
FX->>Skill: mcp_select_tool("mcp_stagehand_snapshot")
Skill-->>FX: Tool selected
FX->>Skill: mcp_select_tool("mcp_stagehand_screenshot")
Skill-->>FX: Tool selected
end
end
alt Permission check
FX->>Permission: Check rule shape for mcp_stagehand_run
alt Pre-allowed in settings.json
Permission-->>FX: allow
else No pre-allow
FX->>User: Permission prompt (headless fails)
alt --auto flag
FX->>FX: Model-based adjudication
end
end
end
Note over FX,Browser: Tool execution (happy path)
FX->>MCP: mcp_stagehand_run({ code: "..." })
MCP->>Facade: Execute browser action
Facade->>Browser: Launch browser (lazy)
Browser-->>Facade: Page ready
Facade->>Browser: Execute JavaScript
Browser-->>Facade: Result
Facade-->>MCP: Tool response
MCP-->>FX: Result
FX->>MCP: mcp_stagehand_snapshot()
MCP->>Facade: Snapshot page
Facade->>Browser: Capture DOM state
Browser-->>Facade: Snapshot data
Facade-->>MCP: Snapshot response
MCP-->>FX: Snapshot
FX-->>User: Final result
Note over FX,Facade: Unhappy path: fallback to shell
alt Skill not loaded (wrong directory)
FX->>User: run_command exploration
Note over User: Leaks host env into transcript
alt run_command denied in settings
FX->>Permission: Check run_command: deny
Permission-->>FX: Blocked
FX-->>User: Error: tool not available
end
end
Note over FX,MCP: fx discards MCP server stderr
Note over MCP,Facade: Debug standalone if issues
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Confidence score: 3/5
- The allowlisting example in
packages/integrations/fx/README.mdomits Stagehand model credentials, soact,extract, andobservecalls can fail while browser-only operations continue to work; update the example to include the required credentials or clearly document the limitation.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/integrations/fx/README.md">
<violation number="1" location="packages/integrations/fx/README.md:116">
P2: When allowlisting the MCP child for `run` code that calls `act`, `extract`, or `observe`, this example passes no Stagehand model credentials, so those calls fail even though browser-only page operations work. State that these calls require separate `STAGEHAND_MODEL_NAME` and `STAGEHAND_MODEL_API_KEY` values, and include them in the allowlist example or explicitly scope the example to browser-only code.
(Based on your team's feedback about documenting separate Stagehand model credentials for MCP children.) .</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Kylejeong2
left a comment
There was a problem hiding this comment.
approved, fix merge conflicts
fx (Vercel Labs' Zig coding agent, v0.0.3) consumes the facade as a standard stdio MCP server; native tools and SDK embedding are not possible (no plugin API; libfx hard-disables MCP mounting). Ships the user-global mcp.json template (no environment block — fx replaces the child env wholesale when one is set, so shell inheritance is the safe path), a project .fx.json raising max_tool_result_bytes past snapshot size and max_agent_steps past the MCP discovery round trips, the headless permission allowlist (rule-key shape verified empirically), and a stagehand-facade skill generated from FACADE_AGENT_INSTRUCTIONS with an fx preamble naming the exact generated tool ids — fx v0.0.3's mcp_search_tools returns no results for the server, and exact-name mcp_select_tool is the working path. Smoke (fx ask --json, sandboxed HOME, Browserbase): skill -> select x2 -> run -> snapshot, 'Example Domain' [0-19], 5 steps, reproduced twice.
Field testing showed a run outside the example directory (skill not loaded) stalls in tool discovery and falls back to native run_command exploration — which dumped the shell environment, credentials included, into the model transcript. The README now marks the working directory as required and recommends denying run_command for browser-only headless workflows.
… test The facade can infer model-provider keys from an inherited environment for optional Stagehand model config, so the security section now says so and documents the environment-allowlist alternative (with the PATH/HOME restatement fx requires). Also bound the sdk-parity notification test at 30s — third test to trip the 5s default on cold runners.
12948a8 to
0c546d4
Compare
# why Add the public documentation for the fx integration introduced in #2776 and hardened in #2791. This PR is intentionally stacked on #2791 because the guide documents its deterministic discovery instructions and transport-safe screenshot mode. # what changed - add a complete fx integration guide following the existing v4 integration page structure - add the official fx mark as a local docs asset - add fx immediately after Mastra and before Pi in the integrations sidebar - add the fx overview card in the same Mastra → fx → Pi position - update overview lifecycle and source descriptions to include fx # test plan - pnpm --filter @browserbasehq/stagehand-docs test:unit (27 tests) - pnpm --filter @browserbasehq/stagehand-docs check - Mint build validation - broken links, anchors, redirects, and snippets - accessibility checks - pnpm exec oxfmt --check packages/docs/docs.json - git diff --check <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds a complete fx integration guide to the v4 docs, updates the overview and sidebar to include fx, and switches to the dark fx logo. This documents deterministic MCP tool discovery and a transport-safe screenshot mode to keep fx sessions stable. - Verify the fx page renders and all anchors, code blocks, and links resolve, including fx v0.0.3 references. - Confirm the dark fx SVG displays with correct alt/aria and matches other integration icons across themes. - Check sidebar ordering (Mastra → fx → Pi) and the updated overview card copy. - Merge only after the stdio facade exposes the `--max-screenshot-base64-bytes` flag and stable tool names; otherwise the guide will be inaccurate. <sup>Written for commit e9dfbe8. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/2792?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why The fx harness added in #2776 can miss all three Stagehand tools during dynamic search and then invent legacy navigate tool names. Inline full-page PNG responses can also exceed the fx raw MCP frame cap before tool-result truncation runs, which closes the RPC connection. # what changed - add deterministic fx project guidance with the exact three tool names and explicit page.goto navigation - make the facade run and screenshot descriptions easier to discover and harder to misinterpret - add an fx-specific 60 KB screenshot payload budget that defaults to viewport JPEG, retries progressively smaller JPEGs, and returns a small tool error if no image fits - document the distinction between the raw response-frame cap and max_tool_result_bytes - add focused contract, transport-budget, and fx configuration tests # test plan - pnpm --filter @browserbasehq/stagehand-extension build - pnpm --filter @browserbasehq/stagehand build - pnpm --filter @browserbasehq/stagehand-integrations typecheck - pnpm --filter @browserbasehq/stagehand-integrations test - pnpm exec oxlint on all changed TypeScript files - pnpm exec oxfmt --check on all changed files - git diff --check <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Hardens fx Stagehand facade tool discovery and screenshot transport to prevent stalled runs and dropped MCP connections, and publishes a complete fx integration guide. Previously fx could return no tools and models invented legacy navigate names; full‑page PNG screenshots could exceed fx’s raw frame cap and close the connection. Now discovery is deterministic and screenshots respect a configurable base64 budget with safe, clamped JPEG retries. - Deterministic discovery and navigation: pins exactly three tools (“run”, “snapshot”, “screenshot”) with updated descriptions; there is no separate navigate/start tool. `packages/integrations/fx/AGENTS.md`, the `skills/stagehand-facade` skill, and new docs (`/v4/integrations/fx`) instruct agents to call `mcp_stagehand_run`, `mcp_stagehand_snapshot`, and `mcp_stagehand_screenshot` directly and navigate with `await page.goto(...)`. - Transport-safe screenshots: the facade enforces a base64 budget (`--max-screenshot-base64-bytes=...`). The fx template sets `--max-screenshot-base64-bytes=60000`, defaults unspecified screenshots to a viewport JPEG (quality 40), retries with smaller JPEG qualities (40 → 25 → 10) without ever increasing a requested JPEG quality, and returns a small tool error if none fit. Docs clarify the raw response-frame cap vs `max_tool_result_bytes`. - Tests: add contract, transport-budget, and fx configuration tests, including quality clamping during screenshot retries. - Required for custom fx setups: add `--max-screenshot-base64-bytes=60000` (or a suitable value) to the Stagehand MCP command; run fx from `packages/integrations/fx` so it loads the project guidance; prefer `{"type":"jpeg","quality":40,"fullPage":false}` for screenshots. <sup>Written for commit 9c5d64a. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/2791?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
Summary
packages/integrations/fx— config-only integration for fx (Vercel Labs' coding agent, v0.0.3)~/.fx/mcp.jsontemplate, a project.fx.jsonsized for snapshots and MCP discovery, the headless permission allowlist, and astagehand-facadeskill generated fromFACADE_AGENT_INSTRUCTIONSWhy
fx only consumes MCP from user-global config: it has no plugin API and
libfxhard-disables MCP mounting, so the native-tools and SDK-embedded shapes don't apply. The skill is load-bearing — fx v0.0.3'smcp_search_toolsreturns no results for the server, so the skill teaches the exactmcp_stagehand_*names; without it, runs stall and fall back torun_commandexploration (which can dump env credentials into the transcript — README recommends denying it for headless browser work). The template omitsenvironmentbecause fx replaces the child env wholesale when one is set.Testing
fx ask --jsonsmoke with the pinned v0.0.3 binary, sandboxedHOME, Browserbase: skill → exact-name select →run→snapshot→ "Example Domain"[0-19], 5 steps, reproduced twicemcp_stagehand_run) and no-environmentinheritance verified empiricallypnpm run fmt:check;vitest run rules/ast-grep/sdk-parity.test.ts(14/14)Docs PR fast-follows as a stack. ACP-client route (
fx acpper-session mounts) tracked as follow-up for evals/embedding; ACP rejects image blocks.