# ADR-0092: Fail-closed external integration registry

- **Status:** Accepted
- **Date:** 2026-09-16
- **Decision owners:** Eve platform, Oshun workbench, security, and privacy
  maintainers
- **Registry contract:** `eve.external-integration-registry.v1`

## Context

Eve currently has one production external-tool surface: the `oshun-workbench`
MCP stdio server used by external coding agents. It holds a scoped workbench
bearer and exposes seven tools. The registry also contains the executable
`bellona-protected-http` reference peer. That peer is exercised locally over a
real Streamable HTTP transport, but is not a deployed endpoint and exposes only
the read-only `bellona_ping` proof tool. Task 4.6 pins both records' owners,
sources, versions, transports, tool risk classes, credential destinations, and
protocol versions.

There is no adopted external-agent protocol or production external-agent
integration. ADR-0091 deliberately defers A2A, and the A2A-shaped Iris and Oshun
libraries are private, unmounted, non-conformant prototypes. They are not
registry entries.

The admin integrations store is not this boundary. It manages operator-created
API keys, webhooks, and connector status; it does not decide whether Eve may
load or call an external tool or agent. The enforceable boundary is the client
admission path immediately before the workbench server registers tools.

## Decision

`EXTERNAL_INTEGRATION_REGISTRY` in `tools/workbench-mcp/trust.mjs` is the
authoritative source-controlled registry. `MCP_SERVER_INVENTORY` remains an
alias for existing MCP callers. Each entry must identify:

- integration kind and protocol;
- accountable owner;
- source path, version, SHA-256, and transport;
- integration-level risk class and per-tool risk classes;
- explicit permissions, credentials, configuration, destination origins, and
  data classes sent there;
- lifecycle state (`active`, `quarantined`, or `revoked`);
- health status, observation time, expiry, and evidence;
- evaluation status, observation time, expiry, and evidence;
- owner review time, expiry, reviewer, and evidence; and
- the exact name set plus SHA-256 pins for every tool input schema and
  description.

Admission is default-deny. An absent entry, missing required field, unknown kind
or lifecycle, quarantine, revocation, unhealthy or unknown status, failed or
pending evaluation, expired health/evaluation/review, changed source, version,
transport, tool set, schema, or description makes the integration unavailable.
Each failure has a stable refusal code. The server performs this governance
decision before registering its first tool, and a caller's combined tool-call
admission repeats it before considering protocol, annotation, credential,
authorization, and consent controls.

The registry currently has two entries. The production workbench entry's seven
schema and description pins were measured from a live MCP `tools/list` response.
The protected-HTTP reference entry's single tool is measured through an official
MCP SDK client against a real local HTTP server; its
`deployment: local-reference` field makes its non-production status explicit.
Both records' health expires after 30 days and their evaluation and owner review
after six months. Renewal means rerunning the relevant tests, reading source and
surface diffs, recording new evidence, and deliberately updating the dates and
hashes. Merely extending an expiry is not a review.

Publish-class workbench tools do not rely on a third-party client's approval UI.
A first MCP call without a consent id creates an exact non-executing impact
preview in the BFF. A distinct operator credential approves or declines it, and
the BFF binds the one-shot approval to actor, tenant, tool, and canonical
arguments before either shipment or verification can execute. The step-up
credential must differ from the shared bearer and every per-agent bearer.

The schema permits `kind: agent`, but there are zero agent entries. A future
agent integration must first satisfy ADR-0091's adoption conditions, then add
its protocol-specific discovery/card and capability pins. Unknown agents are
unavailable by absence; the registry does not create a placeholder that could be
mistaken for admission.

New live third-party admissions also remain subject to the dependency gates
owned by Tasks 4.8, 12.7, 13.7, and 14.7. This ADR prepares and enforces the
registry mechanism; it does not waive those release, red-team, operational, or
privacy obligations and does not claim Task 16.5 closed while its prerequisites
remain open.

## Consequences

Review is now operational state rather than prose. A forgotten integration ages
out; a changed description is treated as tool poisoning rather than a cosmetic
edit; and quarantine/revocation stop startup instead of relying on an operator
to remember not to call a tool. Source-controlled metadata makes every admission
change reviewable and binds the permission and data-destination story to the
same commit as the executable gate.

The deliberate cost is maintenance. Health checks must be renewed monthly,
evaluations and reviews must be renewed at least every six months, and ordinary
tool edits require new schema/description and source pins. A stale registry can
stop the workbench MCP server with exit code 78; that is the intended safe
failure.

## Verification

The adversarial trust suite produces and asserts every refusal code, including
missing metadata, quarantine, revocation, unhealthy and unevaluated states,
three expiry paths, and schema and description drift. The stdio interop suite
launches the real workbench server with the official MCP SDK, negotiates a
protocol version, reads the live seven-tool surface, and checks its schemas,
descriptions, and policy-derived annotations against the registry. Separate live
negative cases prove bad credential destinations prevent the server from serving
any tools.

The protected-HTTP integration suite starts a real local HTTP server, discovers
its path-aware protected-resource metadata, connects an official Streamable HTTP
MCP client with an exact-audience token, lists and calls `bellona_ping`, then
observes a wrong-audience token refused on the wire. The Task 16.3 suite
separately proves the same resource identifier is sent on both OAuth resource
indicator legs. Workbench route tests prove a preview performs no mutation, an
agent bearer cannot self-approve, exact approved arguments execute once, and a
replay or argument change is refused; a PostgreSQL integration test observes the
single real shipped transition.

Task 16.5 evidence and checklist closure are deferred until all dependency tasks
named by the evidence-exit matrix are complete.
