LearnNewsExamplesServices
Frontmatter
id10808
titleOperator-facing env var ergonomics: descriptive names + Chroma host/port overrides
stateClosed
labels
enhancementaiarchitecturebuild
assigneesneo-opus-4-7
createdAtMay 6, 2026, 10:49 AM
updatedAtMay 7, 2026, 7:03 PM
githubUrlhttps://github.com/neomjs/neo/issues/10808
authorneo-opus-4-7
commentsCount0
parentIssue9999
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 6, 2026, 1:06 PM

Operator-facing env var ergonomics: descriptive names + Chroma host/port overrides

Closedenhancementaiarchitecturebuild
neo-opus-4-7
neo-opus-4-7 commented on May 6, 2026, 10:49 AM

Context

Surfaced during cross-family review of PR #10806 (#10800 — cloud deployment cookbook). The cookbook's Section 6 (Environment Variable Inventory) proposed operator-facing env-var names (MCP_HTTP_PORT, NEO_CHROMA_HOST, NEO_CHROMA_PORT) that are more descriptive for external operators than the current substrate names. @tobiu calibrated 2026-05-06: "our env var names are not set in stone, except for the github and gemini ones."

Per the calibration, the right path is substrate-side rename + new-env-var wiring to match the cookbook's forward-looking proposal. Cookbook footnotes this ticket in Section 6 so it reads as desired-state with a substrate-gap pointer.

The Problem

Two operator-facing env-var deficiencies for the shared cloud deployment topology:

(1) SSE_PORT is non-descriptive

Current substrate (ai/mcp/server/memory-core/config.template.mjs:74, ai/mcp/server/knowledge-base/config.template.mjs:41):

ssePort: Number(process.env.SSE_PORT) || 3001,  // MC default
ssePort: Number(process.env.SSE_PORT) || 3000,  // KB default

SSE_PORT describes the transport mechanism (Server-Sent Events) rather than the operator-relevant role (the MCP server's HTTP listening port). For an external operator provisioning a container, MCP_HTTP_PORT (or similar) is more discoverable and intent-clear.

(2) Chroma host/port are hardcoded, not env-overridable

Current substrate (ai/mcp/server/knowledge-base/config.template.mjs:106-107 + equivalent paths in MC config):

host: 'localhost',
port: 8000,

These are hardcoded literals, NOT process.env-driven. An operator deploying KB+MC against a shared cloud-hosted Chroma at, e.g., team-chroma.example.com:8000 has no env-var path to configure this — they'd have to fork the config templates, which is a forking-friction the cookbook flow shouldn't require.

The cookbook's Section 5 prescribes NEO_CHROMA_UNIFIED=true (works — that env var IS wired) AND the host/port fields (which AREN'T wired). The asymmetry is the substrate gap.

The Architectural Reality

  • Config templates touched:

    • ai/mcp/server/memory-core/config.template.mjs:74 (ssePort)
    • ai/mcp/server/knowledge-base/config.template.mjs:41 (ssePort)
    • ai/mcp/server/knowledge-base/config.template.mjs:106-107 (host, port)
    • Memory Core's chroma host/port equivalents (verify path during implementation)
  • Config consumers (downstream of the rename):

    • ai/mcp/server/memory-core/Server.mjs (reads aiConfig.ssePort at SSE transport boot)
    • ai/mcp/server/knowledge-base/Server.mjs (same)
    • ai/mcp/server/shared/services/TransportService.mjs (likely reads from injected config)
    • Any other consumers grep -rn 'ssePort\|aiConfig.ssePort' reveals
  • Documentation surface:

    • learn/agentos/SharedDeployment.md currently documents SSE_PORT env var (verify and update during implementation)
    • PR #10806 cookbook Section 6 references the new names
    • MemoryCoreMcpAuth.md example configs may reference SSE_PORT
  • Test surface:

    • test/playwright/unit/ai/mcp/server/memory-core/Server.spec.mjs and similar may exercise these env vars; verify no regressions

The Fix

Two-part substrate work:

Part 1 — Rename SSE_PORT env var

Add a new descriptive env-var-driven config field (mcpHttpPort or similar, name decided during implementation). Decisions to make:

  • Hard rename (drop SSE_PORT support) vs soft rename with backwards-compat fallback (process.env.MCP_HTTP_PORT || process.env.SSE_PORT || <default>). Soft fallback is cleaner for operators with existing .env files; hard rename is cleaner long-term.
  • Field name in config object: ssePort is currently aliased to the runtime concept. Rename to mcpHttpPort everywhere or keep field name and just rename env var? Empirical preference: rename both for consistency.

Recommendation: soft rename with deprecation footnote in SharedDeployment.md noting SSE_PORT is the legacy env var. This honors backwards-compat for any existing operator deployments while leading the documentation forward.

Part 2 — Wire Chroma host/port as env-overridable

In knowledge-base/config.template.mjs (and equivalent in MC):

// Current (hardcoded):
host: 'localhost',
port: 8000,

// Proposed:
host: process.env.NEO_CHROMA_HOST || 'localhost',
port: Number(process.env.NEO_CHROMA_PORT) || 8000,

Symmetrically apply to MC if its Chroma host/port lives in a parallel field.

Part 3 — Documentation sync

Update all references to the old env-var names:

Acceptance Criteria

  • AC1: MCP_HTTP_PORT env var added (or whatever final name lands) to both KB and MC config templates; soft fallback to SSE_PORT if backwards-compat path chosen.
  • AC2: NEO_CHROMA_HOST + NEO_CHROMA_PORT env vars wired in both KB and MC config templates (currently hardcoded localhost/8000).
  • AC3: All documentation references updated: SharedDeployment.md, MemoryCoreMcpAuth.md, learn/agentos/DeploymentCookbook.md (lands in PR #10806) — all consistent on the new names.
  • AC4: Healthcheck database.topology.coordinates.{host, port} reflects the env-var-driven values when set (per #10127 topology contract).
  • AC5: No regression in existing unit tests; if any tests reference SSE_PORT, update them or add fallback compatibility.

Contract Ledger (T3)

Per canonical specification in learn/agentos/contract-ledger.md. Authored 2026-05-06 — added retroactively by ticket author (@neo-opus-4-7) at intake-time per the systemic batch-velocity gap surfaced during the cookbook follow-ups (#10801-#10805). Closing the gap on my own ticket while picking up Lane A in the next-sprint coordination.

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
aiConfig.mcpHttpPort (new field, replacing ssePort in spirit) + NEO_CHROMA_HOST / NEO_CHROMA_PORT env-overridability — both KB (ai/mcp/server/knowledge-base/config.template.mjs) + MC (ai/mcp/server/memory-core/config.template.mjs). #10808, parent #9999, surfacing PR #10806 cookbook Section 6 footnote (forward-looking env-var names referenced ahead of substrate wiring), @tobiu calibration 2026-05-06 ("our env var names are not set in stone, except for the github and gemini ones"). Soft rename: KB/MC servers read process.env.MCP_HTTP_PORT || process.env.SSE_PORT || <default-port> for the listening port (KB defaults 3000, MC defaults 3001). Field rename ssePortmcpHttpPort in config object across both config.template.mjs files; consumers (Server.mjs, TransportService.mjs) updated to read aiConfig.mcpHttpPort. Chroma host/port wiring: host: process.env.NEO_CHROMA_HOST || 'localhost', port: Number(process.env.NEO_CHROMA_PORT) || 8000 (KB config; symmetric in MC if a parallel field exists). Backwards-compat for operators with existing .env files using SSE_PORT: legacy env var still recognized. Deprecation warning emitted when both MCP_HTTP_PORT and SSE_PORT set with different values (resolver decides based on documented precedence — prefer MCP_HTTP_PORT). If neither set, default port unchanged. Chroma host/port: when env var unset, fallback to current hardcoded localhost:8000; new value takes effect on next server boot. Update learn/agentos/SharedDeployment.md (env var inventory + env-overridable Chroma section), learn/agentos/tooling/MemoryCoreMcpAuth.md (operator config examples that reference SSE_PORT), learn/agentos/DeploymentCookbook.md Section 6 (replace existing #10808 footnote with ratification: "these env vars are now wired"). Cookbook Section 5 (Chroma topology) — verify NEO_CHROMA_HOST/PORT examples land cleanly. L2 unit-test: extend test/playwright/unit/ai/mcp/server/memory-core/config.spec.mjs (or sibling) — fallback test (only SSE_PORT set → consumed); precedence test (both set with different values → MCP_HTTP_PORT wins + warning emitted); default test (neither set → default port). For Chroma host/port: similar 3-case matrix. Plus node --check on both updated config.template.mjs files. Manual verification: npm run server-start with new env vars + curl /healthcheck to confirm port + Chroma connectivity.

Out of Scope

  • NEO_AUTH_* env-var renames — they're already operator-facing and descriptive.
  • NEO_CHROMA_EMBEDDING_PROVIDER / NEO_EMBEDDING_PROVIDER consolidation — covered by #10804. This ticket is purely transport + Chroma host/port.
  • GITHUB_* and GEMINI_API_KEY — explicitly named by @tobiu as set-in-stone (per the calibration that birthed this ticket).
  • Docker artifacts that consume these env vars — covered by #10801.
  • MCP_HTTPS_PORT / TLS-on-server-side — separate concern; the deployment topology assumes TLS termination at reverse proxy.

Avoided Traps

  • Rejected: hard-rename without backwards-compat. Some operators may have .env files using SSE_PORT; soft fallback is operator-friendlier even if the long-term goal is single-name.
  • Rejected: bundle Chroma host/port with Memory Core SQLite path env vars. SQLite path is also currently hardcoded (path.resolve(neoRootDir, '.neo-ai-data/...')) but operators in shared mode don't need to override it (each container has its own filesystem). Different concern; defer.
  • Rejected: do this work as part of PR #10806 cookbook polish. Substrate code change vs documentation are different review surfaces; bundling would scope-creep the cookbook PR. Sibling ticket is cleaner.

Related

  • Parent epic: #9999 — Cloud-Native Knowledge & Multi-Tenant Memory Core.
  • Surfacing PR: PR #10806 — cookbook authorship that proposed the new env-var names.
  • Sibling substrate tickets: #10801 (Docker artifacts — will consume these env vars), #10802 (public canonical URL — may benefit from MCP_HTTP_PORT for URL composition), #10803 (reverse proxy reference — references these ports), #10804 (provider consolidation — separate concern), #10805 (integration test harness — will use these env vars in fixture).
  • Operator calibration that birthed this ticket: @tobiu 2026-05-06 in this session — "our env var names are not set in stone, except for the github and gemini ones."

Origin Session ID: 34c8f800-1855-43ff-aea6-d5e6b9410978

Retrieval Hint: query_raw_memories(query="env var rename SSE_PORT MCP_HTTP_PORT NEO_CHROMA_HOST NEO_CHROMA_PORT operator descriptive cloud deployment cookbook substrate")

tobiu referenced in commit 5e320f6 - "docs(agentos): polish cookbook Section 7 healthcheck JSON sample (#10800) (#10811) on May 6, 2026, 11:48 AM
tobiu referenced in commit 9e349cb - "feat(ai): operator-facing env var ergonomics for MCP HTTP port + Chroma host/port (#10808) (#10812) on May 6, 2026, 1:06 PM
tobiu closed this issue on May 6, 2026, 1:06 PM
tobiu referenced in commit 7af53f8 - "feat(skills): codify clean-slate sunset rule for env-var renames (#10826) (#10828) on May 6, 2026, 7:19 PM
tobiu referenced in commit 95f451d - "test(mcp/Authorization): align fixture env-vars with #10877 NEO_ rename (#10878) (#10879) on May 7, 2026, 11:14 AM