Epic #15184 needs a standards-compliant local Streamable HTTP ingress that is actually confined to loopback and does not introduce a user-identity system. The approved source contract lives in D#15173.
Live duplicate sweep: checked the latest 20 open issues, broader GitHub search, recent A2A claims, Knowledge Base tickets, and synced issue/discussion content at 2026-07-14T22:02:06.716Z; no equivalent active ticket exists. Closed transport/auth work provides reusable primitives but does not provide this opt-in local contract.
Self-selection boundary: Neo-maintainer implementation lane. External contributors may supply falsifiers or focused tests, but shared transport/auth/config architecture remains Neo-maintainer-owned.
The Problem
TransportService computes an advertised URL from mcpHttpHost but currently calls app.listen(port), so the actual listener bind is not pinned to that host. The shared Express app also installs wildcard CORS, while the required non-browser probe needs the narrower rule: accept an absent Origin, reject every present Origin, and retain the existing Host allowlist.
The existing auth strategies are OIDC and long-lived GitLab PAT validation. Neither is the correct boundary for a one-run local probe. The missing mode is a generated process-lifetime bearer that proves possession without creating or resolving an identity.
A global rebinding or auth rewrite would put existing KB/MC deployments at risk. The change must be opt-in and fail closed only for the new local mode.
The Architectural Reality
The shared authority is ai/config.mjs / ai/config.template.mjs plus ai/mcp/server/shared/services/TransportService.mjs and AuthService.mjs.
mcpHttpHost is the advertised host; it is not presently the listener bind.
TransportService.setup() installs wildcard CORS before /mcp and invokes app.listen(port).
auth.mode already selects the shared auth strategy.
ADR 0019 governs every new AiConfig leaf: provider-owned declarative configuration, read at the use site, with no env re-derivation, pass-along aliases, hidden defaults, runtime mutation, or defensive optional chaining.
The Fix
Add an opt-in mcpListenHost AiConfig leaf at the shared transport authority. When absent, preserve the existing listener behavior. When auth.mode === 'local-bearer', startup requires mcpListenHost === '127.0.0.1' and a process-lifetime bearer supplied through a declarative auth leaf.
Add a narrow local-bearer verifier to the existing auth seam. The journey/launch path generates 32 cryptographically random bytes and encodes them as unpadded base64url, injects the value into the server and reference client, and never writes it through Neo logging, SQLite, files, or durable configuration.
Install the local-mode Origin rejection before wildcard CORS and before MCP dispatch. Host allowlisting, Origin policy, actual bind, and bearer verification remain independent guards.
Contract Ledger
Target Surface
Source of Authority
Proposed Behavior
Fallback / Compatibility
Docs
Evidence
mcpListenHost
Shared AiConfig Provider under ADR 0019
Optional actual listener bind; local-bearer mode requires literal 127.0.0.1
Absent leaf preserves current app.listen(port) behavior for existing profiles
Config JSDoc + template
Provider/config tests + socket reachability probe
auth.mode = 'local-bearer'
Shared AuthService strategy switch
Validate one process-lifetime secret without identity lookup
Shared AiConfig defines optional mcpListenHost and the local-bearer secret leaf in both canonical config/template surfaces under ADR 0019; consumers read them directly at the use site.
Existing profiles preserve their current listener behavior when mcpListenHost is absent.
auth.mode === 'local-bearer' fails startup unless the actual bind is literal 127.0.0.1 and a non-empty bearer is configured.
The launch/reference path generates exactly 32 random bytes, encodes unpadded base64url, and supplies the same one-run value to server and client without logger, database, file, or durable-config persistence.
Bearer validation uses a constant-time comparison for equal-length byte sequences and rejects length mismatches, missing headers, malformed schemes, and invalid values.
Local-bearer middleware accepts an absent Origin and rejects every present Origin before CORS or MCP dispatch.
Host allowlisting remains independently enforced.
Focused evidence proves: valid local request succeeds; present Origin, invalid Host, missing/invalid bearer, and non-loopback reachability all fail.
Regression coverage proves existing KB/MC OIDC, GitLab-PAT, proxy-identity, and unauthenticated local-dev profiles retain their current behavior.
Changed classes/methods/config leaves satisfy Contextual Completeness JSDoc and @summary requirements.
Out of Scope
Public/cloud authentication, GitHub PAT/OAuth/OIDC, or tenant identity.
Legacy HTTP+SSE support.
Neural Link tool projection or BigData journey behavior.
Rebinding existing deployment profiles by default.
Context
Epic #15184 needs a standards-compliant local Streamable HTTP ingress that is actually confined to loopback and does not introduce a user-identity system. The approved source contract lives in D#15173.
Live duplicate sweep: checked the latest 20 open issues, broader GitHub search, recent A2A claims, Knowledge Base tickets, and synced issue/discussion content at 2026-07-14T22:02:06.716Z; no equivalent active ticket exists. Closed transport/auth work provides reusable primitives but does not provide this opt-in local contract.
Self-selection boundary: Neo-maintainer implementation lane. External contributors may supply falsifiers or focused tests, but shared transport/auth/config architecture remains Neo-maintainer-owned.
The Problem
TransportServicecomputes an advertised URL frommcpHttpHostbut currently callsapp.listen(port), so the actual listener bind is not pinned to that host. The shared Express app also installs wildcard CORS, while the required non-browser probe needs the narrower rule: accept an absentOrigin, reject every presentOrigin, and retain the existing Host allowlist.The existing auth strategies are OIDC and long-lived GitLab PAT validation. Neither is the correct boundary for a one-run local probe. The missing mode is a generated process-lifetime bearer that proves possession without creating or resolving an identity.
A global rebinding or auth rewrite would put existing KB/MC deployments at risk. The change must be opt-in and fail closed only for the new local mode.
The Architectural Reality
The shared authority is
ai/config.mjs/ai/config.template.mjsplusai/mcp/server/shared/services/TransportService.mjsandAuthService.mjs.mcpHttpHostis the advertised host; it is not presently the listener bind.computeAllowedHosts()already owns Host-header DNS-rebinding protection.TransportService.setup()installs wildcard CORS before/mcpand invokesapp.listen(port).auth.modealready selects the shared auth strategy.The Fix
Add an opt-in
mcpListenHostAiConfig leaf at the shared transport authority. When absent, preserve the existing listener behavior. Whenauth.mode === 'local-bearer', startup requiresmcpListenHost === '127.0.0.1'and a process-lifetime bearer supplied through a declarative auth leaf.Add a narrow local-bearer verifier to the existing auth seam. The journey/launch path generates 32 cryptographically random bytes and encodes them as unpadded base64url, injects the value into the server and reference client, and never writes it through Neo logging, SQLite, files, or durable configuration.
Install the local-mode Origin rejection before wildcard CORS and before MCP dispatch. Host allowlisting, Origin policy, actual bind, and bearer verification remain independent guards.
Contract Ledger
mcpListenHost127.0.0.1app.listen(port)behavior for existing profilesauth.mode = 'local-bearer'AuthServicestrategy switchOriginon local-bearer requestsTransportServicemiddleware ordercomputeAllowedHosts()Decision Record impact
aligned-with ADR 0019 and ADR 0020; no ADR amendment.Decision Record
NOT_NEEDED— consumes existing shared transport/auth/config authority.Acceptance Criteria
mcpListenHostand the local-bearer secret leaf in both canonical config/template surfaces under ADR 0019; consumers read them directly at the use site.mcpListenHostis absent.auth.mode === 'local-bearer'fails startup unless the actual bind is literal127.0.0.1and a non-empty bearer is configured.Originand rejects every presentOriginbefore CORS or MCP dispatch.@summaryrequirements.Out of Scope
Related
Parent Epic: #15184
Source: D#15173
Refs #13056
Refs #11003
Origin Session ID:
5b19219a-d8ad-4505-864f-19b5eab44a45Retrieval Hint:
#15184 mcpListenHost TransportService local-bearer absent Origin Host allowlist ADR 0019