Disciplines · Decisions (ADRs)

ADR-0090: MCP transport authorization boundaries

The repository has one admitted MCP server, oshun-workbench, and it runs over stdio.

4sections3 minread

On this page
  • Status: Accepted
  • Date: 2026-09-16
  • Decision owners: Bellona and Eve platform maintainers
  • Protocol target: MCP 2026-07-28

Context#

The repository has one admitted MCP server, oshun-workbench, and it runs over stdio. It also contains HTTP-shaped MCP libraries and custom hosts, but Task 16.2 found that none is a registered, current-version Streamable HTTP server. Those source surfaces must not become remotely reachable merely because an HTTP listener exists.

MCP defines different credential boundaries by transport. A protected HTTP MCP server is an OAuth resource server. It publishes RFC 9728 protected-resource metadata, accepts access tokens only in the Authorization header, validates that each token was issued for its canonical resource, and returns OAuth challenges for missing, invalid, or insufficient authorization. A stdio server should not run that browser and redirect flow: its client launches a local process and supplies narrowly scoped credentials through the process environment.

Decision#

Any Bellona MCP endpoint made reachable over HTTP must be mounted behind authorizeBellonaMcpProtectedHttpRequest and publish metadata through handleBellonaMcpProtectedResourceMetadata. The endpoint remains unavailable until an authorization server, token verifier, and revocation/rotation store are configured. The gate enforces all of the following on every request:

  • path-aware RFC 9728 protected-resource metadata and an explicit authorization server issuer;
  • OAuth authorization-code planning with PKCE S256, state binding, issuer validation, and the RFC 8707 resource parameter on authorization and token requests;
  • least-privilege initial scopes, one complete insufficient-scope challenge, bounded step-up retries, and explicit scope-hierarchy rules;
  • header-only bearer tokens, mandatory expiry and not-before checks, exact issuer/resource audience validation, revocation, and minimum rotation generations;
  • exact tenant and task binding for every request;
  • a handler principal that contains a one-way token fingerprint but not the raw bearer token; and
  • a downstream boundary that rejects authorization, proxy authorization, cookies, API keys, and credential-shaped query parameters.

The MCP resource server does not issue tokens and does not accept arbitrary upstream tokens. A dedicated identity provider owns user interaction, client registration, token issuance, refresh, and revocation propagation. The resource server only verifies those tokens and enforces local authorization.

For stdio, the admitted process configuration remains .mcp.json plus the MCP trust inventory. Credentials may enter only through declared environment variables, never command arguments or URLs. The stdio process inherits the launching user's local authority, so origin/audience discovery and redirect OAuth are inapplicable; tool risk, destination, disclosure, and consent policy still apply. Promoting a stdio integration to HTTP requires a new registry entry and the protected HTTP gate—it is not a transport toggle.

Consequences#

The gate and OAuth planner are independently testable before a production HTTP listener is admitted. This does not make the legacy Unity or Psyche custom HTTP hosts conformant, and it does not register a Bellona HTTP MCP endpoint. Their Task 16.2 quarantine remains in force until they adopt the current wire protocol, mount this authorization boundary (or an equivalent reviewed one), and pass independent conformance tests.

Token verification remains an injected boundary because JWT validation, introspection, key rotation, and revocation delivery belong to the chosen identity provider. A deployment must use a fail-closed verifier and durable, shared token-status storage; the in-memory store is a deterministic test and single-process reference implementation only.

Verification#

protected-http-auth.test.ts covers metadata discovery, OAuth planning, resource indicators, PKCE/state/issuer checks, least scopes and step-up, audience and expiry failures, rotation and revocation, tenant/task isolation, query-token rejection, and credential-passthrough denial. The Bellona package typecheck, lint, build, and focused MCP suites are release gates for changes to this boundary.