docs(adr): OAB MCP adapter#1446
Conversation
chaodu-agent
left a comment
There was a problem hiding this comment.
Important
CHANGES REQUESTED mcp meta-tool) are unspecified and would be the first questions an implementer hits.
What This PR Does
Adds a docs-only ADR (docs/adr/oab-mcp-adapter.md, 663 lines) defining the OAB MCP Adapter MVP: an agent-facing OAB MCP Facade exposing exactly two methods (search_capabilities / execute_capability) that delegates to the existing openab-agent MCP runtime for hosted Notion and Gmail (Developer Preview) MCP servers, with a capability plugin/native adapter as a documented extension point.
How It Works
The facade is the inbound MCP boundary; a capability dispatcher enforces auth, policy, catalog, schema validation, and audit; the outbound hosted MCP adapter reuses the existing McpRuntimeManager, OAuth/PKCE, credential store, tool filters, timeouts, and circuit breaker. Activation stays config-presence-based via layered .openab/agent/mcp.json — no new TOML source of truth, no behavior change for existing deployments.
Findings
| # | Severity | Finding | Location |
|---|---|---|---|
| 1 | 🟡 | PR body is missing the required ## Review Contract section (Goal / Non-goals / Accepted Residual Risks / Acceptance Criteria / Follow-ups) |
PR description |
| 2 | 🟡 | Facade transport and registration with the coding CLI are unspecified; no reconciliation with the merged ACP-server work (#1418) or acp-server-websocket-mcp-browser.md's "core as MCP proxy/aggregator" role |
docs/adr/oab-mcp-adapter.md §6.1 |
| 3 | 🟡 | Relationship between the facade's two methods and the existing LLM-facing mcp meta-tool (list_servers/list_tools/describe_tool/call/status) is undefined — risk of two discovery/execution surfaces for the same providers |
docs/adr/oab-mcp-adapter.md §4, §6.3 |
| 4 | 🟢 | All external provider claims verified accurate against official docs; config example fields match the actual serde schema | — |
Finding Details
🟡 F1: Missing Review Contract
AGENTS.md and docs/review-contract.md require every PR body to contain the exact ## Review Contract structure with meaningful content under Goal, Non-goals, Accepted Residual Risks, Acceptance Criteria, and Follow-ups. The current body follows the tiered PR template well, but without the contract section Round 1 cannot freeze a contract, and the acceptance criteria for the follow-up implementation PR (currently scattered through §11) have no canonical home. Suggested fix: add the section; most content already exists in §2 (Goals/Non-goals), §9 (risks), and §11 (validation) and just needs to be condensed into the contract format.
🟡 F2: Facade transport/registration unspecified
§6.1 defines what the facade owns but never says how the coding agent reaches it: stdio subprocess? Streamable HTTP on localhost? An entry OAB injects into each backing CLI's MCP config (each CLI has its own config format)? For the native openab-agent, is it an in-process dispatch rather than a real MCP transport? This is the single net-new integration point of the MVP — everything downstream is reuse — so leaving it open makes the ADR non-actionable for the implementation PR.
Related: main now has the ACP server over WebSocket (#1418, merged after this branch was cut) and docs/adr/acp-server-websocket-mcp-browser.md already positions OpenAB core as an "MCP proxy/aggregator" that re-exposes upstream tools to the agent via mcpServers. The ADR should state whether the OAB MCP Facade is that same component, a sibling behind it, or independent — otherwise Alternative C ("no second generic inbound MCP server") is ambiguous about which inbound server is the first one.
🟡 F3: Facade vs. existing mcp meta-tool
openab-agent/src/mcp/meta_tool.rs already exposes an LLM-facing mcp meta-tool with six actions (help, list_servers, list_tools, describe_tool, call, status) — functionally a superset of search_capabilities/execute_capability for the native agent. The ADR cites this progressive-disclosure design as its foundation (§5.1) but never states whether the facade replaces, wraps, or coexists with the meta-tool. If they coexist, the native agent has two discovery/execution surfaces over the same configured providers, which contradicts the "one stable agent-facing surface" goal and weakens the Alternative D reasoning. One clarifying paragraph in §4 or §6.3 resolves this.
🟢 F4: Verified accuracy
Independently verified rather than trusting the PR's validation section — see Verified below.
Baseline Check
- PR opened: 2026-07-24, head
42566c1, 11 commits, docs-only (+663/-0), mergeable - Main already has: the entire downstream foundation this ADR reuses —
docs/adr/openab-agent-mcp.mdplusopenab-agent/src/mcp/{runtime,oauth,breaker,config,meta_tool,flow,sampling}.rs - Net-new value: the named facade boundary, the two-method contract, the dispatcher responsibilities split, Notion/Gmail MVP profiles, and the plugin extension point — none of this exists on main
- Branch is 2 commits behind main (v0.10.0-beta.2 release, #1418 ACP server over WebSocket); no conflict, but #1418 is relevant to F2
Verified
Docs-only PR — cargo checks not applicable. Verified at head 42566c118dedb10eff36cdf5826e4e14789ea12d:
git diff --check origin/main...pr-1446— clean- JSON config example extracted and parsed with
python3 json.load— valid - Config example fields cross-checked against
openab-agent/src/mcp/config.rs:type: http(ServerConfig serde tag),tool_filter.include(ToolFilter),oauth.discovery,oauth.discovery_allowlist,oauth.scopes(OAuthConfig) — all real fields mcp login/mcp doctorcommands cited in §11 exist (openab-agent/src/main.rs:149-159)- Relative link
./openab-agent-mcp.mdresolves - Gmail claims vs. Google's official doc (fetched 2026-07-24): Developer Preview label ✅, endpooint
https://gmailmcp.googleapis.com/mcp/v1✅, scopesgmail.readonly+gmail.compose✅, toolssearch_threads/get_thread/get_message/create_draftall in the official tool reference ✅, no send tool exists upstream ✅ - Notion claims vs. official supported-tools doc:
notion-search,notion-fetch,notion-get-async-taskall real tool names ✅, hosted endpoint and user-OAuth-only claims ✅
What's Good (🟢)
- Provider claims are accurate, not hand-waved — including correctly labeling Gmail as Developer Preview and excluding send/delete (the upstream server doesn't even offer send, and the profile is conservative on top of that)
- Correct architectural instinct: reuse the existing MCP runtime instead of a second OAuth store/transport/lifecycle; reject a duplicate
[mcp]TOML source - Least-privilege defaults with explicit opt-in for mutations; prompt-injection treated as a first-class risk (matching Google's own security guidance for this exact server)
- Prior-art section does real research (OpenWork, OpenWorker, Notion, Google, OpenClaw, Hermes) with source links, per the tiered PR guidelines
- Rollout plan correctly sequences Notion (stable) before Gmail (preview)
5️⃣ Three Reasons We Might Not Need This PR
- The meta-tool may already be the facade — if the existing
mcpmeta-tool's progressive disclosure is sufficient for the native agent, the MVP might reduce to "add Notion/Gmail profile docs + tool filters" with no new facade component at all (this is why F3 must be answered before implementation). - Gmail preview churn — building on a Developer Preview endpoint risks rework; the ADR mitigates this well (opt-in, preview-labelled, native-adapter follow-up documented), but a Notion-only MVP would carry zero preview risk.
- Config-only alternative — operators can already point
mcp.jsonat these hosted servers today; the incremental value is the policy/catalog/audit boundary, which the ADR should make sure justifies its own component rather than being folded into existing runtime filters.
None of these outweigh the ADR's value — the boundary and naming are worth recording — but F1–F3 should be fixed before freeze.
…onship Address review round 1 (F2, F3): - New $6.2: facade delivered via ACP session/new mcpServers, Streamable HTTP on loopback with per-session token; in-process dispatch for the native agent; reconciled with acp-server-websocket-mcp-browser.md's MCP proxy/aggregator role - $6.4: facade and mcp meta-tool are two frontends over one capability dispatcher; no agent runtime sees both surfaces; meta-tool contract unchanged in the MVP
chaodu-agent
left a comment
There was a problem hiding this comment.
Note
LGTM ✅ — Round 2: all three round-1 findings verified fixed at head 042b468c39d0862793dc15ec3432a0f2f38daedb; no regressions, no scope expansion.
Fix Verification (frozen contract, round-1 findings only)
🟡 F1: PR body is missing the required
## Review Contractsection
✅ Addressed — PR body now contains the full contract (Goal / Non-goals / Accepted Residual Risks / Acceptance Criteria / Follow-ups) with meaningful content in every subsection. The Review Contract CI check, which failed on the previous body, now passes (run 30068078515).
🟡 F2: Facade transport and registration with the coding CLI are unspecified
✅ Addressed in 042b468 — new §6.2 "Facade transport and registration": facade delivered through the ACP session/new mcpServers parameter OAB already sends (crates/openab-core/src/acp/connection.rs), served as Streamable HTTP on a loopback-only listener with a per-session token; in-process dispatch for the native agent; explicit no-fallback rule for CLIs that ignore mcpServers. Reconciled with acp-server-websocket-mcp-browser.md's MCP proxy/aggregator role in §6.2 and Alternative C; the branch was updated with main so that relative link resolves.
🟡 F3: Relationship between the facade and the existing
mcpmeta-tool is undefined
✅ Addressed in 042b468 — new §6.4 subsection: the meta-tool and the facade are two frontends over the same capability dispatcher; no agent runtime sees both surfaces (native agent keeps the in-process meta-tool, external CLIs receive only the facade); meta-tool vocabulary unchanged in the MVP, convergence recorded as a follow-up.
Verified
- Head
042b468, mergeable, all CI checks pass (Review Contract,PR Discussion URL Check,PR Review (Scheduled)) - Relative links
./acp-server-websocket-mcp-browser.mdand./openab-agent-mcp.mdresolve on the branch - JSON config example still parses;
git diff --checkclean - Section renumbering (6.2→6.7) consistent; both intra-doc §-references point at the correct sections
- Diff remains docs-only plus a main merge commit (no source/chart/CI changes) — acceptance criteria of the contract hold
Contract is frozen as recorded in the PR body at this head. Ready for maintainer merge.
The MCP runtime lives in the workspace-excluded openab-agent crate, so the broker cannot serve the facade in-process without duplicating the runtime (which this ADR forbids). The facade is therefore advertised as a stdio 'openab-agent mcp-facade' entry in ACP session/new mcpServers; per-session subprocess = session isolation by construction. Loopback HTTP with per-session tokens is recorded as the follow-up.
…er enforcement Implements the OAB MCP Adapter ADR (#1446) MVP slice in openab-agent: - New 'openab-agent mcp-facade' subcommand: inbound stdio MCP server exposing exactly search_capabilities / execute_capability (ADR §6.1, §6.4), backed by the existing McpRuntimeManager + meta_tool dispatcher (one capability dispatcher, two frontends). - search_capabilities: lazy discovery across all configured servers with per-provider failure isolation, name-collision qualification (server:tool), risk labels from MCP tool annotations, and redacted provider errors in an 'unavailable' list. - execute_capability: exact-name resolution against current discovery, then delegation to the shared call path (jsonschema argument validation, timeouts, circuit breaker, redaction). - tool_filter enforcement (accepted MCP ADR §5.6 contract, previously parsed but unenforced): glob include/exclude applied at discovery (fetch_tools, pre-cache) and execution (call_tool, pre-connect) for both the meta-tool and the facade. - rmcp features: + server, transport-io. Broker-side ACP session/new mcpServers advertisement is PR-2.
…er enforcement Implements the OAB MCP Adapter ADR (#1446) MVP slice in openab-agent: - New 'openab-agent mcp-facade' subcommand: inbound stdio MCP server exposing exactly search_capabilities / execute_capability (ADR §6.1, §6.4), backed by the existing McpRuntimeManager + meta_tool dispatcher (one capability dispatcher, two frontends). - search_capabilities: lazy discovery across all configured servers with per-provider failure isolation, name-collision qualification (server:tool), risk labels from MCP tool annotations, and redacted provider errors in an 'unavailable' list. - execute_capability: exact-name resolution against current discovery, then delegation to the shared call path (jsonschema argument validation, timeouts, circuit breaker, redaction). - tool_filter enforcement (accepted MCP ADR §5.6 contract, previously parsed but unenforced): glob include/exclude applied at discovery (fetch_tools, pre-cache) and execution (call_tool, pre-connect) for both the meta-tool and the facade. - rmcp features: + server, transport-io. Broker-side ACP session/new mcpServers advertisement is PR-2.
0. Discord Discussion URL
The design was discussed in the OpenAB Discord thread. No public Discord URL is included in the repository context.
1. What problem does this solve?
OpenAB's native
openab-agentMCP client already supports generic local and remote MCP servers, but the repository lacks a first-class boundary for supported external services. This ADR defines the OAB MCP Adapter MVP and an OpenWork-style, agent-facing OAB MCP Facade for Notion and Gmail.The facade exposes exactly two stable methods:
search_capabilitiesandexecute_capability. OAB performs authorization, discovery, schema validation, and policy checks, then the outbound adapter calls the configured external MCP server. The design does not duplicate the existing downstream MCP runtime or reimplement Gmail/Notion REST clients.2. At a Glance
flowchart TD subgraph OAB_POD [OAB Pod - deployment boundary] A["Coding CLI / Agent<br/>MCP client"] subgraph OAB_RUNTIME [OAB-owned runtime] F["OAB MCP Facade<br/>search_capabilities<br/>execute_capability"] D["Capability Dispatcher<br/>auth - policy - catalog - audit"] M["Hosted MCP Adapter<br/>outbound MCP client<br/>OAuth - tools/list - tools/call"] P["Capability Plugin / Native Adapter<br/>provider API or SDK"] F --> D D --> M D --> P end A -->|MCP| F end N["Notion hosted MCP<br/>external provider"] G["Gmail hosted MCP<br/>external provider - Developer Preview"] X["External service without hosted MCP<br/>provider API or SDK"] M --> N M --> G P --> X style OAB_POD fill:#0b1220,stroke:#60a5fa,stroke-width:3px style OAB_RUNTIME fill:#111827,stroke:#f59e0b,stroke-width:3px style P stroke-dasharray: 5 5 style X stroke-dasharray: 5 5The OAB Pod is the outer deployment boundary. It contains both the Coding
CLI/Agent MCP client and the inner OAB-owned runtime boundary. The inner
runtime contains the OAB MCP Facade, dispatcher, hosted MCP adapter, and
capability-plugin runtime. Notion, Gmail, and provider APIs remain outside the
OAB Pod; only the outbound adapter or plugin crosses that boundary under OAB
policy and audit controls.
The same facade contract supports both paths: hosted MCP for provider-owned
MCP servers, and a capability plugin/native adapter for services without hosted
MCP. The dashed plugin path is an extension point, not a second agent-facing
API. The MVP profiles in this ADR use hosted MCP for Notion and Gmail.
3. Prior Art & Industry Research
docs/adr/openab-agent-mcp.md: provides the downstream MCP client, layeredmcp.json, lazy connection, OAuth, and progressive disclosure.gmail_search_messages,gmail_get_message,gmail_send_email); its generic IMAP/SMTP email connector is a separate path.search_capabilities/execute_capabilityfacade, without promising provider parity in this MVP.https://mcp.notion.com/mcpserver with user OAuth and agent-oriented tools.https://gmailmcp.googleapis.com/mcp/v1, currently documented as a Developer Preview withgmail.readonlyandgmail.composescopes.4. Proposed Solution
search_capabilitiesandexecute_capabilityas the only public facade methods in the MVP.search_capabilities, including the exact input schema plus risk and availability metadata.execute_capabilityto use an exact discovered capability name and schema-validated arguments.~/.openab/agent/mcp.jsonand project.openab/agent/mcp.jsonas the downstream adapter configuration source of truth.McpRuntimeManager, OAuth/PKCE, credential storage, lazy connection, tool filtering, timeout, redaction, and circuit breaker for outbound provider connections.5. Why This Approach
This preserves the OpenWork-style small agent-facing surface while supporting both hosted MCP contracts and future provider plugins. The facade prevents provider schema and credential details from leaking into agent prompts, and the adapter/plugin paths keep provider-specific transport or API logic behind one policy boundary.
Existing deployments remain unchanged unless the facade and a provider profile are explicitly configured. The plugin/native adapter path is intentionally an extension point for services without hosted MCP, not an additional top-level tool API. Gmail is preview-labelled and opt-in because Google's hosted MCP is currently a Developer Preview. A native Gmail adapter remains a documented follow-up if the hosted contract is not sufficiently stable for production.
6. Alternatives Considered
[mcp]TOML source: rejected;openab-agentalready owns layered.openab/agent/mcp.jsonconfiguration.7. Validation
git diff --checkpassed.JSON::PP.Scope
Docs only:
docs/adr/oab-mcp-adapter.md.Review Contract
Goal
Record an accepted architecture decision for the OAB MCP Adapter MVP: an
agent-facing OAB MCP Facade with exactly two methods (
search_capabilities,execute_capability), delivered via ACPsession/newmcpServersover aloopback-only listener, reusing the existing
openab-agentMCP runtime forhosted Notion and Gmail (Developer Preview) connections.
Non-goals
top-level
[mcp]TOML source, no capability-plugin implementation.Accepted Residual Risks
Mitigation: explicit opt-in, preview label, read/draft-only scopes, and a
documented native-adapter follow-up decision (rollout step 5).
merge. Mitigation: the implementation PR re-verifies against live
tools/list, and cache invalidation handlestools/list_changed.mcpServerscannot use the facade in the MVP;documented as unavailable rather than worked around via CLI config edits.
Acceptance Criteria
proposal, alternatives, risks, rollout, validation).
match official documentation; the JSON config example parses and uses only
real
openab-agentMCP config schema fields.mcpmeta-tool are explicitly specified (review round 1 findings F2/F3).Follow-ups
filters, OAuth allowlist, mocked Streamable HTTP flows) and provider smoke
tests as acceptance criteria.
mcpmeta-tool action vocabulary with the facademethod names (breaking change to the accepted meta-tool contract).