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,
ssePort: Number(process.env.SSE_PORT) || 3000,
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
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):
host: 'localhost',
port: 8000,
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:
SharedDeployment.md (verify current refs)
MemoryCoreMcpAuth.md (verify current refs)
- Any
npx neo-app template or harness config snippet
- The cookbook in PR #10806 — once this ticket is filed, that PR can footnote this # in its Section 6
Acceptance Criteria
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 ssePort → mcpHttpPort 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")
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_PORTis non-descriptiveCurrent 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 defaultSSE_PORTdescribes 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:8000has 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)Config consumers (downstream of the rename):
ai/mcp/server/memory-core/Server.mjs(readsaiConfig.ssePortat SSE transport boot)ai/mcp/server/knowledge-base/Server.mjs(same)ai/mcp/server/shared/services/TransportService.mjs(likely reads from injected config)grep -rn 'ssePort\|aiConfig.ssePort'revealsDocumentation surface:
learn/agentos/SharedDeployment.mdcurrently documentsSSE_PORTenv var (verify and update during implementation)MemoryCoreMcpAuth.mdexample configs may referenceSSE_PORTTest surface:
test/playwright/unit/ai/mcp/server/memory-core/Server.spec.mjsand similar may exercise these env vars; verify no regressionsThe Fix
Two-part substrate work:
Part 1 — Rename
SSE_PORTenv varAdd a new descriptive env-var-driven config field (
mcpHttpPortor similar, name decided during implementation). Decisions to make:SSE_PORTsupport) 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.envfiles; hard rename is cleaner long-term.ssePortis currently aliased to the runtime concept. Rename tomcpHttpPorteverywhere or keep field name and just rename env var? Empirical preference: rename both for consistency.Recommendation: soft rename with deprecation footnote in
SharedDeployment.mdnotingSSE_PORTis 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:
SharedDeployment.md(verify current refs)MemoryCoreMcpAuth.md(verify current refs)npx neo-apptemplate or harness config snippetAcceptance Criteria
MCP_HTTP_PORTenv var added (or whatever final name lands) to both KB and MC config templates; soft fallback toSSE_PORTif backwards-compat path chosen.NEO_CHROMA_HOST+NEO_CHROMA_PORTenv vars wired in both KB and MC config templates (currently hardcodedlocalhost/8000).SharedDeployment.md,MemoryCoreMcpAuth.md,learn/agentos/DeploymentCookbook.md(lands in PR #10806) — all consistent on the new names.database.topology.coordinates.{host, port}reflects the env-var-driven values when set (per #10127 topology contract).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.aiConfig.mcpHttpPort(new field, replacingssePortin spirit) +NEO_CHROMA_HOST/NEO_CHROMA_PORTenv-overridability — both KB (ai/mcp/server/knowledge-base/config.template.mjs) + MC (ai/mcp/server/memory-core/config.template.mjs).process.env.MCP_HTTP_PORT || process.env.SSE_PORT || <default-port>for the listening port (KB defaults3000, MC defaults3001). Field renamessePort→mcpHttpPortin config object across bothconfig.template.mjsfiles; consumers (Server.mjs,TransportService.mjs) updated to readaiConfig.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)..envfiles usingSSE_PORT: legacy env var still recognized. Deprecation warning emitted when bothMCP_HTTP_PORTandSSE_PORTset with different values (resolver decides based on documented precedence — preferMCP_HTTP_PORT). If neither set, default port unchanged. Chroma host/port: when env var unset, fallback to current hardcodedlocalhost:8000; new value takes effect on next server boot.learn/agentos/SharedDeployment.md(env var inventory + env-overridable Chroma section),learn/agentos/tooling/MemoryCoreMcpAuth.md(operator config examples that referenceSSE_PORT),learn/agentos/DeploymentCookbook.mdSection 6 (replace existing #10808 footnote with ratification: "these env vars are now wired"). Cookbook Section 5 (Chroma topology) — verifyNEO_CHROMA_HOST/PORTexamples land cleanly.test/playwright/unit/ai/mcp/server/memory-core/config.spec.mjs(or sibling) — fallback test (onlySSE_PORTset → consumed); precedence test (both set with different values →MCP_HTTP_PORTwins + warning emitted); default test (neither set → default port). For Chroma host/port: similar 3-case matrix. Plusnode --checkon both updatedconfig.template.mjsfiles. Manual verification:npm run server-startwith new env vars + curl/healthcheckto 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_PROVIDERconsolidation — covered by #10804. This ticket is purely transport + Chroma host/port.GITHUB_*andGEMINI_API_KEY— explicitly named by @tobiu as set-in-stone (per the calibration that birthed this ticket).MCP_HTTPS_PORT/ TLS-on-server-side — separate concern; the deployment topology assumes TLS termination at reverse proxy.Avoided Traps
.envfiles usingSSE_PORT; soft fallback is operator-friendlier even if the long-term goal is single-name.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.Related
MCP_HTTP_PORTfor 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).Origin Session ID:
34c8f800-1855-43ff-aea6-d5e6b9410978Retrieval 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")