screenpipe-mcp 0.18.6 → 0.18.7

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.
@@ -284,11 +284,14 @@ function buildHttpServer(config) {
284
284
  const server = createMcpServer(fetchAPI);
285
285
  const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
286
286
  sessionIdGenerator: () => crypto.randomUUID(),
287
+ onsessioninitialized: (newSessionId) => {
288
+ sessions.set(newSessionId, { server, transport });
289
+ },
290
+ onsessionclosed: (closedSessionId) => {
291
+ sessions.delete(closedSessionId);
292
+ },
287
293
  });
288
294
  await server.connect(transport);
289
- if (transport.sessionId) {
290
- sessions.set(transport.sessionId, { server, transport });
291
- }
292
295
  session = { server, transport };
293
296
  }
294
297
  await session.transport.handleRequest(req, res);
@@ -147,3 +147,74 @@ const http_server_1 = require("./http-server");
147
147
  (0, vitest_1.expect)((0, http_server_1.isAuthorized)(lan("Bearer SECRET"), "secret")).toBe(false);
148
148
  });
149
149
  });
150
+ (0, vitest_1.describe)("buildHttpServer", () => {
151
+ (0, vitest_1.it)("persists initialized sessions so tools/list works on the next request", async () => {
152
+ const server = (0, http_server_1.buildHttpServer)({
153
+ mcpPort: 0,
154
+ screenpipePort: 3030,
155
+ host: "127.0.0.1",
156
+ apiKey: "secret",
157
+ });
158
+ await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
159
+ const address = server.address();
160
+ if (!address || typeof address === "string") {
161
+ throw new Error("expected server.address() to return a bound port");
162
+ }
163
+ const baseUrl = `http://127.0.0.1:${address.port}`;
164
+ try {
165
+ const initResponse = await fetch(`${baseUrl}/mcp`, {
166
+ method: "POST",
167
+ headers: {
168
+ authorization: "Bearer secret",
169
+ "content-type": "application/json",
170
+ accept: "application/json, text/event-stream",
171
+ },
172
+ body: JSON.stringify({
173
+ jsonrpc: "2.0",
174
+ id: 1,
175
+ method: "initialize",
176
+ params: {
177
+ protocolVersion: "2024-11-05",
178
+ capabilities: {},
179
+ clientInfo: { name: "vitest", version: "1.0.0" },
180
+ },
181
+ }),
182
+ });
183
+ (0, vitest_1.expect)(initResponse.status).toBe(200);
184
+ const sessionId = initResponse.headers.get("mcp-session-id");
185
+ (0, vitest_1.expect)(sessionId).toBeTruthy();
186
+ await initResponse.text();
187
+ const healthResponse = await fetch(`${baseUrl}/health`);
188
+ (0, vitest_1.expect)(healthResponse.status).toBe(200);
189
+ (0, vitest_1.expect)(await healthResponse.json()).toEqual({ status: "ok", sessions: 1 });
190
+ const toolsResponse = await fetch(`${baseUrl}/mcp`, {
191
+ method: "POST",
192
+ headers: {
193
+ authorization: "Bearer secret",
194
+ "content-type": "application/json",
195
+ accept: "application/json, text/event-stream",
196
+ "mcp-session-id": sessionId,
197
+ "mcp-protocol-version": "2024-11-05",
198
+ },
199
+ body: JSON.stringify({
200
+ jsonrpc: "2.0",
201
+ id: 2,
202
+ method: "tools/list",
203
+ params: {},
204
+ }),
205
+ });
206
+ (0, vitest_1.expect)(toolsResponse.status).toBe(200);
207
+ (0, vitest_1.expect)(await toolsResponse.text()).toContain('"name":"search_content"');
208
+ }
209
+ finally {
210
+ await new Promise((resolve, reject) => {
211
+ server.close((err) => {
212
+ if (err)
213
+ reject(err);
214
+ else
215
+ resolve();
216
+ });
217
+ });
218
+ }
219
+ });
220
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "screenpipe-mcp",
3
- "version": "0.18.6",
3
+ "version": "0.18.7",
4
4
  "description": "MCP server for screenpipe - search your screen recordings and audio transcriptions",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { describe, it, expect } from "vitest";
6
6
  import {
7
+ buildHttpServer,
7
8
  CliError,
8
9
  isAuthorized,
9
10
  isLoopbackRequest,
@@ -178,3 +179,80 @@ describe("isAuthorized", () => {
178
179
  expect(isAuthorized(lan("Bearer SECRET"), "secret")).toBe(false);
179
180
  });
180
181
  });
182
+
183
+ describe("buildHttpServer", () => {
184
+ it("persists initialized sessions so tools/list works on the next request", async () => {
185
+ const server = buildHttpServer({
186
+ mcpPort: 0,
187
+ screenpipePort: 3030,
188
+ host: "127.0.0.1",
189
+ apiKey: "secret",
190
+ });
191
+
192
+ await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
193
+
194
+ const address = server.address();
195
+ if (!address || typeof address === "string") {
196
+ throw new Error("expected server.address() to return a bound port");
197
+ }
198
+
199
+ const baseUrl = `http://127.0.0.1:${address.port}`;
200
+
201
+ try {
202
+ const initResponse = await fetch(`${baseUrl}/mcp`, {
203
+ method: "POST",
204
+ headers: {
205
+ authorization: "Bearer secret",
206
+ "content-type": "application/json",
207
+ accept: "application/json, text/event-stream",
208
+ },
209
+ body: JSON.stringify({
210
+ jsonrpc: "2.0",
211
+ id: 1,
212
+ method: "initialize",
213
+ params: {
214
+ protocolVersion: "2024-11-05",
215
+ capabilities: {},
216
+ clientInfo: { name: "vitest", version: "1.0.0" },
217
+ },
218
+ }),
219
+ });
220
+
221
+ expect(initResponse.status).toBe(200);
222
+ const sessionId = initResponse.headers.get("mcp-session-id");
223
+ expect(sessionId).toBeTruthy();
224
+ await initResponse.text();
225
+
226
+ const healthResponse = await fetch(`${baseUrl}/health`);
227
+ expect(healthResponse.status).toBe(200);
228
+ expect(await healthResponse.json()).toEqual({ status: "ok", sessions: 1 });
229
+
230
+ const toolsResponse = await fetch(`${baseUrl}/mcp`, {
231
+ method: "POST",
232
+ headers: {
233
+ authorization: "Bearer secret",
234
+ "content-type": "application/json",
235
+ accept: "application/json, text/event-stream",
236
+ "mcp-session-id": sessionId!,
237
+ "mcp-protocol-version": "2024-11-05",
238
+ },
239
+ body: JSON.stringify({
240
+ jsonrpc: "2.0",
241
+ id: 2,
242
+ method: "tools/list",
243
+ params: {},
244
+ }),
245
+ });
246
+
247
+ expect(toolsResponse.status).toBe(200);
248
+ expect(await toolsResponse.text()).toContain('"name":"search_content"');
249
+ } finally {
250
+ await new Promise<void>((resolve, reject) => {
251
+ server.close((err) => {
252
+ if (err) reject(err);
253
+ else resolve();
254
+ });
255
+ });
256
+ }
257
+ });
258
+ });
@@ -337,13 +337,15 @@ export function buildHttpServer(config: CliConfig) {
337
337
  const server = createMcpServer(fetchAPI);
338
338
  const transport = new StreamableHTTPServerTransport({
339
339
  sessionIdGenerator: () => crypto.randomUUID(),
340
+ onsessioninitialized: (newSessionId) => {
341
+ sessions.set(newSessionId, { server, transport });
342
+ },
343
+ onsessionclosed: (closedSessionId) => {
344
+ sessions.delete(closedSessionId);
345
+ },
340
346
  });
341
347
 
342
348
  await server.connect(transport);
343
-
344
- if (transport.sessionId) {
345
- sessions.set(transport.sessionId, { server, transport });
346
- }
347
349
  session = { server, transport };
348
350
  }
349
351