Skip to content

feat(core): oc_context — portable context handle: export/import only (browserbase adoption C) #873

@shaun0927

Description

@shaun0927

Why

browserbase/mcp-server-browserbase exposes --contextId and --persist flags that bind cookies, storage, cache, and signed-in state to a single opaque handle. The handle can be reattached anywhere, which is a meaningful ergonomic win for fleet / CI / multi-host workflows.

OpenChrome already has every primitive — cookies, storage, http_auth, session_snapshot/session_resume, the pilot-tier handoff token (#793/#794). They are scattered across distinct tools, which means an LLM agent that wants to "carry the same logged-in state to another openchrome instance" needs to compose ~5 tool calls and stitch the result by hand.

This issue does not introduce a new lifecycle abstraction. It adds a single pair of tools, oc_context_export / oc_context_import, that wrap the existing primitives into one envelope. No state machine; no runtime registry; no implicit persistence (P4: facts vs decisions — the host LLM decides when to persist, openchrome only exports/imports on request).

Stays inside core because no outbound network and no LLM calls are introduced. Encryption-at-rest stays in pilot (#794).

What

Add two tools — oc_context_export and oc_context_import — that serialize/deserialize a single tab's auth-relevant state to/from a plaintext JSON envelope. No lifecycle CRUD, no daemon-side storage — the host stores the envelope wherever it wants (file, memory, handoff token).

Boundary: src/tools/oc-context.ts (new). Reuses existing cookies.ts, storage.ts, http-auth.ts internals; no parallel state walker. No new runtime dependency.

Contract

// src/tools/oc-context.ts
export interface ContextEnvelope {
  version: 1;
  origin: string;                 // origin the cookies/storage were scoped to
  capturedAt: number;
  userAgent?: string;             // captured iff captureUA: true
  viewport?: { width: number; height: number };
  cookies: Cookie[];              // same shape as cookies.ts get()
  localStorage?: Record<string, string>;
  sessionStorage?: Record<string, string>;
  httpAuth?: { username: string; password: string };
  /** SHA-256 of the canonical-JSON form of the above fields, excluding self */
  integrity: string;
}

export interface ExportOptions {
  origin?: string;                // default: active tab origin
  includeStorage?: boolean;       // default true
  includeHttpAuth?: boolean;      // default false (rarely safe to round-trip)
  captureUA?: boolean;            // default false
  tabId?: string;
}

export interface ImportOptions {
  envelope: ContextEnvelope;
  /** if true, mismatch between envelope.origin and active tab origin is an
   *  error; if false (default), import navigates to envelope.origin first */
  strictOrigin?: boolean;
  tabId?: string;
}

export interface ImportResponse {
  ok: boolean;
  appliedCookies: number;
  appliedStorageKeys: number;
  /** present iff envelope.integrity verification failed */
  integrityError?: string;
}

Invariants:

  1. oc_context_export produces a deterministic envelope ordering (cookies sorted by domain,path,name; storage keys lexicographically). Identical browser state yields byte-identical envelopes modulo capturedAt.
  2. integrity is a SHA-256 over the canonical-JSON form excluding the integrity field itself; oc_context_import re-computes and rejects on mismatch.
  3. oc_context_import is a strict replace, not a merge — existing cookies/storage for the target origin are cleared first. (Merge semantics are a separate, harder problem; not in scope.)
  4. HTTP-auth round-trip is opt-in and not stored anywhere by openchrome itself; the envelope is plaintext, by design. Encrypted persistence is the pilot-tier handoff token's job (feat(pilot): handoff persistence with AES-256-GCM + ephemeral key default (replaces #755 cherry-pick) #794).

Acceptance criteria

  • oc_context_export and oc_context_import registered under category storage (per feat(host): tool category toggle / --slim mode (chrome-devtools-mcp adoption C) #847's taxonomy).
  • Tools delegate to existing cookies.ts, storage.ts, http-auth.ts internals; no parallel CDP traversal.
  • Integrity hash verified on import; mismatch returns { ok: false, integrityError } without applying any state.
  • Strict replace semantics (not merge) — covered by tests/tools/oc-context-replace.test.ts.
  • Cross-instance round-trip test: export from instance A, import into instance B with isolated user-data-dir, assert authenticated request succeeds against https://httpbin.org/cookies (mirrors the supplied cookies). Lives in tests/e2e/oc-context-roundtrip.test.ts.
  • Tool descriptions follow the refactor(core): standardize tool descriptions with 'When to use / When NOT to use' guidance #841 standard, explicitly warning that the envelope is plaintext and the host MUST treat it as a secret.
  • npm run build && npm test green.

Real verification (post-merge, via openchrome MCP)

Two openchrome instances are required. Run them on the same machine with distinct --user-data-dir and --port.

  1. Instance A: mcp__openchrome__navigatehttps://httpbin.org/cookies/set?session=abc123&user=alice. Confirm the page shows the cookies set.
  2. Instance A: mcp__openchrome__oc_context_export origin='https://httpbin.org', includeStorage=true.
    • Pass: response envelope.cookies contains both session=abc123 and user=alice; integrity is a 64-char hex string.
  3. Save the envelope JSON to disk (host-side; openchrome itself does not persist).
  4. Instance B: mcp__openchrome__navigatehttps://httpbin.org/cookies (separate fresh profile).
    • Pass: response shows empty cookies.
  5. Instance B: mcp__openchrome__oc_context_import with the envelope from step 2.
    • Pass: ok: true, appliedCookies >= 2.
  6. Instance B: mcp__openchrome__navigatehttps://httpbin.org/cookies.
    • Pass: response page shows session=abc123 and user=alice.
  7. Tamper test: edit the saved envelope to flip one cookie value, then re-import.
    • Pass: ok: false, integrityError non-empty, no cookies applied (verify by reading mcp__openchrome__cookies action=get).
  8. Determinism: re-export from instance B after step 6, then diff against the step-2 envelope (ignoring capturedAt).
    • Pass: byte-identical cookies / storage payloads.
  9. mcp__openchrome__oc_journal records both export and import with origin summaries.

Reproducer script: scripts/verify/browserbase-C-context-roundtrip.mjs.

Out of scope

Dependencies

Effort

S–M (~2–3 dev days). Two tools, integrity hash, fixture-backed e2e.

References

Revision history

  • 2026-05-12 r1: Original draft proposed full CRUD lifecycle (create/attach/export/import/delete with daemon-side registry).
  • 2026-05-12 r2: Self-critic pass scoped down to export/import only.
    • Rationale: a daemon-side registry is a premature abstraction (CLAUDE.md guidance) and overlaps with the pilot handoff token's intended role.
    • Added explicit strict-replace semantics (no merge) and integrity hash contract so import is auditable.
    • Stated clearly that the envelope is plaintext — encryption stays in pilot/handoff. This keeps the new code in core without expanding the core tier's responsibilities.
    • Excluded IndexedDB capture and cross-origin bundles to keep v1 narrow.

Curated scope, overlap handling, and verification checklist

Scope classification

  • Canonical lane: OpenChrome additive improvement with live-verification guardrails.
  • Primary deliverable: oc_context — portable context handle: export/import only (browserbase adoption C).
  • Open PR: none currently linked in the active priority map; verify GitHub again before implementation.
  • Detected labels: enhancement, P2, reliability, host-integration.
  • Affected OpenChrome surfaces from issue text: act, navigate, oc_context, oc_journal.
  • Non-goal: breaking existing tool response compatibility, changing defaults without opt-in, or adding server-side autonomous planning.

Overlap and conflict resolution

Implementation checklist

  • Restate the exact contract for oc_context — portable context handle: export/import only (browserbase adoption C) in code/docs before changing behavior.
  • Implement the narrow surface named by this issue before broadening to adjacent systems.
  • Preserve existing behavior by default and gate new behavior with explicit config/tool arguments where appropriate.
  • Add targeted unit/integration tests for success, failure, compatibility, and bounded output.
  • Add regression coverage for the issue-specific happy path, failure path, default/disabled path, and artifact/output bounds.
  • Update user-facing docs or inline tool descriptions when hosts must choose a new flag, mode, policy, or workflow.

Success criteria

  • The implementation satisfies the primary deliverable without broadening into non-goals.
  • Existing default behavior remains backward-compatible or the issue explicitly documents the compatibility break.
  • Failure cases return bounded, actionable diagnostics rather than silent fallback or unbounded dumps.
  • Tests/benchmarks cover the concrete surface named in this issue, not only helper utilities.
  • Any produced artifact is deterministic, redacted, and small enough for merge review or stored behind handles.

Post-merge OpenChrome live verification checklist

  • Run the documented local OpenChrome fixture or smoke path for oc_context — portable context handle: export/import only (browserbase adoption C) and capture the exact command/tool calls.
  • Verify act behavior matches the issue goal in both the enabled path and the default/disabled compatibility path.
  • Inspect generated artifacts/logs/responses for bounded size, redaction, source links, and clear failure diagnostics.
  • Record sanitized output excerpts, artifact paths, and any benchmark/latency/payload numbers in merge verification notes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium priorityenhancementNew feature or requesthost-integrationWires module cores into host (CDP, MCP, tools, transports, OS APIs)reliabilityReliability and stability improvement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions