@cybermem/mcp 0.14.8 → 0.14.10
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/CHANGELOG.md +7 -0
- package/dist/index.js +42 -15
- package/e2e/sse_transport.spec.ts +81 -0
- package/package.json +1 -1
- package/playwright.config.ts +1 -1
- package/src/index.ts +73 -28
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @cybermem/mcp
|
|
2
2
|
|
|
3
|
+
## 0.14.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#120](https://github.com/mikhailkogan17/cybermem/pull/120) [`2319994`](https://github.com/mikhailkogan17/cybermem/commit/2319994f096e4063e2ca4bc4ca02eb8b33f192ce) Thanks [@mikhailkogan17-antigravity](https://github.com/mikhailkogan17-antigravity)! - fix(mcp): remove redundant transport.start() call causing SSE crash loop; switch to SSEServerTransport for multi-client support
|
|
8
|
+
fix(dashboard): update mcp-config API to support SSE and --allow-http
|
|
9
|
+
|
|
3
10
|
## 0.14.8
|
|
4
11
|
|
|
5
12
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -12,11 +12,23 @@ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
|
12
12
|
const async_hooks_1 = require("async_hooks");
|
|
13
13
|
const cors_1 = __importDefault(require("cors"));
|
|
14
14
|
const express_1 = __importDefault(require("express"));
|
|
15
|
+
const fs_1 = require("fs");
|
|
16
|
+
const path_1 = require("path");
|
|
15
17
|
const zod_1 = require("zod");
|
|
16
18
|
// Async Storage for Request Context (User ID and Client Name)
|
|
17
19
|
const requestContext = new async_hooks_1.AsyncLocalStorage();
|
|
18
20
|
// CLI args processing
|
|
19
21
|
const args = process.argv.slice(2);
|
|
22
|
+
// Read version from package.json
|
|
23
|
+
let PACKAGE_VERSION = "0.0.0";
|
|
24
|
+
try {
|
|
25
|
+
const packageJsonPath = (0, path_1.join)(__dirname, "../package.json");
|
|
26
|
+
const packageJson = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, "utf-8"));
|
|
27
|
+
PACKAGE_VERSION = packageJson.version;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error("[MCP] Failed to read package.json version", error);
|
|
31
|
+
}
|
|
20
32
|
// Start the server
|
|
21
33
|
startServer();
|
|
22
34
|
async function startServer() {
|
|
@@ -97,7 +109,8 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
97
109
|
let client;
|
|
98
110
|
const ctx = requestContext.getStore();
|
|
99
111
|
if (opts.sessionId) {
|
|
100
|
-
|
|
112
|
+
// For SSE sessions, prefer the real client name from the request context when available
|
|
113
|
+
client = ctx?.clientName || "sse-client";
|
|
101
114
|
}
|
|
102
115
|
else if (ctx) {
|
|
103
116
|
client = ctx.clientName || stdioClientName || "unknown";
|
|
@@ -114,7 +127,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
114
127
|
db.run("INSERT INTO cybermem_access_log (timestamp, client_name, client_version, method, endpoint, operation, status, is_error) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [
|
|
115
128
|
ts,
|
|
116
129
|
client,
|
|
117
|
-
|
|
130
|
+
PACKAGE_VERSION,
|
|
118
131
|
method,
|
|
119
132
|
endpoint,
|
|
120
133
|
operation,
|
|
@@ -127,13 +140,13 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
127
140
|
catch { }
|
|
128
141
|
};
|
|
129
142
|
// Factory to create configured McpServer instance
|
|
130
|
-
const createConfiguredServer = () => {
|
|
131
|
-
const server = new mcp_js_1.McpServer({ name: "cybermem", version:
|
|
143
|
+
const createConfiguredServer = (onClientConnected) => {
|
|
144
|
+
const server = new mcp_js_1.McpServer({ name: "cybermem", version: PACKAGE_VERSION }, {
|
|
132
145
|
instructions: CYBERMEM_INSTRUCTIONS,
|
|
133
146
|
});
|
|
134
|
-
// access underlying server
|
|
135
|
-
|
|
136
|
-
|
|
147
|
+
// access underlying server to set internal state for direct memory access
|
|
148
|
+
// Casting to unknown first to allow adding private property
|
|
149
|
+
server._memoryReady = true;
|
|
137
150
|
server.registerResource("CyberMem Agent Protocol", "cybermem://protocol", { description: "Instructions for AI agents", mimeType: "text/plain" }, async () => ({
|
|
138
151
|
contents: [
|
|
139
152
|
{
|
|
@@ -148,8 +161,15 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
148
161
|
// For SSE multiple clients, stdioClientName global is less useful,
|
|
149
162
|
// but we can set it for context if running in single-user mode.
|
|
150
163
|
// For multi-user, rely on requestContext.
|
|
151
|
-
|
|
152
|
-
|
|
164
|
+
// For SSE multiple clients, rely on per-request context instead of a global.
|
|
165
|
+
const clientName = request.params.clientInfo.name;
|
|
166
|
+
if (onClientConnected) {
|
|
167
|
+
onClientConnected(clientName);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
stdioClientName = clientName;
|
|
171
|
+
}
|
|
172
|
+
console.error(`[MCP] Client identified via handshake: ${clientName}`);
|
|
153
173
|
return {
|
|
154
174
|
protocolVersion: "2024-11-05",
|
|
155
175
|
capabilities: {
|
|
@@ -158,7 +178,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
158
178
|
},
|
|
159
179
|
serverInfo: {
|
|
160
180
|
name: "cybermem",
|
|
161
|
-
version:
|
|
181
|
+
version: PACKAGE_VERSION,
|
|
162
182
|
},
|
|
163
183
|
};
|
|
164
184
|
});
|
|
@@ -181,7 +201,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
181
201
|
});
|
|
182
202
|
server.registerTool("query_memory", {
|
|
183
203
|
description: "Search memories.",
|
|
184
|
-
inputSchema: zod_1.z.object({ query: zod_1.z.string(), k: zod_1.z.number().default(
|
|
204
|
+
inputSchema: zod_1.z.object({ query: zod_1.z.string(), k: zod_1.z.number().default(5) }),
|
|
185
205
|
}, async (args) => {
|
|
186
206
|
const res = await memory.search(args.query, { limit: args.k });
|
|
187
207
|
await logActivity("read", {
|
|
@@ -264,7 +284,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
264
284
|
const app = (0, express_1.default)();
|
|
265
285
|
app.use((0, cors_1.default)());
|
|
266
286
|
app.use(express_1.default.json());
|
|
267
|
-
app.get("/health", (req, res) => res.json({ ok: true, version:
|
|
287
|
+
app.get("/health", (req, res) => res.json({ ok: true, version: PACKAGE_VERSION }));
|
|
268
288
|
app.use((req, res, next) => {
|
|
269
289
|
const clientName = req.headers["x-client-name"] || "antigravity-client";
|
|
270
290
|
requestContext.run({ clientName }, next);
|
|
@@ -371,7 +391,11 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
371
391
|
app.get("/sse", async (req, res) => {
|
|
372
392
|
console.error("[MCP] Attempting SSE Connection...");
|
|
373
393
|
const transport = new sse_js_1.SSEServerTransport("/message", res);
|
|
374
|
-
const newServer = createConfiguredServer()
|
|
394
|
+
const newServer = createConfiguredServer((name) => {
|
|
395
|
+
const session = sessions.get(transport.sessionId);
|
|
396
|
+
if (session)
|
|
397
|
+
session.clientName = name;
|
|
398
|
+
});
|
|
375
399
|
try {
|
|
376
400
|
await newServer.connect(transport);
|
|
377
401
|
sessions.set(transport.sessionId, { server: newServer, transport });
|
|
@@ -383,7 +407,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
383
407
|
console.error(`[MCP] SSE Connection Error: ${transport.sessionId}`, err);
|
|
384
408
|
sessions.delete(transport.sessionId);
|
|
385
409
|
};
|
|
386
|
-
await transport.start();
|
|
410
|
+
// await transport.start(); // FIXED: connect() starts it automatically
|
|
387
411
|
}
|
|
388
412
|
catch (err) {
|
|
389
413
|
console.error("[MCP] Failed to start SSE transport:", err);
|
|
@@ -402,7 +426,10 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
402
426
|
return;
|
|
403
427
|
}
|
|
404
428
|
try {
|
|
405
|
-
|
|
429
|
+
const clientName = session.clientName || "sse-client";
|
|
430
|
+
await requestContext.run({ clientName }, async () => {
|
|
431
|
+
await session.transport.handlePostMessage(req, res);
|
|
432
|
+
});
|
|
406
433
|
}
|
|
407
434
|
catch (err) {
|
|
408
435
|
console.error(`[MCP] Error handling message for session ${sessionId}:`, err);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { expect, test } from "@playwright/test";
|
|
2
|
+
import { ChildProcess, spawn } from "child_process";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
test.describe("MCP SSE Transport", () => {
|
|
6
|
+
let serverProcess: ChildProcess;
|
|
7
|
+
const PORT = 3101; // Use unique port for this test
|
|
8
|
+
|
|
9
|
+
test.setTimeout(120000);
|
|
10
|
+
|
|
11
|
+
test.beforeAll(async () => {
|
|
12
|
+
// Start the server in http mode
|
|
13
|
+
const serverPath = path.join(__dirname, "../dist/index.js");
|
|
14
|
+
serverProcess = spawn(
|
|
15
|
+
"node",
|
|
16
|
+
[
|
|
17
|
+
serverPath,
|
|
18
|
+
"--port",
|
|
19
|
+
PORT.toString(),
|
|
20
|
+
"--env",
|
|
21
|
+
"test",
|
|
22
|
+
"--db-path",
|
|
23
|
+
":memory:",
|
|
24
|
+
],
|
|
25
|
+
{
|
|
26
|
+
stdio: "pipe",
|
|
27
|
+
env: { ...process.env, OM_DB_PATH: ":memory:" },
|
|
28
|
+
},
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
// Wait for server to start
|
|
32
|
+
await new Promise<void>((resolve, reject) => {
|
|
33
|
+
serverProcess.stderr?.on("data", (data) => {
|
|
34
|
+
const output = data.toString();
|
|
35
|
+
console.log("[Server]", output);
|
|
36
|
+
if (
|
|
37
|
+
output.includes(`CyberMem MCP running on http://localhost:${PORT}`)
|
|
38
|
+
) {
|
|
39
|
+
resolve();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
serverProcess.on("error", reject);
|
|
43
|
+
setTimeout(() => reject(new Error("Server start timeout")), 60000);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test.afterAll(() => {
|
|
48
|
+
serverProcess.kill();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("should establish SSE connection without crashing", async () => {
|
|
52
|
+
const response = await fetch(`http://localhost:${PORT}/sse`);
|
|
53
|
+
expect(response.status).toBe(200);
|
|
54
|
+
expect(response.headers.get("content-type")).toBe("text/event-stream");
|
|
55
|
+
|
|
56
|
+
// Read stream for a bit to ensure it doesn't close immediately due to error
|
|
57
|
+
const reader = response.body?.getReader();
|
|
58
|
+
expect(reader).toBeDefined();
|
|
59
|
+
|
|
60
|
+
const decoder = new TextDecoder();
|
|
61
|
+
let endpointFound = false;
|
|
62
|
+
|
|
63
|
+
// Read first few chunks
|
|
64
|
+
for (let i = 0; i < 3; i++) {
|
|
65
|
+
const { value, done } = await reader!.read();
|
|
66
|
+
if (done) break;
|
|
67
|
+
const text = decoder.decode(value);
|
|
68
|
+
if (text.includes("event: endpoint")) {
|
|
69
|
+
endpointFound = true;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
expect(endpointFound).toBe(true);
|
|
74
|
+
|
|
75
|
+
// Cleanup connection
|
|
76
|
+
await reader?.cancel();
|
|
77
|
+
|
|
78
|
+
// Check if server process is still running (didn't crash)
|
|
79
|
+
expect(serverProcess.exitCode).toBeNull();
|
|
80
|
+
});
|
|
81
|
+
});
|
package/package.json
CHANGED
package/playwright.config.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -8,12 +8,25 @@ import { InitializeRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
|
8
8
|
import { AsyncLocalStorage } from "async_hooks";
|
|
9
9
|
import cors from "cors";
|
|
10
10
|
import express from "express";
|
|
11
|
+
import { readFileSync } from "fs";
|
|
12
|
+
import { join } from "path";
|
|
11
13
|
import { z } from "zod";
|
|
12
14
|
|
|
13
15
|
// Type definition for OpenMemory Memory class
|
|
14
16
|
interface IMemory {
|
|
15
|
-
add(
|
|
16
|
-
|
|
17
|
+
add(
|
|
18
|
+
content: string,
|
|
19
|
+
opts?: { tags?: string[]; user_id?: string; [key: string]: unknown },
|
|
20
|
+
): Promise<unknown>;
|
|
21
|
+
search(
|
|
22
|
+
query: string,
|
|
23
|
+
opts?: {
|
|
24
|
+
limit?: number;
|
|
25
|
+
user_id?: string;
|
|
26
|
+
sectors?: unknown;
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
},
|
|
29
|
+
): Promise<unknown>;
|
|
17
30
|
get(id: string): Promise<unknown>;
|
|
18
31
|
delete_all(user_id: string): Promise<unknown>;
|
|
19
32
|
wipe(): Promise<unknown>;
|
|
@@ -28,6 +41,16 @@ const requestContext = new AsyncLocalStorage<{
|
|
|
28
41
|
// CLI args processing
|
|
29
42
|
const args = process.argv.slice(2);
|
|
30
43
|
|
|
44
|
+
// Read version from package.json
|
|
45
|
+
let PACKAGE_VERSION = "0.0.0";
|
|
46
|
+
try {
|
|
47
|
+
const packageJsonPath = join(__dirname, "../package.json");
|
|
48
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
49
|
+
PACKAGE_VERSION = packageJson.version;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error("[MCP] Failed to read package.json version", error);
|
|
52
|
+
}
|
|
53
|
+
|
|
31
54
|
// Start the server
|
|
32
55
|
startServer();
|
|
33
56
|
|
|
@@ -47,8 +70,17 @@ async function startServer() {
|
|
|
47
70
|
// --- IMPLEMENTATION LOGIC ---
|
|
48
71
|
|
|
49
72
|
let memory: IMemory | null = null;
|
|
50
|
-
let sdk_update_memory:
|
|
51
|
-
|
|
73
|
+
let sdk_update_memory:
|
|
74
|
+
| ((
|
|
75
|
+
id: string,
|
|
76
|
+
content?: string,
|
|
77
|
+
tags?: string[],
|
|
78
|
+
metadata?: Record<string, unknown>,
|
|
79
|
+
) => Promise<unknown>)
|
|
80
|
+
| null = null;
|
|
81
|
+
let sdk_reinforce_memory:
|
|
82
|
+
| ((id: string, boost?: number) => Promise<unknown>)
|
|
83
|
+
| null = null;
|
|
52
84
|
|
|
53
85
|
// LOCAL SDK MODE
|
|
54
86
|
const dbPath = process.env.OM_DB_PATH!;
|
|
@@ -122,15 +154,10 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
122
154
|
const logActivity = async (
|
|
123
155
|
operation: string,
|
|
124
156
|
opts: {
|
|
125
|
-
details?: unknown;
|
|
126
|
-
query?: string;
|
|
127
|
-
memoryId?: string;
|
|
128
|
-
delta?: string;
|
|
129
|
-
tags?: string[];
|
|
130
|
-
sessionId?: string;
|
|
131
157
|
method?: string;
|
|
132
158
|
endpoint?: string;
|
|
133
159
|
status?: number;
|
|
160
|
+
sessionId?: string;
|
|
134
161
|
} = {},
|
|
135
162
|
) => {
|
|
136
163
|
// Determine client name (priority: specific > store > default)
|
|
@@ -138,7 +165,8 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
138
165
|
const ctx = requestContext.getStore();
|
|
139
166
|
|
|
140
167
|
if (opts.sessionId) {
|
|
141
|
-
|
|
168
|
+
// For SSE sessions, prefer the real client name from the request context when available
|
|
169
|
+
client = ctx?.clientName || "sse-client";
|
|
142
170
|
} else if (ctx) {
|
|
143
171
|
client = ctx.clientName || stdioClientName || "unknown";
|
|
144
172
|
} else {
|
|
@@ -156,7 +184,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
156
184
|
[
|
|
157
185
|
ts,
|
|
158
186
|
client,
|
|
159
|
-
|
|
187
|
+
PACKAGE_VERSION,
|
|
160
188
|
method,
|
|
161
189
|
endpoint,
|
|
162
190
|
operation,
|
|
@@ -173,17 +201,19 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
173
201
|
};
|
|
174
202
|
|
|
175
203
|
// Factory to create configured McpServer instance
|
|
176
|
-
const createConfiguredServer = (
|
|
204
|
+
const createConfiguredServer = (
|
|
205
|
+
onClientConnected?: (name: string) => void,
|
|
206
|
+
) => {
|
|
177
207
|
const server = new McpServer(
|
|
178
|
-
{ name: "cybermem", version:
|
|
208
|
+
{ name: "cybermem", version: PACKAGE_VERSION },
|
|
179
209
|
{
|
|
180
210
|
instructions: CYBERMEM_INSTRUCTIONS,
|
|
181
211
|
},
|
|
182
212
|
);
|
|
183
213
|
|
|
184
|
-
// access underlying server
|
|
185
|
-
|
|
186
|
-
|
|
214
|
+
// access underlying server to set internal state for direct memory access
|
|
215
|
+
// Casting to unknown first to allow adding private property
|
|
216
|
+
(server as unknown as { _memoryReady: boolean })._memoryReady = true;
|
|
187
217
|
|
|
188
218
|
server.registerResource(
|
|
189
219
|
"CyberMem Agent Protocol",
|
|
@@ -207,10 +237,14 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
207
237
|
// For SSE multiple clients, stdioClientName global is less useful,
|
|
208
238
|
// but we can set it for context if running in single-user mode.
|
|
209
239
|
// For multi-user, rely on requestContext.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
240
|
+
// For SSE multiple clients, rely on per-request context instead of a global.
|
|
241
|
+
const clientName = request.params.clientInfo.name;
|
|
242
|
+
if (onClientConnected) {
|
|
243
|
+
onClientConnected(clientName);
|
|
244
|
+
} else {
|
|
245
|
+
stdioClientName = clientName;
|
|
246
|
+
}
|
|
247
|
+
console.error(`[MCP] Client identified via handshake: ${clientName}`);
|
|
214
248
|
return {
|
|
215
249
|
protocolVersion: "2024-11-05",
|
|
216
250
|
capabilities: {
|
|
@@ -219,7 +253,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
219
253
|
},
|
|
220
254
|
serverInfo: {
|
|
221
255
|
name: "cybermem",
|
|
222
|
-
version:
|
|
256
|
+
version: PACKAGE_VERSION,
|
|
223
257
|
},
|
|
224
258
|
};
|
|
225
259
|
},
|
|
@@ -252,7 +286,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
252
286
|
"query_memory",
|
|
253
287
|
{
|
|
254
288
|
description: "Search memories.",
|
|
255
|
-
inputSchema: z.object({ query: z.string(), k: z.number().default(
|
|
289
|
+
inputSchema: z.object({ query: z.string(), k: z.number().default(5) }),
|
|
256
290
|
},
|
|
257
291
|
async (args: { query: string; k?: number }) => {
|
|
258
292
|
const res = await memory!.search(args.query, { limit: args.k });
|
|
@@ -279,7 +313,9 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
279
313
|
async (args: { id: string; content?: string; tags?: string[] }) => {
|
|
280
314
|
if (!sdk_update_memory) throw new Error("Update not available in SDK");
|
|
281
315
|
if (args.content === undefined && args.tags === undefined) {
|
|
282
|
-
throw new Error(
|
|
316
|
+
throw new Error(
|
|
317
|
+
"At least one of 'content' or 'tags' must be provided to update_memory",
|
|
318
|
+
);
|
|
283
319
|
}
|
|
284
320
|
const res = await sdk_update_memory(args.id, args.content, args.tags);
|
|
285
321
|
await logActivity("update", {
|
|
@@ -357,7 +393,9 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
357
393
|
const app = express();
|
|
358
394
|
app.use(cors());
|
|
359
395
|
app.use(express.json());
|
|
360
|
-
app.get("/health", (req, res) =>
|
|
396
|
+
app.get("/health", (req, res) =>
|
|
397
|
+
res.json({ ok: true, version: PACKAGE_VERSION }),
|
|
398
|
+
);
|
|
361
399
|
|
|
362
400
|
app.use((req, res, next) => {
|
|
363
401
|
const clientName =
|
|
@@ -467,6 +505,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
467
505
|
{
|
|
468
506
|
server: McpServer;
|
|
469
507
|
transport: SSEServerTransport;
|
|
508
|
+
clientName?: string;
|
|
470
509
|
}
|
|
471
510
|
>();
|
|
472
511
|
|
|
@@ -482,7 +521,10 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
482
521
|
app.get("/sse", async (req, res) => {
|
|
483
522
|
console.error("[MCP] Attempting SSE Connection...");
|
|
484
523
|
const transport = new SSEServerTransport("/message", res);
|
|
485
|
-
const newServer = createConfiguredServer()
|
|
524
|
+
const newServer = createConfiguredServer((name) => {
|
|
525
|
+
const session = sessions.get(transport.sessionId);
|
|
526
|
+
if (session) session.clientName = name;
|
|
527
|
+
});
|
|
486
528
|
|
|
487
529
|
try {
|
|
488
530
|
await newServer.connect(transport);
|
|
@@ -500,7 +542,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
500
542
|
sessions.delete(transport.sessionId);
|
|
501
543
|
};
|
|
502
544
|
|
|
503
|
-
await transport.start();
|
|
545
|
+
// await transport.start(); // FIXED: connect() starts it automatically
|
|
504
546
|
} catch (err) {
|
|
505
547
|
console.error("[MCP] Failed to start SSE transport:", err);
|
|
506
548
|
sessions.delete(transport.sessionId);
|
|
@@ -519,7 +561,10 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
|
|
|
519
561
|
return;
|
|
520
562
|
}
|
|
521
563
|
try {
|
|
522
|
-
|
|
564
|
+
const clientName = session.clientName || "sse-client";
|
|
565
|
+
await requestContext.run({ clientName }, async () => {
|
|
566
|
+
await session.transport.handlePostMessage(req, res);
|
|
567
|
+
});
|
|
523
568
|
} catch (err) {
|
|
524
569
|
console.error(
|
|
525
570
|
`[MCP] Error handling message for session ${sessionId}:`,
|