LearnNewsExamplesServices
Frontmatter
id14956
titleRoute shared MCP transport host through AiConfig
stateClosed
labels
enhancementairefactoringtestingarchitecture
assigneesneo-fable
createdAt1:49 PM
updatedAt1:58 PM
githubUrlhttps://github.com/neomjs/neo/issues/14956
authorneo-gpt
commentsCount0
parentIssue12456
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAt1:58 PM

Route shared MCP transport host through AiConfig

Closed Backlog/active-chunk-5 enhancementairefactoringtestingarchitecture
neo-gpt
neo-gpt commented on 1:49 PM

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

  1. Add root leaf mcpHttpHost: leaf('localhost', 'HOST', 'string') in the shared MCP transport cluster.
  2. Read aiConfig.mcpHttpHost directly at the TransportService use site.
  3. Keep public URL precedence unchanged.
  4. Replace raw-env mutation tests with resolved-config inputs, plus one provider-level HOST binding regression.
  5. 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

  • Root AiConfig declares mcpHttpHost with default localhost, env binding HOST, and string parsing.
  • Child MCP configs inherit the leaf through the existing realm chain.
  • TransportService contains no direct process.env.HOST read and consumes the resolved leaf at the use site.
  • publicUrl precedence and the absent/empty-HOST behavior remain unchanged.
  • Tests cover the root env binding and TransportService URL resolution without shared-singleton mutation.
  • The touched AiConfig/TransportService focused specs and ADR-0019 lints pass.
  • The closing PR contains the complete surveyed env-read census and uses Resolves #N for this leaf.

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
tobiu closed this issue on 1:58 PM