@socketsecurity/mcp 0.0.11 → 0.0.13
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 +11 -2
- package/index.js +52 -178
- package/mock-client/http-client.js +10 -28
- package/mock-client/stdio-client.js +1 -1
- package/package.json +14 -11
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
|
[](https://vscode.dev/redirect/mcp/install?name=socket-mcp&config={"url":"https://mcp.socket.dev/","type":"http"})
|
|
28
|
-
[](https://cursor.com/install-mcp?name=socket-mcp&config=
|
|
28
|
+
[](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
|
[](https://vscode.dev/redirect/mcp/install?name=socket-mcp&config={"command":"npx","args":["@socketsecurity/mcp@latest"],"type":"stdio"})
|
|
152
|
-
[](https://cursor.com/install-mcp?name=socket-mcp
|
|
152
|
+
[](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.js
CHANGED
|
@@ -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,47 +50,50 @@ async function getApiKeyInteractively() {
|
|
|
52
50
|
return apiKey;
|
|
53
51
|
}
|
|
54
52
|
let SOCKET_API_KEY = process.env['SOCKET_API_KEY'] || '';
|
|
55
|
-
|
|
53
|
+
function buildSocketHeaders() {
|
|
54
|
+
return {
|
|
55
|
+
'user-agent': `socket-mcp/${VERSION}`,
|
|
56
|
+
accept: 'application/x-ndjson',
|
|
57
|
+
'content-type': 'application/json',
|
|
58
|
+
authorization: `Bearer ${SOCKET_API_KEY}`
|
|
59
|
+
};
|
|
60
|
+
}
|
|
56
61
|
const server = new McpServer({
|
|
57
62
|
name: 'socket',
|
|
58
63
|
version: VERSION,
|
|
59
|
-
description: 'Socket MCP server',
|
|
60
|
-
capabilities: {
|
|
61
|
-
resources: {},
|
|
62
|
-
tools: {},
|
|
63
|
-
streaming: {}
|
|
64
|
-
},
|
|
65
64
|
});
|
|
66
|
-
server.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
server.registerTool('depscore', {
|
|
66
|
+
title: 'Dependency Score Tool',
|
|
67
|
+
description: "Get the dependency score of packages with the `depscore` tool from Socket. Use 'unknown' for version if not known. Use this tool to scan dependencies for their quality and security on existing code or when code is generated. Stop generating code and ask the user how to proceed when any of the scores are low. When checking dependencies, make sure to also check the imports in the code, not just the manifest files (pyproject.toml, package.json, etc).",
|
|
68
|
+
inputSchema: z.object({
|
|
69
|
+
packages: z.array(z.object({
|
|
70
|
+
ecosystem: z.string().describe('The package ecosystem (e.g., npm, pypi)').default('npm'),
|
|
71
|
+
depname: z.string().describe('The name of the dependency'),
|
|
72
|
+
version: z.string().describe("The version of the dependency, use 'unknown' if not known").default('unknown'),
|
|
73
|
+
})).describe('Array of packages to check'),
|
|
74
|
+
}),
|
|
75
|
+
annotations: {
|
|
76
|
+
readOnlyHint: true,
|
|
77
|
+
},
|
|
72
78
|
}, async ({ packages }) => {
|
|
73
79
|
logger.info(`Received request for ${packages.length} packages`);
|
|
74
|
-
const SOCKET_HEADERS = {
|
|
75
|
-
'user-agent': `socket-mcp/${VERSION}`,
|
|
76
|
-
accept: 'application/x-ndjson',
|
|
77
|
-
'content-type': 'application/json',
|
|
78
|
-
authorization: `Bearer ${SOCKET_API_KEY}`
|
|
79
|
-
};
|
|
80
80
|
const components = packages.map(pkg => {
|
|
81
|
-
const cleanedVersion = pkg.version.replace(/[\^~]/g, '');
|
|
81
|
+
const cleanedVersion = (pkg.version ?? 'unknown').replace(/[\^~]/g, '');
|
|
82
|
+
const ecosystem = pkg.ecosystem ?? 'npm';
|
|
82
83
|
let purl;
|
|
83
84
|
if (cleanedVersion === '1.0.0' || cleanedVersion === 'unknown' || !cleanedVersion) {
|
|
84
|
-
purl = `pkg:${
|
|
85
|
+
purl = `pkg:${ecosystem}/${pkg.depname}`;
|
|
85
86
|
}
|
|
86
87
|
else {
|
|
87
88
|
logger.info(`Using version ${cleanedVersion} for ${pkg.depname}`);
|
|
88
|
-
purl = `pkg:${
|
|
89
|
+
purl = `pkg:${ecosystem}/${pkg.depname}@${cleanedVersion}`;
|
|
89
90
|
}
|
|
90
91
|
return { purl };
|
|
91
92
|
});
|
|
92
93
|
try {
|
|
93
94
|
const response = await fetch(SOCKET_API_URL, {
|
|
94
95
|
method: 'POST',
|
|
95
|
-
headers:
|
|
96
|
+
headers: buildSocketHeaders(),
|
|
96
97
|
body: JSON.stringify({ components })
|
|
97
98
|
});
|
|
98
99
|
const responseText = await response.text();
|
|
@@ -157,6 +158,9 @@ server.tool('depscore', "Get the dependency score of packages with the `depscore
|
|
|
157
158
|
.join(', ');
|
|
158
159
|
results.push(`${purl}: ${scoreEntries}`);
|
|
159
160
|
}
|
|
161
|
+
else {
|
|
162
|
+
results.push(`${purl}: No score found`);
|
|
163
|
+
}
|
|
160
164
|
}
|
|
161
165
|
return {
|
|
162
166
|
content: [
|
|
@@ -204,6 +208,7 @@ if (!SOCKET_API_KEY) {
|
|
|
204
208
|
}
|
|
205
209
|
if (useHttp) {
|
|
206
210
|
logger.info(`Starting HTTP server on port ${port}`);
|
|
211
|
+
let httpTransport = null;
|
|
207
212
|
const httpServer = createServer(async (req, res) => {
|
|
208
213
|
const origin = req.headers.origin;
|
|
209
214
|
const allowedOrigins = [
|
|
@@ -212,8 +217,8 @@ if (useHttp) {
|
|
|
212
217
|
'https://mcp.socket.dev',
|
|
213
218
|
'https://mcp.socket-staging.dev'
|
|
214
219
|
];
|
|
215
|
-
const isValidOrigin =
|
|
216
|
-
if (
|
|
220
|
+
const isValidOrigin = origin && allowedOrigins.includes(origin);
|
|
221
|
+
if (!isValidOrigin) {
|
|
217
222
|
logger.warn(`Rejected request from invalid origin: ${origin}`);
|
|
218
223
|
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
219
224
|
res.end(JSON.stringify({
|
|
@@ -229,9 +234,8 @@ if (useHttp) {
|
|
|
229
234
|
else {
|
|
230
235
|
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
|
|
231
236
|
}
|
|
232
|
-
res.setHeader('Access-Control-Allow-Methods', '
|
|
233
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type,
|
|
234
|
-
res.setHeader('Access-Control-Expose-Headers', 'mcp-session-id');
|
|
237
|
+
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
|
|
238
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Accept');
|
|
235
239
|
if (req.method === 'OPTIONS') {
|
|
236
240
|
res.writeHead(200);
|
|
237
241
|
res.end();
|
|
@@ -263,79 +267,34 @@ if (useHttp) {
|
|
|
263
267
|
}
|
|
264
268
|
if (url.pathname === '/') {
|
|
265
269
|
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
270
|
let body = '';
|
|
278
271
|
req.on('data', chunk => (body += chunk));
|
|
279
272
|
req.on('end', async () => {
|
|
280
273
|
try {
|
|
281
274
|
const jsonData = JSON.parse(body);
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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);
|
|
275
|
+
if (jsonData && jsonData.method === 'initialize') {
|
|
276
|
+
if (httpTransport) {
|
|
277
|
+
try {
|
|
278
|
+
httpTransport.close();
|
|
312
279
|
}
|
|
280
|
+
catch { }
|
|
281
|
+
}
|
|
282
|
+
httpTransport = new StreamableHTTPServerTransport({
|
|
283
|
+
sessionIdGenerator: undefined,
|
|
284
|
+
enableJsonResponse: true
|
|
313
285
|
});
|
|
314
|
-
|
|
315
|
-
|
|
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);
|
|
286
|
+
await server.connect(httpTransport);
|
|
287
|
+
await httpTransport.handleRequest(req, res, jsonData);
|
|
323
288
|
return;
|
|
324
289
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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;
|
|
290
|
+
if (!httpTransport) {
|
|
291
|
+
httpTransport = new StreamableHTTPServerTransport({
|
|
292
|
+
sessionIdGenerator: undefined,
|
|
293
|
+
enableJsonResponse: true
|
|
294
|
+
});
|
|
295
|
+
await server.connect(httpTransport);
|
|
337
296
|
}
|
|
338
|
-
await
|
|
297
|
+
await httpTransport.handleRequest(req, res, jsonData);
|
|
339
298
|
}
|
|
340
299
|
catch (error) {
|
|
341
300
|
logger.error(`Error processing POST request: ${error}`);
|
|
@@ -350,91 +309,6 @@ if (useHttp) {
|
|
|
350
309
|
}
|
|
351
310
|
});
|
|
352
311
|
}
|
|
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
312
|
else {
|
|
439
313
|
res.writeHead(405);
|
|
440
314
|
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
|
-
|
|
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.
|
|
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);
|
|
@@ -9,7 +9,7 @@ async function main() {
|
|
|
9
9
|
command: 'node',
|
|
10
10
|
args: ['--experimental-strip-types', serverPath],
|
|
11
11
|
env: {
|
|
12
|
-
...process.env,
|
|
12
|
+
...Object.fromEntries(Object.entries(process.env).filter(([, value]) => value !== undefined)),
|
|
13
13
|
SOCKET_API_KEY: process.env['SOCKET_API_KEY'] || ''
|
|
14
14
|
}
|
|
15
15
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@socketsecurity/mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"bin": {
|
|
@@ -20,19 +20,22 @@
|
|
|
20
20
|
"build": "npm run clean && run-s build:*",
|
|
21
21
|
"build:types": "tsc -p tsconfig.declaration.json",
|
|
22
22
|
"build:permissions": "chmod +x ./index.js && (chmod +x ./mock-client/*.js 2>/dev/null || true)",
|
|
23
|
-
"build-
|
|
24
|
-
"build-
|
|
25
|
-
"build-
|
|
26
|
-
"build-
|
|
23
|
+
"build-mcpb": "run-s build build-mcpb:*",
|
|
24
|
+
"build-mcpb:versions_match": "node --experimental-strip-types scripts/check-versions.ts",
|
|
25
|
+
"build-mcpb:validate": "npx mcpb validate ./",
|
|
26
|
+
"build-mcpb:ensure-deps": "npm install --production --ignore-scripts",
|
|
27
|
+
"build-mcpb:mcpb-pack": "npx mcpb pack ./",
|
|
27
28
|
"clean": "./scripts/clean.sh",
|
|
28
29
|
"debug-stdio": "node --experimental-strip-types ./mock-client/debug-client.ts",
|
|
29
30
|
"debug-sdk": "node --experimental-strip-types ./mock-client/stdio-client.ts",
|
|
30
31
|
"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} ./
|
|
32
|
+
"server-stdio": "SOCKET_API_KEY=${SOCKET_API_KEY} node --experimental-strip-types ./index.ts",
|
|
33
|
+
"server-http": "MCP_HTTP_MODE=true SOCKET_API_KEY=${SOCKET_API_KEY} node --experimental-strip-types ./index.ts"
|
|
33
34
|
},
|
|
34
35
|
"keywords": [],
|
|
35
36
|
"files": [
|
|
37
|
+
"package.json",
|
|
38
|
+
"package-lock.json",
|
|
36
39
|
"index.js",
|
|
37
40
|
"index.d.ts",
|
|
38
41
|
"index.d.ts.map",
|
|
@@ -46,19 +49,19 @@
|
|
|
46
49
|
"url": "https://github.com/SocketDev/socket-mcp"
|
|
47
50
|
},
|
|
48
51
|
"dependencies": {
|
|
49
|
-
"@
|
|
50
|
-
"
|
|
52
|
+
"@anthropic-ai/mcpb": "^1.1.0",
|
|
53
|
+
"@modelcontextprotocol/sdk": "^1.18.0",
|
|
54
|
+
"pino": "^10.0.0",
|
|
51
55
|
"pino-pretty": "^13.0.0",
|
|
52
56
|
"semver": "^7.7.2",
|
|
53
57
|
"zod": "^3.24.4"
|
|
54
58
|
},
|
|
55
59
|
"devDependencies": {
|
|
56
|
-
"neostandard": "^0.12.0",
|
|
57
|
-
"@anthropic-ai/dxt": "^0.2.0",
|
|
58
60
|
"@types/node": "^24.0.7",
|
|
59
61
|
"@types/semver": "^7.7.0",
|
|
60
62
|
"@types/triple-beam": "^1.3.5",
|
|
61
63
|
"c8": "^10.0.0",
|
|
64
|
+
"neostandard": "^0.12.0",
|
|
62
65
|
"npm-run-all2": "^8.0.1",
|
|
63
66
|
"typescript": "~5.9.2"
|
|
64
67
|
}
|