Context
PR #14942 is the third bounded cleanup batch under parent epic #12456. It converts the shared MCP transport host from an inline process.env.HOST || 'localhost' derivation into the owning reactive AiConfig realm while preserving the existing HOST operator binding.
This leaf exists so the already-complete one-PR implementation has a native, non-epic close target. Live latest-open and recent A2A claim sweeps immediately before creation found no equivalent ticket.
The Problem
ai/mcp/server/shared/services/TransportService.mjs derives the advertised SSE/HTTP host beside other values that already come from AiConfig. The inline environment read and hidden default duplicate resolution outside the Provider, matching ADR 0019 §3 A1. Pointing the PR at parent epic #12456 cannot truthfully close that multi-leaf workstream and fails the agent PR-body gate.
The Architectural Reality
ai/config.template.mjs is the Tier-1 realm root for shared MCP transport values.
- Child MCP-server configs inherit root leaves through the ConfigProvider parent chain.
TransportService.setup() is the use site and already consumes the resolved aiConfig realm.
Neo.util.Env.parseString treats absent and empty-string values as absent, preserving the prior || 'localhost' behavior when the leaf default is localhost.
- Tests must exercise resolved provider state and the explicit env-binding seam; they must not mutate the shared AiConfig singleton.
The structure-map gate confirms these are existing owning substrates: ai/config.template.mjs, ai/mcp/server/shared/services/TransportService.mjs, and their existing unit specs. No new file or service boundary is introduced.
The Fix
- Add root leaf
mcpHttpHost: leaf('localhost', 'HOST', 'string') in the shared MCP transport cluster.
- Read
aiConfig.mcpHttpHost directly at the TransportService use site.
- Keep public URL precedence unchanged.
- Replace raw-env mutation tests with resolved-config inputs, plus one provider-level
HOST binding regression.
- Retain the complete env-read census so deferred runtime-identity, credential, process-metadata, and safety-guard reads are not accidentally converted into config.
Contract Ledger
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
AiConfig.mcpHttpHost |
ADR 0019 + ai/config.template.mjs |
Root transport host leaf bound to HOST |
Literal localhost when absent/empty |
JSDoc on leaf |
Provider env-binding spec |
| SSE/HTTP advertised host |
TransportService.setup() |
Read resolved leaf at use site; publicUrl still wins |
Root/parent-chain resolution |
Existing service JSDoc |
TransportService specs + runtime probe |
| Env-read census |
ADR 0019 §3/§5 |
Classify every surveyed read by ownership |
Explicit defer/skip rationale |
PR/ticket ledger |
Exact source sweep |
Decision Record impact
Aligned with ADR 0019. This ticket applies its A1 use-site-read rule and does not amend the ADR.
Acceptance Criteria
Out of Scope
- Folding the five per-server
npm_package_version duplicates.
- Moving process identity, session identity, credential injection, or destructive-operation confirmation into AiConfig.
- Any new MCP transport mode or URL contract.
Avoided Traps
- Duplicating
mcpHttpHost on every server config instead of using the realm root.
- Keeping
process.env.HOST as a defensive fallback beside the resolved leaf.
- Converting fail-closed safety or runtime-identity reads merely because they are environment reads.
- Splitting the leaf, consumer, and tests into separate PRs.
Related
- Parent epic: #12456
- Implementation PR: #14942
- Adjacent batches: #14935 and #14941
- Authority:
learn/agentos/decisions/0019-aiconfig-reactive-provider-ssot.md
Origin Session ID: de713f27-0e82-4960-b4c6-f281e0c36449
Handoff Retrieval Hints
- Memory Core:
ADR 0019 mcpHttpHost TransportService HOST realm chain
- Exact implementation anchor: PR #14942 at
38fcee8d047ba814dd83fbde1f5220bf1269f548
Context
PR #14942 is the third bounded cleanup batch under parent epic #12456. It converts the shared MCP transport host from an inline
process.env.HOST || 'localhost'derivation into the owning reactive AiConfig realm while preserving the existingHOSToperator binding.This leaf exists so the already-complete one-PR implementation has a native, non-epic close target. Live latest-open and recent A2A claim sweeps immediately before creation found no equivalent ticket.
The Problem
ai/mcp/server/shared/services/TransportService.mjsderives the advertised SSE/HTTP host beside other values that already come from AiConfig. The inline environment read and hidden default duplicate resolution outside the Provider, matching ADR 0019 §3 A1. Pointing the PR at parent epic #12456 cannot truthfully close that multi-leaf workstream and fails the agent PR-body gate.The Architectural Reality
ai/config.template.mjsis the Tier-1 realm root for shared MCP transport values.TransportService.setup()is the use site and already consumes the resolvedaiConfigrealm.Neo.util.Env.parseStringtreats absent and empty-string values as absent, preserving the prior|| 'localhost'behavior when the leaf default islocalhost.The structure-map gate confirms these are existing owning substrates:
ai/config.template.mjs,ai/mcp/server/shared/services/TransportService.mjs, and their existing unit specs. No new file or service boundary is introduced.The Fix
mcpHttpHost: leaf('localhost', 'HOST', 'string')in the shared MCP transport cluster.aiConfig.mcpHttpHostdirectly at the TransportService use site.HOSTbinding regression.Contract Ledger
AiConfig.mcpHttpHostai/config.template.mjsHOSTlocalhostwhen absent/emptyTransportService.setup()publicUrlstill winsDecision Record impact
Aligned with ADR 0019. This ticket applies its A1 use-site-read rule and does not amend the ADR.
Acceptance Criteria
mcpHttpHostwith defaultlocalhost, env bindingHOST, and string parsing.process.env.HOSTread and consumes the resolved leaf at the use site.publicUrlprecedence and the absent/empty-HOSTbehavior remain unchanged.Resolves #Nfor this leaf.Out of Scope
npm_package_versionduplicates.Avoided Traps
mcpHttpHoston every server config instead of using the realm root.process.env.HOSTas a defensive fallback beside the resolved leaf.Related
learn/agentos/decisions/0019-aiconfig-reactive-provider-ssot.mdOrigin Session ID: de713f27-0e82-4960-b4c6-f281e0c36449
Handoff Retrieval Hints
ADR 0019 mcpHttpHost TransportService HOST realm chain38fcee8d047ba814dd83fbde1f5220bf1269f548