SSE Transport
From spec-memo Wiki, the living architecture & domain knowledge base
Feature Overview [edit]
memo serve --sse starts a network-accessible MCP server using the @modelcontextprotocol/sdk/server/sse.js transport, letting remote agents, container runners, and IDE plugins reach the same 11 MCP tools over HTTP. The SSE listener defaults to http://127.0.0.1:3123 unless config.json ports.sse overrides it (legacy ports.mcp is also honored). Regular memo serve (stdio) remains the default host-spawn transport and does not open a network port.
Endpoints:
GET /sse(andGET /) opens a persistent Server-Sent Events stream and registers an MCP session.POST /message?sessionId=<id>delivers inbound JSON-RPC for an open session.GET /healthreturns machine JSON (status, service, bound port/host, project count, active transports).- Authenticated HTTP changeset routes (
/api/sync/pull,/api/sync/push,/api/sync) share the same origin for hybrid/remote sync.
Unless --no-status is passed, the SSE daemon also co-starts the human Status Monitor companion on the status port (default 3124).
Business Rules & Logic [edit]
- Default bind is loopback
127.0.0.1. Binding a non-loopback--hostwithout an auth token throws beforelisten, with the message naming--auth-token/SPEC_MEMO_SSE_TOKEN; the same refusal applies to the co-hosted status server. - Auth token precedence:
--auth-token, thenSPEC_MEMO_AUTH_TOKEN, thenSPEC_MEMO_SSE_TOKEN. A request is authorized byAuthorization: Bearer <token>(bare header match also accepted) or?token=/?authToken=; unauthorized requests receive401 { error: "Unauthorized" }. - Every request captures exactly one
type: "http"activity event (method, path, status, duration) into the shared bus; failed responses with status >= 400 recordok: false. - Tool parity: the SSE server exposes the exact same tools as stdio with the same budget caps, redaction, and project binding.
- Graceful shutdown on
SIGINT/SIGTERMruns the fail-open shutdown flush (flushOnShutdown) first, then closes the activity bus, the status companion, the MCP transports/listener, and drains telemetry. If the status companion fails to bind, the SSE listener, transports, and bus are rolled back before rejecting. - Per-connection
cleanupremoves the transport and disconnects the client exactly once, and closes the per-session MCP server; SSE disconnect does not leak sessions or drop other clients. /messagerequires a valid opensessionId; missing or unknown ids return400 { error: "Valid sessionId required" }.
Technical Architecture [edit]
src/server.tsstartSseServer(options)acceptsport,host,vaultRoot,authToken,statusPort,statusHost,statusAuthToken,enableStatus,activityBus,errorLogPathand resolves the port fromresolveConfiguredPorts. It returns{ server, port, host, url, statusUrl?, statusPort?, activityBus, close }.- Port resolution (
src/vault.tsresolveConfiguredPorts) readsports.sse(fallbackports.mcp) withDEFAULT_VAULT_CONFIG.ports.sse = 3123. /healthbody:{ status: "ok", service: "spec-memo-mcp-sse", port, host, projectsCount, activeTransports }.- The status companion starts in the same process after the SSE listener binds, sharing one
ActivityBus(capacity 200);getMcp()reports{ host, port, activeTransports, available }to the status API. - When
sync.autoSyncIntervalMinutes > 0and mode ishybrid, the daemon starts a non-blocking background sync worker (interval timer,unref'd). Each tick tries the vault lock (tryAcquireVaultLockSync) and skips if busy, then runssyncDualper project withconflictStrategyfrom config (defaultsmart-merge). Shutdown clears and awaits the timer. - CLI mapping (
src/cli.ts):memo serve --sseaccepts--port,--host,--status-port,--no-status,--auth-token,--json,--vaultRoot. Non-JSON stdout prints the SSE URL,/sse,/message,/health, and the status URL when enabled;--jsonemits{ status, service, url, port, host, statusUrl?, statusPort? }. - The
closehandler awaits the in-flight background sync, runsflushOnShutdown, closes the bus, closes the status instance, closes and clears transports, callscloseAllConnections(), closes the listener, thenflushTelemetrySync/closeTelemetry. - Provenance:
0043-mcp-sse-transport.spec.md(original:3000default),0023-mcp-status-monitor.spec.md(companion + bus),0025-deployment-modes.spec.md(sync routes),0035-sync-conflict-reconciliation.spec.md(background worker). Current shipped default is3123, not the spec's3000. See Status Monitor and Vault Sync.