@socketsecurity/mcp 0.0.10 → 0.0.12

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/README.md CHANGED
@@ -25,7 +25,7 @@ The easiest way to get started is to use our public Socket MCP server. **No API
25
25
 
26
26
 
27
27
  [![Install in VS Code](https://img.shields.io/badge/VS_Code-Socket_MCP-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=socket-mcp&config={"url":"https://mcp.socket.dev/","type":"http"})
28
- [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=socket-mcp&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vbWNwLnNvY2tldC5kZXYifQ%3D%3D)
28
+ [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=socket-mcp&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vbWNwLnNvY2tldC5kZXYvIn0%3D)
29
29
 
30
30
 
31
31
  <details><summary><b>Manual Installation Instructions & more MCP Clients</b></summary>
@@ -149,7 +149,7 @@ For local deployment, you have two options:
149
149
  Click a button below to install the self-hosted stdio server in your favorite AI assistant.
150
150
 
151
151
  [![Install in VS Code](https://img.shields.io/badge/VS_Code-Socket_MCP-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=socket-mcp&config={"command":"npx","args":["@socketsecurity/mcp@latest"],"type":"stdio"})
152
- [![Install in Cursor (stdio)](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=socket-mcp-stdio&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyJAc29ja2V0c2VjdXJpdHkvbWNwQGxhdGVzdCJdLCJlbnYiOnsiU09DS0VUX0FQSV9LRVkiOiJ5b3VyLWFwaS1rZXktaGVyZSJ9fQ==)
152
+ [![Install in Cursor (stdio)](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=socket-mcp&config=eyJjb21tYW5kIjoibnB4IEBzb2NrZXRzZWN1cml0eS9tY3BAbGF0ZXN0IiwiZW52Ijp7IlNPQ0tFVF9BUElfS0VZIjoieW91ci1hcGkta2V5LWhlcmUifX0%3D)
153
153
 
154
154
  Claude Code (stdio mode) can be set up with the following command:
155
155
 
@@ -374,3 +374,12 @@ MCP_HTTP_MODE=true SOCKET_API_KEY=your_api_key_here node --experimental-strip-ty
374
374
  - 📖 [Socket Documentation](https://docs.socket.dev)
375
375
  - 🐛 [Report Issues](https://github.com/SocketDev/socket-mcp/issues)
376
376
  - 💬 [Community Support](https://github.com/SocketDev/socket-mcp/discussions)
377
+
378
+ <br/>
379
+ <div align="center">
380
+ <picture>
381
+ <source media="(prefers-color-scheme: dark)" srcset="logo-white.png">
382
+ <source media="(prefers-color-scheme: light)" srcset="logo-black.png">
383
+ <img width="324" height="108" alt="Socket Logo" src="logo-black.png">
384
+ </picture>
385
+ </div>
package/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- #!/usr/bin/env node --experimental-strip-types
1
+ #!/usr/bin/env -S node --experimental-strip-types
2
2
  export {};
3
3
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node --experimental-strip-types
1
+ #!/usr/bin/env -S node --experimental-strip-types
2
2
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
4
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
@@ -9,8 +9,6 @@ import { join } from 'path';
9
9
  import { readFileSync } from 'fs';
10
10
  import { tmpdir } from 'os';
11
11
  import { createServer } from 'http';
12
- import { randomUUID } from 'crypto';
13
- import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
14
12
  const __dirname = import.meta.dirname;
15
13
  const packageJson = JSON.parse(readFileSync(join(__dirname, './package.json'), 'utf8'));
16
14
  const VERSION = packageJson.version || '0.0.1';
@@ -52,7 +50,6 @@ async function getApiKeyInteractively() {
52
50
  return apiKey;
53
51
  }
54
52
  let SOCKET_API_KEY = process.env['SOCKET_API_KEY'] || '';
55
- const transports = {};
56
53
  const server = new McpServer({
57
54
  name: 'socket',
58
55
  version: VERSION,
@@ -204,6 +201,7 @@ if (!SOCKET_API_KEY) {
204
201
  }
205
202
  if (useHttp) {
206
203
  logger.info(`Starting HTTP server on port ${port}`);
204
+ let httpTransport = null;
207
205
  const httpServer = createServer(async (req, res) => {
208
206
  const origin = req.headers.origin;
209
207
  const allowedOrigins = [
@@ -229,9 +227,8 @@ if (useHttp) {
229
227
  else {
230
228
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
231
229
  }
232
- res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
233
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type, mcp-session-id, Accept, Last-Event-ID');
234
- res.setHeader('Access-Control-Expose-Headers', 'mcp-session-id');
230
+ res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
231
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Accept');
235
232
  if (req.method === 'OPTIONS') {
236
233
  res.writeHead(200);
237
234
  res.end();
@@ -263,79 +260,34 @@ if (useHttp) {
263
260
  }
264
261
  if (url.pathname === '/') {
265
262
  if (req.method === 'POST') {
266
- const acceptHeader = req.headers.accept;
267
- if (!acceptHeader || (!acceptHeader.includes('application/json') && !acceptHeader.includes('text/event-stream'))) {
268
- logger.warn(`Invalid Accept header: ${acceptHeader}`);
269
- res.writeHead(400, { 'Content-Type': 'application/json' });
270
- res.end(JSON.stringify({
271
- jsonrpc: '2.0',
272
- error: { code: -32000, message: 'Bad Request: Accept header must include application/json or text/event-stream' },
273
- id: null
274
- }));
275
- return;
276
- }
277
263
  let body = '';
278
264
  req.on('data', chunk => (body += chunk));
279
265
  req.on('end', async () => {
280
266
  try {
281
267
  const jsonData = JSON.parse(body);
282
- const sessionId = req.headers['mcp-session-id'];
283
- if (sessionId && !/^[\x21-\x7E]+$/.test(sessionId)) {
284
- logger.warn(`Invalid session ID format: ${sessionId}`);
285
- res.writeHead(400, { 'Content-Type': 'application/json' });
286
- res.end(JSON.stringify({
287
- jsonrpc: '2.0',
288
- error: { code: -32000, message: 'Bad Request: Session ID must contain only visible ASCII characters' },
289
- id: jsonData.id || null
290
- }));
291
- return;
292
- }
293
- let transport;
294
- if (sessionId && transports[sessionId]) {
295
- transport = transports[sessionId];
296
- }
297
- else if (!sessionId) {
298
- const newSessionId = randomUUID();
299
- const isInit = isInitializeRequest(jsonData);
300
- if (isInit) {
301
- logger.info(`Creating new session for initialize request: ${newSessionId}`);
302
- }
303
- else {
304
- logger.warn(`Creating fallback session for non-initialize request: ${newSessionId}`);
305
- }
306
- transport = new StreamableHTTPServerTransport({
307
- sessionIdGenerator: () => newSessionId,
308
- onsessioninitialized: (id) => {
309
- transports[id] = transport;
310
- logger.info(`Session initialized: ${id}`);
311
- res.setHeader('mcp-session-id', id);
268
+ if (jsonData && jsonData.method === 'initialize') {
269
+ if (httpTransport) {
270
+ try {
271
+ httpTransport.close();
312
272
  }
273
+ catch { }
274
+ }
275
+ httpTransport = new StreamableHTTPServerTransport({
276
+ sessionIdGenerator: undefined,
277
+ enableJsonResponse: true
313
278
  });
314
- transport.onclose = () => {
315
- const sid = transport.sessionId;
316
- if (sid && transports[sid]) {
317
- delete transports[sid];
318
- logger.info(`Session closed: ${sid}`);
319
- }
320
- };
321
- await server.connect(transport);
322
- await transport.handleRequest(req, res, jsonData);
279
+ await server.connect(httpTransport);
280
+ await httpTransport.handleRequest(req, res, jsonData);
323
281
  return;
324
282
  }
325
- else {
326
- logger.error(`Invalid session ID: ${sessionId}. Active sessions count: ${Object.keys(transports).length}`);
327
- res.writeHead(400);
328
- res.end(JSON.stringify({
329
- jsonrpc: '2.0',
330
- error: {
331
- code: -32000,
332
- message: 'Bad Request: Invalid session ID. Please initialize a new session first.'
333
- },
334
- id: jsonData.id || null
335
- }));
336
- return;
283
+ if (!httpTransport) {
284
+ httpTransport = new StreamableHTTPServerTransport({
285
+ sessionIdGenerator: undefined,
286
+ enableJsonResponse: true
287
+ });
288
+ await server.connect(httpTransport);
337
289
  }
338
- await transport.handleRequest(req, res, jsonData);
290
+ await httpTransport.handleRequest(req, res, jsonData);
339
291
  }
340
292
  catch (error) {
341
293
  logger.error(`Error processing POST request: ${error}`);
@@ -350,91 +302,6 @@ if (useHttp) {
350
302
  }
351
303
  });
352
304
  }
353
- else if (req.method === 'GET') {
354
- const acceptHeader = req.headers.accept;
355
- if (!acceptHeader || !acceptHeader.includes('text/event-stream')) {
356
- logger.warn(`GET request without text/event-stream Accept header: ${acceptHeader}`);
357
- res.writeHead(405, { 'Content-Type': 'application/json' });
358
- res.end(JSON.stringify({
359
- jsonrpc: '2.0',
360
- error: { code: -32000, message: 'Method Not Allowed: GET requires Accept: text/event-stream' },
361
- id: null
362
- }));
363
- return;
364
- }
365
- const sessionId = req.headers['mcp-session-id'];
366
- if (sessionId && !/^[\x21-\x7E]+$/.test(sessionId)) {
367
- logger.warn(`Invalid session ID format in GET request: ${sessionId}`);
368
- res.writeHead(400, { 'Content-Type': 'application/json' });
369
- res.end(JSON.stringify({
370
- jsonrpc: '2.0',
371
- error: { code: -32000, message: 'Bad Request: Session ID must contain only visible ASCII characters' },
372
- id: null
373
- }));
374
- return;
375
- }
376
- if (!sessionId || !transports[sessionId]) {
377
- logger.warn(`SSE request with invalid session ID: ${sessionId}`);
378
- res.writeHead(400, { 'Content-Type': 'application/json' });
379
- res.end(JSON.stringify({
380
- jsonrpc: '2.0',
381
- error: { code: -32000, message: 'Bad Request: Invalid or missing session ID for SSE stream' },
382
- id: null
383
- }));
384
- return;
385
- }
386
- const lastEventId = req.headers['last-event-id'];
387
- if (lastEventId) {
388
- logger.info(`SSE resumability requested with Last-Event-ID: ${lastEventId}`);
389
- }
390
- logger.info(`Opening SSE stream for session: ${sessionId}`);
391
- req.socket?.setTimeout(0);
392
- req.socket?.setKeepAlive(true, 30000);
393
- let streamClosed = false;
394
- req.on('close', () => {
395
- streamClosed = true;
396
- logger.info(`Client disconnected SSE stream for session: ${sessionId}`);
397
- });
398
- req.on('aborted', () => {
399
- streamClosed = true;
400
- logger.info(`Client aborted SSE stream for session: ${sessionId}`);
401
- });
402
- const transport = transports[sessionId];
403
- try {
404
- await transport.handleRequest(req, res);
405
- if (!streamClosed && !res.destroyed) {
406
- logger.info(`Transport completed, maintaining SSE stream for session: ${sessionId}`);
407
- const heartbeat = setInterval(() => {
408
- if (streamClosed || res.destroyed) {
409
- clearInterval(heartbeat);
410
- return;
411
- }
412
- try {
413
- res.write(': heartbeat\n\n');
414
- }
415
- catch (error) {
416
- logger.error(error, `Heartbeat error for session ${sessionId}:`);
417
- clearInterval(heartbeat);
418
- }
419
- }, 30000);
420
- req.on('close', () => clearInterval(heartbeat));
421
- res.on('close', () => clearInterval(heartbeat));
422
- }
423
- }
424
- catch (error) {
425
- logger.error(error, `SSE transport error for session ${sessionId}:`);
426
- }
427
- }
428
- else if (req.method === 'DELETE') {
429
- const sessionId = req.headers['mcp-session-id'];
430
- if (!sessionId || !transports[sessionId]) {
431
- res.writeHead(400);
432
- res.end('Invalid or missing session ID');
433
- return;
434
- }
435
- const transport = transports[sessionId];
436
- await transport.handleRequest(req, res);
437
- }
438
305
  else {
439
306
  res.writeHead(405);
440
307
  res.end('Method not allowed');
@@ -16,10 +16,8 @@ async function parseResponse(response) {
16
16
  }
17
17
  async function testHTTPMode() {
18
18
  const baseUrl = (process.env['MCP_URL'] || 'http://localhost:3000').replace(/\/$/, '');
19
- const sessionId = `test-session-${Date.now()}`;
20
19
  console.log('Testing Socket MCP in HTTP mode...');
21
20
  console.log(`Server URL: ${baseUrl}`);
22
- console.log(`Session ID: ${sessionId}`);
23
21
  try {
24
22
  console.log('\n1. Initializing connection...');
25
23
  const initRequest = {
@@ -46,9 +44,7 @@ async function testHTTPMode() {
46
44
  });
47
45
  const initResult = await parseResponse(initResponse);
48
46
  console.log('Initialize response:', JSON.stringify(initResult, null, 2));
49
- const serverSessionId = initResponse.headers.get('mcp-session-id');
50
- const actualSessionId = serverSessionId || sessionId;
51
- console.log('Session ID:', actualSessionId);
47
+ console.log('Initialized (stateless)');
52
48
  console.log('\n2. Listing available tools...');
53
49
  const toolsRequest = {
54
50
  jsonrpc: '2.0',
@@ -60,13 +56,18 @@ async function testHTTPMode() {
60
56
  method: 'POST',
61
57
  headers: {
62
58
  'Content-Type': 'application/json',
63
- Accept: 'application/json, text/event-stream',
64
- 'mcp-session-id': actualSessionId
59
+ Accept: 'application/json, text/event-stream'
65
60
  },
66
61
  body: JSON.stringify(toolsRequest)
67
62
  });
68
63
  const toolsResult = await parseResponse(toolsResponse);
69
64
  console.log('Available tools:', JSON.stringify(toolsResult, null, 2));
65
+ if (!toolsResult ||
66
+ !toolsResult.result ||
67
+ !Array.isArray(toolsResult.result.tools) ||
68
+ !toolsResult.result.tools.some((tool) => tool.name === 'depscore')) {
69
+ throw new Error('depscore tool not found in available tools');
70
+ }
70
71
  console.log('\n3. Calling depscore tool...');
71
72
  const depscoreRequest = {
72
73
  jsonrpc: '2.0',
@@ -87,32 +88,13 @@ async function testHTTPMode() {
87
88
  method: 'POST',
88
89
  headers: {
89
90
  'Content-Type': 'application/json',
90
- Accept: 'application/json, text/event-stream',
91
- 'mcp-session-id': actualSessionId
91
+ Accept: 'application/json, text/event-stream'
92
92
  },
93
93
  body: JSON.stringify(depscoreRequest)
94
94
  });
95
95
  const depscoreResult = await parseResponse(depscoreResponse);
96
96
  console.log('Depscore result:', JSON.stringify(depscoreResult, null, 2));
97
- console.log('\n4. Testing SSE stream connection...');
98
- const sseResponse = await fetch(`${baseUrl}/`, {
99
- method: 'GET',
100
- headers: {
101
- 'mcp-session-id': actualSessionId,
102
- Accept: 'text/event-stream'
103
- }
104
- });
105
- if (sseResponse.ok) {
106
- console.log('SSE stream connected successfully');
107
- }
108
- console.log('\n5. Cleaning up session...');
109
- const cleanupResponse = await fetch(`${baseUrl}/`, {
110
- method: 'DELETE',
111
- headers: {
112
- 'mcp-session-id': actualSessionId
113
- }
114
- });
115
- console.log('Session cleanup:', cleanupResponse.status === 200 ? 'Success' : 'Failed');
97
+ console.log('\n4. HTTP mode test complete (no sessions)');
116
98
  }
117
99
  catch (error) {
118
100
  console.error('Error:', error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@socketsecurity/mcp",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -28,8 +28,8 @@
28
28
  "debug-stdio": "node --experimental-strip-types ./mock-client/debug-client.ts",
29
29
  "debug-sdk": "node --experimental-strip-types ./mock-client/stdio-client.ts",
30
30
  "debug-http": "node --experimental-strip-types ./mock-client/http-client.ts",
31
- "server-stdio": "SOCKET_API_KEY=${SOCKET_API_KEY} --experimental-strip-types ./index.ts",
32
- "server-http": "MCP_HTTP_MODE=true SOCKET_API_KEY=${SOCKET_API_KEY} ./build/index.js"
31
+ "server-stdio": "SOCKET_API_KEY=${SOCKET_API_KEY} node --experimental-strip-types ./index.ts",
32
+ "server-http": "MCP_HTTP_MODE=true SOCKET_API_KEY=${SOCKET_API_KEY} node --experimental-strip-types ./index.ts"
33
33
  },
34
34
  "keywords": [],
35
35
  "files": [
@@ -46,19 +46,19 @@
46
46
  "url": "https://github.com/SocketDev/socket-mcp"
47
47
  },
48
48
  "dependencies": {
49
- "@modelcontextprotocol/sdk": "^1.11.3",
49
+ "@modelcontextprotocol/sdk": "^1.18.0",
50
50
  "pino": "^9.7.0",
51
51
  "pino-pretty": "^13.0.0",
52
52
  "semver": "^7.7.2",
53
53
  "zod": "^3.24.4"
54
54
  },
55
55
  "devDependencies": {
56
- "neostandard": "^0.12.0",
57
56
  "@anthropic-ai/dxt": "^0.2.0",
58
57
  "@types/node": "^24.0.7",
59
58
  "@types/semver": "^7.7.0",
60
59
  "@types/triple-beam": "^1.3.5",
61
60
  "c8": "^10.0.0",
61
+ "neostandard": "^0.12.0",
62
62
  "npm-run-all2": "^8.0.1",
63
63
  "typescript": "~5.9.2"
64
64
  }