Skip to content

docs(adr): OAB MCP adapter#1446

Draft
chaodu-obk[bot] wants to merge 14 commits into
mainfrom
docs/adr-oab-mcp-adapter-mvp
Draft

docs(adr): OAB MCP adapter#1446
chaodu-obk[bot] wants to merge 14 commits into
mainfrom
docs/adr-oab-mcp-adapter-mvp

Conversation

@chaodu-obk

@chaodu-obk chaodu-obk Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

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-agent MCP 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_capabilities and execute_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 5
Loading

The 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

  • Existing OpenAB docs/adr/openab-agent-mcp.md: provides the downstream MCP client, layered mcp.json, lazy connection, OAuth, and progressive disclosure.
  • OpenWork is the primary product inspiration: its Connect and MCP model shows how an agent can access authorized external capabilities through one progressive-discovery boundary.
  • OpenWork's visible Connect services include Gmail, Google Calendar, Google Drive, Slack, Notion, and Linear; its hosted/custom MCP model extends to services such as Stripe, Sentry, Exa, and Context7.
  • OpenWorker is complementary implementation prior art: its local agent server uses a connector registry with native provider adapters and optional MCP, rather than forcing every integration through MCP.
  • OpenWorker's Gmail connector uses OAuth access tokens and direct Gmail REST tools (gmail_search_messages, gmail_get_message, gmail_send_email); its generic IMAP/SMTP email connector is a separate path.
  • OAB adopts OpenWorker's account lifecycle, tool-level privacy filtering, and approval-gated writes for the Capability Plugin / Native Adapter path, while retaining the two-method facade.
  • OAB adopts this access vision for the OAB Agent: these and future approved services should be reachable through the same search_capabilities / execute_capability facade, without promising provider parity in this MVP.
  • Notion and Gmail hosted MCP are the current MVP profiles; other services are roadmap candidates that can use the hosted MCP or plugin/native adapter path after auth and safety review.
  • Notion: provides the hosted https://mcp.notion.com/mcp server with user OAuth and agent-oriented tools.
  • Google: provides https://gmailmcp.googleapis.com/mcp/v1, currently documented as a Developer Preview with gmail.readonly and gmail.compose scopes.
  • OpenClaw: is primarily a channel gateway, so its MCP patterns are not a direct model for the native OpenAB agent client.
  • Hermes Agent: provides relevant per-server lifecycle, OAuth, failure isolation, and circuit-breaker prior art.

4. Proposed Solution

  • Name the feature OAB MCP and expose an OAB MCP Facade to the agent.
  • Keep search_capabilities and execute_capability as the only public facade methods in the MVP.
  • Return only configured, authorized, policy-allowed capabilities from search_capabilities, including the exact input schema plus risk and availability metadata.
  • Require execute_capability to use an exact discovered capability name and schema-validated arguments.
  • Position the OAB Agent to access approved external capabilities through this same facade as the provider catalog grows, following OpenWork's Connect/MCP model rather than binding access to one coding CLI.
  • Keep ~/.openab/agent/mcp.json and project .openab/agent/mcp.json as the downstream adapter configuration source of truth.
  • Reuse McpRuntimeManager, OAuth/PKCE, credential storage, lazy connection, tool filtering, timeout, redaction, and circuit breaker for outbound provider connections.
  • Provide an extension point for services without hosted MCP through a capability plugin/native adapter using a provider API or SDK; this path is outside the Notion/Gmail hosted-MCP MVP.
  • Support Notion hosted MCP with conservative read-first tooling.
  • Support Gmail hosted MCP as an explicit Developer Preview integration for search/read and draft creation only; direct send/delete are excluded.

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

  • Native Gmail and Notion REST adapters: rejected for this MVP because they duplicate provider clients and OAuth/API maintenance.
  • Let each backing coding CLI configure providers independently: rejected as the OAB default because auth, filtering, and diagnostics would diverge by CLI.
  • Add a second generic inbound MCP server: rejected; the scoped OAB MCP Facade is the intentional inbound boundary, and another server would blur its two-method contract.
  • Flatten every provider tool into the top-level agent tool list: rejected; the facade's two methods and lazy discovery preserve prompt and tool-selection budgets.
  • Add a duplicate top-level [mcp] TOML source: rejected; openab-agent already owns layered .openab/agent/mcp.json configuration.

7. Validation

  • git diff --check passed.
  • The ADR JSON example was parsed successfully with Perl JSON::PP.
  • Relative ADR links resolve.
  • Notion, Gmail MCP, and referenced official documentation URLs were probed successfully.
  • This PR is docs-only; Python and Cargo are unavailable in the current environment, so Rust checks are not applicable to this change.

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 ACP session/new mcpServers over a
loopback-only listener, reusing the existing openab-agent MCP runtime for
hosted Notion and Gmail (Developer Preview) connections.

Non-goals

  • No code, Helm, or config behavior changes in this PR (docs only).
  • No native Gmail/Notion REST adapters, no second outbound MCP client, no new
    top-level [mcp] TOML source, no capability-plugin implementation.
  • No provider parity promise with OpenWork's Connect catalog.

Accepted Residual Risks

  • Gmail hosted MCP is a Developer Preview: the contract may change or break.
    Mitigation: explicit opt-in, preview label, read/draft-only scopes, and a
    documented native-adapter follow-up decision (rollout step 5).
  • External provider docs (Notion/Gmail tool names, endpoints) may drift after
    merge. Mitigation: the implementation PR re-verifies against live
    tools/list, and cache invalidation handles tools/list_changed.
  • Backing CLIs that ignore ACP mcpServers cannot use the facade in the MVP;
    documented as unavailable rather than worked around via CLI config edits.

Acceptance Criteria

  • ADR follows the tiered PR template (problem, prior art with sources,
    proposal, alternatives, risks, rollout, validation).
  • All relative ADR links resolve on the merged tree; external provider claims
    match official documentation; the JSON config example parses and uses only
    real openab-agent MCP config schema fields.
  • The facade's transport/registration and its relationship to the existing
    mcp meta-tool are explicitly specified (review round 1 findings F2/F3).
  • No source, chart, or CI files are touched.

Follow-ups

  • Implementation PR with the §11 automated checks (config layering, tool
    filters, OAuth allowlist, mocked Streamable HTTP flows) and provider smoke
    tests as acceptance criteria.
  • Decision on converging the mcp meta-tool action vocabulary with the facade
    method names (breaking change to the accepted meta-tool contract).
  • Gmail hosted-MCP vs. native-adapter decision after preview stability review.

@chaodu-obk
chaodu-obk Bot requested a review from thepagent as a code owner July 24, 2026 01:55
@thepagent thepagent changed the title docs(adr): define OAB MCP adapter MVP docs(adr): OAB MCP adapter Jul 24, 2026
@thepagent
thepagent marked this pull request as draft July 24, 2026 02:32

@chaodu-agent chaodu-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Important

CHANGES REQUESTED ⚠️ — Well-researched ADR with verified provider claims and a correct reuse strategy, but the PR is missing the required Review Contract section, and two load-bearing design points (facade transport/registration and the relationship to the existing 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.md plus openab-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 doctor commands cited in §11 exist (openab-agent/src/main.rs:149-159)
  • Relative link ./openab-agent-mcp.md resolves
  • Gmail claims vs. Google's official doc (fetched 2026-07-24): Developer Preview label ✅, endpooint https://gmailmcp.googleapis.com/mcp/v1 ✅, scopes gmail.readonly+gmail.compose ✅, tools search_threads/get_thread/get_message/create_draft all in the official tool reference ✅, no send tool exists upstream ✅
  • Notion claims vs. official supported-tools doc: notion-search, notion-fetch, notion-get-async-task all 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

  1. The meta-tool may already be the facade — if the existing mcp meta-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).
  2. 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.
  3. Config-only alternative — operators can already point mcp.json at 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
chaodu-agent previously approved these changes Jul 24, 2026

@chaodu-agent chaodu-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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 Contract section

✅ 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 mcp meta-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.md and ./openab-agent-mcp.md resolve on the branch
  • JSON config example still parses; git diff --check clean
  • 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.
chaodu-agent added a commit that referenced this pull request Jul 24, 2026
…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.
chaodu-agent added a commit that referenced this pull request Jul 24, 2026
…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.
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.

1 participant