feat(facade): session-aware in-process capability sources#1454
Merged
Conversation
- sources module: CapabilitySource trait (optional SessionCtx per call, requires_session gating), SessionTokens registry (broker mints one opaque token per agent session, constant-time resolve, revoke on evict), per-request identity resolution from the Authorization header via the HTTP parts rmcp injects into request extensions. - facade: with_sources/serve_http_with; discovery merges source tools (downstream names win, shadowed source tools published as provider:tool); execution dispatches sources first with the same schema pre-flight the meta-tool applies, audit lines carry channel. - Session-bound sources are invisible AND unreachable to anonymous clients (no dangling catalog entries, nothing to probe). - Anonymous behavior with zero sources is byte-identical to before. Groundwork for routing #1447's per-session browser capability through the facade (one listener, one discovery surface).
…r session tokens Self-review findings: - BUG: execution dispatched sources before the downstream catalog while discovery publishes downstream-wins-bare-name — a source tool sharing a downstream tool's name would hijack calls addressed to the downstream tool. Execution now resolves the catalog first (mirroring the publish rule); shadowed source tools stay reachable via provider:tool. - GAP: the rmcp Parts-into-extensions mechanism (which token resolution rides on) had no end-to-end coverage. Added build_router + a tower oneshot test driving real HTTP initialize→tools/call with/without/ wrong Authorization, asserting source visibility flips accordingly. - constant_time_eq: black_box the accumulator so the claim is enforced, not asserted in a comment.
…ce calls Self-review round 2: - Discovery's collision set now grows as sources publish, so two sources sharing a tool name no longer produce duplicate catalog entries — the first registrant keeps the bare name, later ones publish as provider:tool (matching execution's registration-order resolution). - Source-call audit lines now carry args_sha256 like the meta_tool dispatcher's — one audit shape across both dispatch paths.
thepagent
approved these changes
Jul 25, 2026
pahud
pushed a commit
to brettchien/openab
that referenced
this pull request
Jul 25, 2026
…ade mode, default) Routes browser tools through the OAB MCP Facade as a session-aware in-process capability source (openab-mcp openabdev#1454), replacing per-session proxy servers as the default transport. Proxy and Option C bridge modes are unchanged and remain explicit opt-outs (OPENAB_BROWSER_MODE). - src/browser_source.rs: CapabilitySource over the existing AcpMcpTunnel (requires_session; D4 static-advertise; tunnel errors surface as MCP error results); FacadeRegistrar adapts the facade's SessionTokens to core's new SessionTokenRegistrar hook (core stays openab-mcp-free). - core mcp_proxy: BrowserMode::Facade (new default; runtime fallback to Proxy when no facade is serving), write_facade_mcp_config — a static, write-once 'openab' entry whose Authorization references ${OPENAB_SESSION_TOKEN}; the per-session secret rides the agent process env instead of config files, eliminating the shared-workdir clobber class entirely (incl. kiro --agent files + @OpenAB allowlist). - pool: with_facade_sessions wiring; mints/injects the token per spawn, revokes via the same DropGuard plumbing proxy mode uses. - main: facade constructed with the BrowserSource; one listener, one discovery surface (search_capabilities/execute_capability). - rmcp re-exported from openab-mcp for source implementors. - docs: facade-mode section in the browser setup guide.
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Groundwork for routing #1447's per-session browser capability through the facade (one listener, one discovery surface), per tonight's design discussion. Self-contained: no behavior change for existing deployments.
What's added
sourcesmodule (openab-mcp):CapabilitySourcetrait — in-process providers registered at facade construction (no mcp.json entry, no extra listener, no subprocess). Every call receives an optionalSessionCtx;requires_session()marks session-bound sources.SessionTokens— the broker↔facade identity contract: broker mints one opaque token per agent session (delivered to that agent's MCP config asAuthorization: Bearer), revokes on evict; facade resolves it per request from the HTTP parts rmcp injects into request extensions (documented rmcp 1.7 mechanism — stateless, no session-binding map). Constant-time token comparison.with_sources/serve_http_with; discovery merges source tools into the catalog (downstream names win; shadowed source tools published asprovider:tool, mirroring the existing duplicate rule); execution dispatches sources first with the same JSON-Schema pre-flight the meta-tool applies; audit lines carry the channel id.Self-review round 2
Two more findings, fixed:
provider:tool(matching execution's registration-order resolution; regression test added).args_sha256like the meta_tool dispatcher — one audit shape across both dispatch paths.Noted-not-changed (deliberate):
SessionTokensusesstd::sync::RwLockwithexpect(no user code in the critical sections, poisoning is unreachable short of an allocator panic); execution resolving the downstream catalog before source dispatch adds a mostly-cache-hit lookup to source calls — consistency with the publish rule is worth that.Validation
openab-mcp: 214 tests pass (7 new: full-HTTP session-gating e2e; token mint/replace/revoke lifecycle, constant-time eq, ctx-from-http-parts resolution incl. no-parts/wrong-token; facade: session-bound invisibility+unreachability, ctx-routed execution, anonymous host-level source + schema pre-flight rejection)--workspace --all-features -D warningsclean; fmt cleanReview Contract
Goal
Give the facade a session-aware in-process capability-source interface and a broker-shared session-token registry, so session-bound capabilities (browser control, #1447) can later be served through the single facade listener and discovery surface.
Non-goals
Accepted Residual Risks
Acceptance Criteria
requires_sessionsource (tests).tower.rsdocumentedParts-in-extensions pattern).Follow-ups
BrowserSourcein the root binary (tunnel-backed), SessionPool mint/revoke + config-writer reuse, retire the per-session proxy default (Option C bridge untouched).requires_session=falsesource, retiring its separate port.