Skip to content

feat(integrations): fx harness example (MCP config) - #2776

Merged
miguelg719 merged 6 commits into
mainfrom
miguel/harness-fx
Aug 20, 2026
Merged

feat(integrations): fx harness example (MCP config)#2776
miguelg719 merged 6 commits into
mainfrom
miguel/harness-fx

Conversation

@miguelg719

@miguelg719 miguelg719 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add packages/integrations/fx — config-only integration for fx (Vercel Labs' coding agent, v0.0.3)
  • ship the ~/.fx/mcp.json template, a project .fx.json sized for snapshots and MCP discovery, the headless permission allowlist, and a stagehand-facade skill generated from FACADE_AGENT_INSTRUCTIONS
  • bound the sdk-parity notification test at 30s (third test to trip the 5s default on cold runners)

Why

fx only consumes MCP from user-global config: it has no plugin API and libfx hard-disables MCP mounting, so the native-tools and SDK-embedded shapes don't apply. The skill is load-bearing — fx v0.0.3's mcp_search_tools returns no results for the server, so the skill teaches the exact mcp_stagehand_* names; without it, runs stall and fall back to run_command exploration (which can dump env credentials into the transcript — README recommends denying it for headless browser work). The template omits environment because fx replaces the child env wholesale when one is set.

Testing

  • fx ask --json smoke with the pinned v0.0.3 binary, sandboxed HOME, Browserbase: skill → exact-name select → runsnapshot → "Example Domain" [0-19], 5 steps, reproduced twice
  • allowlist rule-key shape (mcp_stagehand_run) and no-environment inheritance verified empirically
  • pnpm 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 acp per-session mounts) tracked as follow-up for evals/embedding; ACP rejects image blocks.

@changeset-bot

changeset-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 71d1045

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 4 files

Confidence score: 2/5

  • packages/integrations/fx/mcp.json has no environment allowlist, 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.md documents a no-environment setup 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
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/integrations/fx/README.md Outdated
Comment thread packages/integrations/fx/mcp.json

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Confidence score: 3/5

  • The allowlisting example in packages/integrations/fx/README.md omits Stagehand model credentials, so act, extract, and observe calls 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

Comment thread packages/integrations/fx/README.md
Comment thread packages/integrations/fx/README.md Outdated

@Kylejeong2 Kylejeong2 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approved, fix merge conflicts

miguelg719 and others added 5 commits August 20, 2026 11:07
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.
@miguelg719
miguelg719 merged commit f8f4536 into main Aug 20, 2026
52 checks passed
miguelg719 added a commit that referenced this pull request Aug 20, 2026
# 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. -->
miguelg719 added a commit that referenced this pull request Aug 20, 2026
# 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. -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants