memorix 1.8.2 → 1.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -158117,11 +158117,14 @@ var init_request_context = __esm({
158117
158117
  }
158118
158118
  });
158119
158119
 
158120
- // src/server/mcp-compat.ts
158121
- import { RequestSchema } from "@modelcontextprotocol/sdk/types.js";
158122
- import { z as z625 } from "zod/v4";
158123
- function buildMcpDiscoverResult(server, serverInfo) {
158124
- const getCapabilities = server.server.getCapabilities.bind(server.server);
158120
+ // src/server/mcp-discovery.ts
158121
+ function getMcpServerInfo() {
158122
+ return {
158123
+ name: "memorix",
158124
+ version: true ? "1.8.3" : "1.0.1"
158125
+ };
158126
+ }
158127
+ function createMcpDiscoverResult(capabilities, serverInfo) {
158125
158128
  return {
158126
158129
  resultType: "complete",
158127
158130
  supportedVersions: [
@@ -158129,31 +158132,51 @@ function buildMcpDiscoverResult(server, serverInfo) {
158129
158132
  MCP_LEGACY_PROTOCOL_VERSION,
158130
158133
  MCP_OLDEST_LEGACY_PROTOCOL_VERSION
158131
158134
  ],
158132
- capabilities: getCapabilities(),
158135
+ capabilities,
158133
158136
  _meta: {
158134
158137
  [MCP_SERVER_INFO_META_KEY]: { ...serverInfo }
158135
158138
  },
158136
- // v1 has no response-cache negotiation. A zero private TTL is the
158137
- // conservative result and prevents clients from inventing a shared cache.
158139
+ // v1 has no response-cache negotiation. A zero private TTL prevents clients
158140
+ // from inventing a shared cache for an implementation that cannot invalidate it.
158138
158141
  ttlMs: 0,
158139
158142
  cacheScope: "private"
158140
158143
  };
158141
158144
  }
158145
+ function createMcpStartupDiscoverResult(serverInfo) {
158146
+ return createMcpDiscoverResult({ tools: { listChanged: true } }, serverInfo);
158147
+ }
158148
+ var MCP_MODERN_PROTOCOL_VERSION, MCP_LEGACY_PROTOCOL_VERSION, MCP_OLDEST_LEGACY_PROTOCOL_VERSION, MCP_SERVER_DISCOVER_METHOD, MCP_SERVER_INFO_META_KEY;
158149
+ var init_mcp_discovery = __esm({
158150
+ "src/server/mcp-discovery.ts"() {
158151
+ "use strict";
158152
+ init_esm_shims();
158153
+ MCP_MODERN_PROTOCOL_VERSION = "2026-07-28";
158154
+ MCP_LEGACY_PROTOCOL_VERSION = "2025-11-25";
158155
+ MCP_OLDEST_LEGACY_PROTOCOL_VERSION = "2024-11-05";
158156
+ MCP_SERVER_DISCOVER_METHOD = "server/discover";
158157
+ MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
158158
+ }
158159
+ });
158160
+
158161
+ // src/server/mcp-compat.ts
158162
+ import { RequestSchema } from "@modelcontextprotocol/sdk/types.js";
158163
+ import { z as z625 } from "zod/v4";
158164
+ function buildMcpDiscoverResult(server, serverInfo) {
158165
+ const getCapabilities = server.server.getCapabilities.bind(server.server);
158166
+ return createMcpDiscoverResult(getCapabilities(), serverInfo);
158167
+ }
158142
158168
  function registerMcpDiscovery(server, serverInfo) {
158143
158169
  if (registeredServers.has(server)) return;
158144
158170
  server.server.setRequestHandler(ServerDiscoverRequestSchema, async () => buildMcpDiscoverResult(server, serverInfo));
158145
158171
  registeredServers.add(server);
158146
158172
  }
158147
- var MCP_MODERN_PROTOCOL_VERSION, MCP_LEGACY_PROTOCOL_VERSION, MCP_OLDEST_LEGACY_PROTOCOL_VERSION, MCP_SERVER_DISCOVER_METHOD, MCP_SERVER_INFO_META_KEY, ServerDiscoverRequestSchema, registeredServers;
158173
+ var ServerDiscoverRequestSchema, registeredServers;
158148
158174
  var init_mcp_compat = __esm({
158149
158175
  "src/server/mcp-compat.ts"() {
158150
158176
  "use strict";
158151
158177
  init_esm_shims();
158152
- MCP_MODERN_PROTOCOL_VERSION = "2026-07-28";
158153
- MCP_LEGACY_PROTOCOL_VERSION = "2025-11-25";
158154
- MCP_OLDEST_LEGACY_PROTOCOL_VERSION = "2024-11-05";
158155
- MCP_SERVER_DISCOVER_METHOD = "server/discover";
158156
- MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
158178
+ init_mcp_discovery();
158179
+ init_mcp_discovery();
158157
158180
  ServerDiscoverRequestSchema = RequestSchema.extend({
158158
158181
  method: z625.literal(MCP_SERVER_DISCOVER_METHOD),
158159
158182
  params: z625.looseObject({}).optional()
@@ -168447,10 +168470,7 @@ The path should point to a directory containing a .git folder.`
168447
168470
  isError: true
168448
168471
  };
168449
168472
  };
168450
- const serverInfo = {
168451
- name: "memorix",
168452
- version: true ? "1.8.2" : "1.0.1"
168453
- };
168473
+ const serverInfo = getMcpServerInfo();
168454
168474
  const server = existingServer ?? new McpServer(serverInfo);
168455
168475
  registerMcpDiscovery(server, serverInfo);
168456
168476
  const originalRegisterTool = server.registerTool.bind(server);
@@ -172857,6 +172877,218 @@ var init_server2 = __esm({
172857
172877
  }
172858
172878
  });
172859
172879
 
172880
+ // src/server/stdio-startup-gate.ts
172881
+ import { PassThrough as PassThrough3 } from "stream";
172882
+ var STDIO_STARTUP_GATE_MAX_BUFFER_SIZE, StdioStartupGate;
172883
+ var init_stdio_startup_gate = __esm({
172884
+ "src/server/stdio-startup-gate.ts"() {
172885
+ "use strict";
172886
+ init_esm_shims();
172887
+ init_mcp_discovery();
172888
+ STDIO_STARTUP_GATE_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
172889
+ StdioStartupGate = class {
172890
+ input = new PassThrough3();
172891
+ stdin;
172892
+ stdout;
172893
+ serverInfo;
172894
+ maxBufferSize;
172895
+ onError;
172896
+ onEnd;
172897
+ queuedMessages = [];
172898
+ pendingInput = "";
172899
+ queuedBytes = 0;
172900
+ started = false;
172901
+ ready = false;
172902
+ stopped = false;
172903
+ stdinEnded = false;
172904
+ endNotified = false;
172905
+ onData = (chunk) => {
172906
+ if (this.stopped) return;
172907
+ if (this.ready) {
172908
+ if (Buffer.byteLength(chunk, "utf8") > this.maxBufferSize) {
172909
+ this.fail(new Error(`stdio input chunk exceeded ${this.maxBufferSize} bytes`));
172910
+ return;
172911
+ }
172912
+ this.input.write(chunk);
172913
+ return;
172914
+ }
172915
+ const text2 = typeof chunk === "string" ? chunk : chunk.toString("utf8");
172916
+ if (this.queuedBytes + Buffer.byteLength(this.pendingInput, "utf8") + Buffer.byteLength(text2, "utf8") > this.maxBufferSize) {
172917
+ this.fail(new Error(`stdio startup input exceeded ${this.maxBufferSize} bytes before a complete JSON-RPC line`));
172918
+ return;
172919
+ }
172920
+ this.pendingInput += text2;
172921
+ let newline = this.pendingInput.indexOf("\n");
172922
+ while (newline >= 0 && !this.stopped) {
172923
+ const line = this.pendingInput.slice(0, newline + 1);
172924
+ this.pendingInput = this.pendingInput.slice(newline + 1);
172925
+ this.handleLine(line);
172926
+ newline = this.pendingInput.indexOf("\n");
172927
+ }
172928
+ if (!this.stopped && Buffer.byteLength(this.pendingInput, "utf8") > this.maxBufferSize) {
172929
+ this.fail(new Error(`stdio startup input exceeded ${this.maxBufferSize} bytes`));
172930
+ }
172931
+ };
172932
+ onStdinError = (error) => {
172933
+ this.fail(error);
172934
+ };
172935
+ onStdinEnd = () => {
172936
+ this.stdinEnded = true;
172937
+ if (this.ready) this.finishInput();
172938
+ };
172939
+ constructor(options) {
172940
+ this.stdin = options.stdin;
172941
+ this.stdout = options.stdout;
172942
+ this.serverInfo = { ...options.serverInfo };
172943
+ this.maxBufferSize = options.maxBufferSize ?? STDIO_STARTUP_GATE_MAX_BUFFER_SIZE;
172944
+ this.onError = options.onError;
172945
+ this.onEnd = options.onEnd;
172946
+ }
172947
+ start() {
172948
+ if (this.started || this.stopped) return;
172949
+ this.started = true;
172950
+ this.stdin.on("data", this.onData);
172951
+ this.stdin.on("error", this.onStdinError);
172952
+ this.stdin.on("end", this.onStdinEnd);
172953
+ }
172954
+ /** Release queued messages only after StdioServerTransport has installed its listener. */
172955
+ markReady() {
172956
+ if (this.stopped || this.ready) return;
172957
+ this.ready = true;
172958
+ for (const message of this.queuedMessages) this.input.write(message);
172959
+ this.queuedMessages.length = 0;
172960
+ this.queuedBytes = 0;
172961
+ if (this.pendingInput) {
172962
+ this.input.write(this.pendingInput);
172963
+ this.pendingInput = "";
172964
+ }
172965
+ if (this.stdinEnded) this.finishInput();
172966
+ }
172967
+ stop() {
172968
+ if (this.stopped) return;
172969
+ this.stopped = true;
172970
+ this.stdin.off("data", this.onData);
172971
+ this.stdin.off("error", this.onStdinError);
172972
+ this.stdin.off("end", this.onStdinEnd);
172973
+ this.queuedMessages.length = 0;
172974
+ this.pendingInput = "";
172975
+ this.queuedBytes = 0;
172976
+ if (!this.input.destroyed) this.input.end();
172977
+ }
172978
+ handleLine(line) {
172979
+ const parsed = this.parseLine(line);
172980
+ if (!parsed) return;
172981
+ if ("error" in parsed) {
172982
+ this.writeJsonRpcError(null, parsed.error.code, parsed.error.message);
172983
+ return;
172984
+ }
172985
+ if (!this.ready && this.isDiscoveryRequest(parsed.message)) {
172986
+ const response = {
172987
+ jsonrpc: "2.0",
172988
+ id: parsed.message.id,
172989
+ result: createMcpStartupDiscoverResult(this.serverInfo)
172990
+ };
172991
+ try {
172992
+ this.stdout.write(`${JSON.stringify(response)}
172993
+ `);
172994
+ } catch (error) {
172995
+ this.fail(error instanceof Error ? error : new Error(String(error)));
172996
+ }
172997
+ return;
172998
+ }
172999
+ if (this.ready) {
173000
+ this.input.write(line);
173001
+ return;
173002
+ }
173003
+ const bytes = Buffer.byteLength(line, "utf8");
173004
+ if (this.queuedBytes + bytes > this.maxBufferSize) {
173005
+ this.fail(new Error(`stdio startup queue exceeded ${this.maxBufferSize} bytes`));
173006
+ return;
173007
+ }
173008
+ this.queuedMessages.push(line);
173009
+ this.queuedBytes += bytes;
173010
+ }
173011
+ parseLine(line) {
173012
+ const trimmed = line.endsWith("\n") ? line.slice(0, -1).replace(/\r$/, "") : line;
173013
+ if (!trimmed.trim()) return null;
173014
+ let value;
173015
+ try {
173016
+ value = JSON.parse(trimmed);
173017
+ } catch {
173018
+ return { error: { code: -32700, message: "Parse error" } };
173019
+ }
173020
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
173021
+ return { error: { code: -32600, message: "Invalid Request" } };
173022
+ }
173023
+ const message = value;
173024
+ if (message.jsonrpc !== "2.0") {
173025
+ return { error: { code: -32600, message: "Invalid Request" } };
173026
+ }
173027
+ const hasId = Object.prototype.hasOwnProperty.call(message, "id");
173028
+ const hasMethod = typeof message.method === "string";
173029
+ const hasResult = Object.prototype.hasOwnProperty.call(message, "result");
173030
+ const hasError = Object.prototype.hasOwnProperty.call(message, "error");
173031
+ if (hasMethod && (hasResult || hasError)) {
173032
+ return { error: { code: -32600, message: "Invalid Request" } };
173033
+ }
173034
+ if (!hasMethod && !hasResult && !hasError) {
173035
+ return { error: { code: -32600, message: "Invalid Request" } };
173036
+ }
173037
+ if (hasId && !this.isValidRequestId(message.id)) {
173038
+ return { error: { code: -32600, message: "Invalid Request" } };
173039
+ }
173040
+ if (!hasMethod && !hasId) {
173041
+ return { error: { code: -32600, message: "Invalid Request" } };
173042
+ }
173043
+ return { message };
173044
+ }
173045
+ isDiscoveryRequest(message) {
173046
+ if (message.method !== MCP_SERVER_DISCOVER_METHOD) return false;
173047
+ if (!Object.prototype.hasOwnProperty.call(message, "id")) return false;
173048
+ const params = message.params;
173049
+ return params === void 0 || typeof params === "object" && params !== null && !Array.isArray(params);
173050
+ }
173051
+ isValidRequestId(id) {
173052
+ return id === null || typeof id === "string" || typeof id === "number" && Number.isFinite(id);
173053
+ }
173054
+ writeJsonRpcError(id, code, message) {
173055
+ try {
173056
+ this.stdout.write(`${JSON.stringify({
173057
+ jsonrpc: "2.0",
173058
+ id,
173059
+ error: { code, message }
173060
+ })}
173061
+ `);
173062
+ } catch (error) {
173063
+ this.fail(error instanceof Error ? error : new Error(String(error)));
173064
+ }
173065
+ }
173066
+ finishInput() {
173067
+ if (!this.ready || this.input.destroyed || this.input.writableEnded) return;
173068
+ this.input.end();
173069
+ this.input.once("end", () => this.notifyEnd());
173070
+ }
173071
+ notifyEnd() {
173072
+ if (this.endNotified) return;
173073
+ this.endNotified = true;
173074
+ this.onEnd?.();
173075
+ }
173076
+ fail(error) {
173077
+ if (this.stopped) return;
173078
+ this.stopped = true;
173079
+ this.stdin.off("data", this.onData);
173080
+ this.stdin.off("error", this.onStdinError);
173081
+ this.stdin.off("end", this.onStdinEnd);
173082
+ this.queuedMessages.length = 0;
173083
+ this.pendingInput = "";
173084
+ this.queuedBytes = 0;
173085
+ if (!this.input.destroyed) this.input.destroy();
173086
+ this.onError?.(error);
173087
+ }
173088
+ };
173089
+ }
173090
+ });
173091
+
172860
173092
  // src/cli/mcp-root-path.ts
172861
173093
  import path35 from "path";
172862
173094
  function mcpFileUriToPath(uri, platform = process.platform) {
@@ -173001,7 +173233,7 @@ var init_serve_shared = __esm({
173001
173233
 
173002
173234
  // src/cli/version.ts
173003
173235
  function getCliVersion() {
173004
- return true ? "1.8.2" : pkg.version;
173236
+ return true ? "1.8.3" : pkg.version;
173005
173237
  }
173006
173238
  var init_version3 = __esm({
173007
173239
  "src/cli/version.ts"() {
@@ -173231,6 +173463,8 @@ var init_serve = __esm({
173231
173463
  "use strict";
173232
173464
  init_esm_shims();
173233
173465
  init_tool_profile();
173466
+ init_mcp_discovery();
173467
+ init_stdio_startup_gate();
173234
173468
  init_mcp_root_path();
173235
173469
  serve_default = defineCommand({
173236
173470
  meta: {
@@ -173255,15 +173489,25 @@ var init_serve = __esm({
173255
173489
  }
173256
173490
  },
173257
173491
  run: async ({ args }) => {
173492
+ const startupGate = new StdioStartupGate({
173493
+ stdin: process.stdin,
173494
+ stdout: process.stdout,
173495
+ serverInfo: getMcpServerInfo(),
173496
+ onError: (error) => {
173497
+ console.error(`[memorix] stdio startup gate error: ${error.message}`);
173498
+ process.exit(1);
173499
+ },
173500
+ onEnd: () => {
173501
+ console.error("[memorix] stdin closed \u2014 exiting");
173502
+ process.exitCode = 0;
173503
+ }
173504
+ });
173505
+ startupGate.start();
173258
173506
  const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
173259
173507
  const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (init_server2(), server_exports2));
173260
173508
  const { detectProject: detectProject2, findGitInSubdirs: findGitInSubdirs2, isSystemDirectory: isSystemDirectory2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
173261
173509
  const { homedir: homedir27 } = await import("os");
173262
173510
  const { resolveServeProject: resolveServeProject2 } = await Promise.resolve().then(() => (init_serve_shared(), serve_shared_exports));
173263
- process.stdin.on("end", () => {
173264
- console.error("[memorix] stdin closed \u2014 exiting");
173265
- process.exit(0);
173266
- });
173267
173511
  let safeCwd;
173268
173512
  try {
173269
173513
  safeCwd = process.cwd();
@@ -173298,8 +173542,9 @@ var init_serve = __esm({
173298
173542
  const toolProfile = resolveToolProfile({ explicit: args.mode, envValue: process.env.MEMORIX_MODE, fallback: "micro" });
173299
173543
  const serverOptions = detected ? { toolProfile, deferProjectRuntimeInit: true } : { allowUntrackedFallback: allowUntracked, deferProjectInitUntilBound: !allowUntracked, deferProjectRuntimeInit: true, toolProfile };
173300
173544
  const { server, projectId, deferredInit, switchProject } = await createMemorixServer2(projectRoot, void 0, void 0, serverOptions);
173301
- const transport = new StdioServerTransport();
173545
+ const transport = new StdioServerTransport(startupGate.input, process.stdout);
173302
173546
  await server.connect(transport);
173547
+ startupGate.markReady();
173303
173548
  console.error(`[memorix] MCP Server running on stdio (project: ${projectId})`);
173304
173549
  console.error(`[memorix] Project root: ${detected?.rootPath ?? projectRoot}`);
173305
173550
  const tryRootsSwitch = async () => {
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.8.3] - 2026-08-25
8
+
9
+ ### Fixed
10
+ - **Stdio MCP startup gate** -- `memorix serve` now reads and bounds
11
+ newline-delimited JSON-RPC input before project initialization completes.
12
+ Early `server/discover` requests receive the complete discovery result, while
13
+ initialize, notifications, responses, and versionless tool requests replay
14
+ through the pinned SDK transport in input order without duplicate handling.
15
+
16
+ ### MCP Compatibility
17
+ - **Stable cold-start discovery** -- real stdio CLI startup now supports
18
+ pre-initialize discovery within the startup window and preserves legacy
19
+ initialize plus versionless `tools/list`/`tools/call` behavior. Tasks,
20
+ subscriptions, list-response caching, and modern non-discovery result
21
+ metadata remain unsupported or partial.
22
+
7
23
  ## [1.8.2] - 2026-08-25
8
24
 
9
25
  ### Fixed
package/dist/sdk.js CHANGED
@@ -167806,18 +167806,21 @@ function createProjectBindingController(projectRoot) {
167806
167806
  init_esm_shims();
167807
167807
  import { RequestSchema } from "@modelcontextprotocol/sdk/types.js";
167808
167808
  import { z as z625 } from "zod/v4";
167809
+
167810
+ // src/server/mcp-discovery.ts
167811
+ init_esm_shims();
167809
167812
  var MCP_MODERN_PROTOCOL_VERSION = "2026-07-28";
167810
167813
  var MCP_LEGACY_PROTOCOL_VERSION = "2025-11-25";
167811
167814
  var MCP_OLDEST_LEGACY_PROTOCOL_VERSION = "2024-11-05";
167812
167815
  var MCP_SERVER_DISCOVER_METHOD = "server/discover";
167813
167816
  var MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
167814
- var ServerDiscoverRequestSchema = RequestSchema.extend({
167815
- method: z625.literal(MCP_SERVER_DISCOVER_METHOD),
167816
- params: z625.looseObject({}).optional()
167817
- });
167818
- var registeredServers = /* @__PURE__ */ new WeakSet();
167819
- function buildMcpDiscoverResult(server, serverInfo) {
167820
- const getCapabilities = server.server.getCapabilities.bind(server.server);
167817
+ function getMcpServerInfo() {
167818
+ return {
167819
+ name: "memorix",
167820
+ version: true ? "1.8.3" : "1.0.1"
167821
+ };
167822
+ }
167823
+ function createMcpDiscoverResult(capabilities, serverInfo) {
167821
167824
  return {
167822
167825
  resultType: "complete",
167823
167826
  supportedVersions: [
@@ -167825,16 +167828,27 @@ function buildMcpDiscoverResult(server, serverInfo) {
167825
167828
  MCP_LEGACY_PROTOCOL_VERSION,
167826
167829
  MCP_OLDEST_LEGACY_PROTOCOL_VERSION
167827
167830
  ],
167828
- capabilities: getCapabilities(),
167831
+ capabilities,
167829
167832
  _meta: {
167830
167833
  [MCP_SERVER_INFO_META_KEY]: { ...serverInfo }
167831
167834
  },
167832
- // v1 has no response-cache negotiation. A zero private TTL is the
167833
- // conservative result and prevents clients from inventing a shared cache.
167835
+ // v1 has no response-cache negotiation. A zero private TTL prevents clients
167836
+ // from inventing a shared cache for an implementation that cannot invalidate it.
167834
167837
  ttlMs: 0,
167835
167838
  cacheScope: "private"
167836
167839
  };
167837
167840
  }
167841
+
167842
+ // src/server/mcp-compat.ts
167843
+ var ServerDiscoverRequestSchema = RequestSchema.extend({
167844
+ method: z625.literal(MCP_SERVER_DISCOVER_METHOD),
167845
+ params: z625.looseObject({}).optional()
167846
+ });
167847
+ var registeredServers = /* @__PURE__ */ new WeakSet();
167848
+ function buildMcpDiscoverResult(server, serverInfo) {
167849
+ const getCapabilities = server.server.getCapabilities.bind(server.server);
167850
+ return createMcpDiscoverResult(getCapabilities(), serverInfo);
167851
+ }
167838
167852
  function registerMcpDiscovery(server, serverInfo) {
167839
167853
  if (registeredServers.has(server)) return;
167840
167854
  server.server.setRequestHandler(ServerDiscoverRequestSchema, async () => buildMcpDiscoverResult(server, serverInfo));
@@ -168238,10 +168252,7 @@ The path should point to a directory containing a .git folder.`
168238
168252
  isError: true
168239
168253
  };
168240
168254
  };
168241
- const serverInfo = {
168242
- name: "memorix",
168243
- version: true ? "1.8.2" : "1.0.1"
168244
- };
168255
+ const serverInfo = getMcpServerInfo();
168245
168256
  const server = existingServer ?? new McpServer(serverInfo);
168246
168257
  registerMcpDiscovery(server, serverInfo);
168247
168258
  const originalRegisterTool = server.registerTool.bind(server);
@@ -18,12 +18,15 @@ Status: accepted implementation contract for Memorix 1.8.0.
18
18
  ## Compatibility Contract
19
19
 
20
20
  Memorix preserves the legacy 2025-era initialize contract, including stdio and
21
- stateful Streamable HTTP with `Mcp-Session-Id`. Memorix 1.8.2 also registers a
21
+ stateful Streamable HTTP with `Mcp-Session-Id`. Memorix 1.8.3 also registers a
22
22
  low-level `server/discover` compatibility adapter for the 2026-07-28 request.
23
23
  Its `DiscoverResult` is complete for the required identity, versions,
24
24
  capabilities, and private zero-TTL cache hint. Versionless `tools/list` and
25
25
  `tools/call` are accepted by the pinned v1 SDK and retain its legacy result
26
- envelopes. HTTP stateless project handles remain a compatibility adapter: they
26
+ envelopes. The stdio startup gate reads bounded newline-delimited input before
27
+ project initialization, answers discovery immediately, and replays all other
28
+ messages in order; EOF is deferred until the queued input is released. HTTP
29
+ stateless project handles remain a compatibility adapter: they
27
30
  own project routing, but do not turn the v1 SDK into a complete 2026 runtime.
28
31
  Tasks, subscriptions, and list-response caching are unsupported and are not
29
32
  advertised or simulated.
@@ -147,14 +147,15 @@ preserved. A memory without explicit feedback keeps the legacy relevance and
147
147
  retention score. The first feedback event opts that candidate into the
148
148
  feedback projection.
149
149
 
150
- ### HTTP MCP Compatibility
151
-
152
- Legacy clients use stateful Streamable HTTP with `Mcp-Session-Id`. Current
153
- Legacy clients use the 2025-era `initialize` handshake and stateful
154
- `Mcp-Session-Id`. The stdio server also accepts the 2026-07-28
155
- `server/discover` request before `initialize` and returns the required
156
- `DiscoverResult`. Versionless `tools/list` and `tools/call` use the pinned
157
- SDK's legacy result envelopes. HTTP stateless clients may use a durable
150
+ ### MCP Compatibility
151
+
152
+ Legacy clients use stateful Streamable HTTP with `Mcp-Session-Id` and the
153
+ 2025-era `initialize` handshake. The 1.8.3 stdio server starts a bounded
154
+ newline-delimited JSON-RPC gate before project initialization: it answers the
155
+ 2026-07-28 `server/discover` request before `initialize`, then replays other
156
+ requests, notifications, and responses in order into the pinned SDK transport.
157
+ Versionless `tools/list` and `tools/call` use the SDK's legacy result envelopes.
158
+ HTTP stateless clients may use a durable
158
159
  `Mcp-Project-Handle`; `/protocol-diagnostics` labels this as compatibility-only.
159
160
  Modern result metadata is discovery-only with a private zero-TTL hint. Tasks,
160
161
  subscriptions, and list-response caching are unsupported. When MCP discovery
@@ -13,8 +13,8 @@ Memorix is a TypeScript project built around:
13
13
 
14
14
  ## Current Development Baseline
15
15
 
16
- The current release work targets the **1.8.2 release line** and package metadata
17
- is kept at `1.8.2` for this release commit.
16
+ The current release work targets the **1.8.3 release line** and package metadata
17
+ is kept at `1.8.3` for this release commit.
18
18
 
19
19
  Contributors should assume the following areas are part of the current release line:
20
20
 
@@ -96,6 +96,7 @@ npm run test:watch
96
96
 
97
97
  ```bash
98
98
  memorix serve
99
+ node scripts/mcp-stdio-smoke.mjs
99
100
  memorix background start
100
101
  memorix status
101
102
  ```
package/docs/README.md CHANGED
@@ -94,7 +94,7 @@ The public docs are organized by user intent:
94
94
  | 1.2 honest Lite and optional semantic CodeGraph provider contract | [1.2 Provider Quality](1.2.0-PROVIDER-QUALITY.md) |
95
95
  | 1.3 long-term memory model, source boundary, and lifecycle | [1.3 Memory Architecture](1.3-MEMORY-ARCHITECTURE.md) |
96
96
  | Active context-control work | [1.2.2 Memory Control Plane](1.2.2-MEMORY-CONTROL-PLANE.md) |
97
- | 1.8.2 context-control and compatibility acceptance contract | [1.8.0 Release Specification](1.8.0-RELEASE-CANDIDATE-SPEC.md) |
97
+ | 1.8.3 stdio discovery startup and compatibility acceptance contract | [1.8.0 Release Specification](1.8.0-RELEASE-CANDIDATE-SPEC.md) |
98
98
  | Historical cloud sync and multi-agent research | [CLOUD_SYNC_AND_MULTI_AGENT_RESEARCH.md](CLOUD_SYNC_AND_MULTI_AGENT_RESEARCH.md) |
99
99
  | Known issues and old roadmap notes | [KNOWN_ISSUES_AND_ROADMAP.md](KNOWN_ISSUES_AND_ROADMAP.md) |
100
100
 
@@ -122,7 +122,7 @@ Historical/deep-reference documents may describe older designs. If they conflict
122
122
 
123
123
  ## Current Product Line
124
124
 
125
- The current product line is **1.8.2**. The authoritative acceptance contract is
125
+ The current product line is **1.8.3**. The authoritative acceptance contract is
126
126
  [1.8.0 Release Specification](1.8.0-RELEASE-CANDIDATE-SPEC.md).
127
127
  The current baseline has:
128
128
 
@@ -141,10 +141,13 @@ The current baseline has:
141
141
  - `~/.memorix/config.toml` and project `memorix.toml` are the user-facing configuration model
142
142
  - legacy `memorix.yml`, `.env`, and `config.json` files are still read for compatibility, but new setups should use TOML
143
143
 
144
- For MCP compatibility, 1.8.2 preserves legacy 2025-era initialize and
145
- stateful Streamable HTTP behavior, and adds a tested 2026-07-28
146
- `server/discover` adapter. Versionless `tools/list` and `tools/call` continue
147
- through the SDK's legacy result envelopes. Modern result metadata is limited to
148
- the discovery response (`ttlMs: 0`, private cache scope); Tasks, subscriptions,
149
- and list-response caching are unsupported. Stateless HTTP project handles are
150
- a compatibility adapter, not a claim of complete 2026 conformance.
144
+ For MCP compatibility, 1.8.3 preserves legacy 2025-era initialize and
145
+ stateful Streamable HTTP behavior. `memorix serve` starts a bounded stdio
146
+ startup gate: pre-initialize 2026-07-28 `server/discover` is answered with a
147
+ complete discovery result, and other early JSON-RPC messages replay in order
148
+ through the pinned SDK transport. Versionless `tools/list` and `tools/call`
149
+ continue through the SDK's legacy result envelopes. Modern result metadata is
150
+ limited to the discovery response (`ttlMs: 0`, private cache scope); Tasks,
151
+ subscriptions, and list-response caching are unsupported. Stateless HTTP
152
+ project handles are a compatibility adapter, not a claim of complete 2026
153
+ conformance.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "memorix",
3
3
  "mcpName": "io.github.AVIDS2/memorix",
4
- "version": "1.8.2",
4
+ "version": "1.8.3",
5
5
  "description": "Local-first shared memory layer for AI coding agents across MCP clients, Git history, reasoning context, and project sessions.",
6
6
  "type": "module",
7
7
  "sideEffects": false,
@@ -62,6 +62,7 @@
62
62
  "update-models": "npm --workspace @memorix/ai run update-models",
63
63
  "start": "node dist/index.js",
64
64
  "test": "vitest run --no-file-parallelism --maxWorkers=1 --minWorkers=1",
65
+ "test:mcp-stdio-smoke": "node scripts/mcp-stdio-smoke.mjs",
65
66
  "test:watch": "vitest",
66
67
  "test:llm-live": "MEMORIX_RUN_LIVE_LLM_TESTS=1 vitest run tests/integration/formation-llm-quality.test.ts",
67
68
  "test:e2e": "vitest run tests/e2e/",
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.8.2"
3
+ "version": "1.8.3"
4
4
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
3
  "name": "memorix",
4
- "version": "1.8.2",
4
+ "version": "1.8.3",
5
5
  "description": "Shared workspace memory for Claude Code and other AI coding agents.",
6
6
  "author": {
7
7
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "description": "Local-first project memory for CodeBuddy Code and other coding agents.",
5
5
  "author": {
6
6
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "description": "Shared workspace memory for Codex and other AI coding agents.",
5
5
  "author": {
6
6
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "description": "Shared local workspace memory for GitHub Copilot CLI and other AI coding agents.",
5
5
  "author": {
6
6
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "mcpServers": {
5
5
  "memorix": {
6
6
  "command": "memorix",
@@ -1,5 +1,5 @@
1
1
  name: memorix
2
- version: "1.8.2"
2
+ version: "1.8.3"
3
3
  description: Shared workspace memory bridge for Hermes Agent.
4
4
  author: AVIDS2
5
5
  license: Apache-2.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix-omp-package",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "description": "Memorix shared workspace memory package for Oh-my-Pi.",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [