🚨 Active Supply Chain Attack:node-ipc Package Compromised.Learn More
Socket
Book a DemoSign in
Socket

@socketsecurity/mcp

Package Overview
Dependencies
Maintainers
2
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@socketsecurity/mcp - npm Package Compare versions

Comparing version
0.0.11
to
0.0.12
+21
-154
index.js

@@ -12,4 +12,2 @@ #!/usr/bin/env -S node --experimental-strip-types

import { createServer } from 'http';
import { randomUUID } from 'crypto';
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
const __dirname = import.meta.dirname;

@@ -56,3 +54,2 @@ const packageJson = JSON.parse(readFileSync(join(__dirname, './package.json'), 'utf8'));

let SOCKET_API_KEY = process.env['SOCKET_API_KEY'] || '';
const transports = {};
const server = new McpServer({

@@ -209,2 +206,3 @@ name: 'socket',

logger.info(`Starting HTTP server on port ${port}`);
let httpTransport = null;
const httpServer = createServer(async (req, res) => {

@@ -235,5 +233,4 @@ const origin = req.headers.origin;

}
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, mcp-session-id, Accept, Last-Event-ID');
res.setHeader('Access-Control-Expose-Headers', 'mcp-session-id');
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Accept');
if (req.method === 'OPTIONS') {

@@ -270,13 +267,2 @@ res.writeHead(200);

if (req.method === 'POST') {
const acceptHeader = req.headers.accept;
if (!acceptHeader || (!acceptHeader.includes('application/json') && !acceptHeader.includes('text/event-stream'))) {
logger.warn(`Invalid Accept header: ${acceptHeader}`);
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
jsonrpc: '2.0',
error: { code: -32000, message: 'Bad Request: Accept header must include application/json or text/event-stream' },
id: null
}));
return;
}
let body = '';

@@ -287,59 +273,25 @@ req.on('data', chunk => (body += chunk));

const jsonData = JSON.parse(body);
const sessionId = req.headers['mcp-session-id'];
if (sessionId && !/^[\x21-\x7E]+$/.test(sessionId)) {
logger.warn(`Invalid session ID format: ${sessionId}`);
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
jsonrpc: '2.0',
error: { code: -32000, message: 'Bad Request: Session ID must contain only visible ASCII characters' },
id: jsonData.id || null
}));
return;
}
let transport;
if (sessionId && transports[sessionId]) {
transport = transports[sessionId];
}
else if (!sessionId) {
const newSessionId = randomUUID();
const isInit = isInitializeRequest(jsonData);
if (isInit) {
logger.info(`Creating new session for initialize request: ${newSessionId}`);
if (jsonData && jsonData.method === 'initialize') {
if (httpTransport) {
try {
httpTransport.close();
}
catch { }
}
else {
logger.warn(`Creating fallback session for non-initialize request: ${newSessionId}`);
}
transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => newSessionId,
onsessioninitialized: (id) => {
transports[id] = transport;
logger.info(`Session initialized: ${id}`);
res.setHeader('mcp-session-id', id);
}
httpTransport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
enableJsonResponse: true
});
transport.onclose = () => {
const sid = transport.sessionId;
if (sid && transports[sid]) {
delete transports[sid];
logger.info(`Session closed: ${sid}`);
}
};
await server.connect(transport);
await transport.handleRequest(req, res, jsonData);
await server.connect(httpTransport);
await httpTransport.handleRequest(req, res, jsonData);
return;
}
else {
logger.error(`Invalid session ID: ${sessionId}. Active sessions count: ${Object.keys(transports).length}`);
res.writeHead(400);
res.end(JSON.stringify({
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Bad Request: Invalid session ID. Please initialize a new session first.'
},
id: jsonData.id || null
}));
return;
if (!httpTransport) {
httpTransport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
enableJsonResponse: true
});
await server.connect(httpTransport);
}
await transport.handleRequest(req, res, jsonData);
await httpTransport.handleRequest(req, res, jsonData);
}

@@ -359,87 +311,2 @@ catch (error) {

}
else if (req.method === 'GET') {
const acceptHeader = req.headers.accept;
if (!acceptHeader || !acceptHeader.includes('text/event-stream')) {
logger.warn(`GET request without text/event-stream Accept header: ${acceptHeader}`);
res.writeHead(405, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
jsonrpc: '2.0',
error: { code: -32000, message: 'Method Not Allowed: GET requires Accept: text/event-stream' },
id: null
}));
return;
}
const sessionId = req.headers['mcp-session-id'];
if (sessionId && !/^[\x21-\x7E]+$/.test(sessionId)) {
logger.warn(`Invalid session ID format in GET request: ${sessionId}`);
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
jsonrpc: '2.0',
error: { code: -32000, message: 'Bad Request: Session ID must contain only visible ASCII characters' },
id: null
}));
return;
}
if (!sessionId || !transports[sessionId]) {
logger.warn(`SSE request with invalid session ID: ${sessionId}`);
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
jsonrpc: '2.0',
error: { code: -32000, message: 'Bad Request: Invalid or missing session ID for SSE stream' },
id: null
}));
return;
}
const lastEventId = req.headers['last-event-id'];
if (lastEventId) {
logger.info(`SSE resumability requested with Last-Event-ID: ${lastEventId}`);
}
logger.info(`Opening SSE stream for session: ${sessionId}`);
req.socket?.setTimeout(0);
req.socket?.setKeepAlive(true, 30000);
let streamClosed = false;
req.on('close', () => {
streamClosed = true;
logger.info(`Client disconnected SSE stream for session: ${sessionId}`);
});
req.on('aborted', () => {
streamClosed = true;
logger.info(`Client aborted SSE stream for session: ${sessionId}`);
});
const transport = transports[sessionId];
try {
await transport.handleRequest(req, res);
if (!streamClosed && !res.destroyed) {
logger.info(`Transport completed, maintaining SSE stream for session: ${sessionId}`);
const heartbeat = setInterval(() => {
if (streamClosed || res.destroyed) {
clearInterval(heartbeat);
return;
}
try {
res.write(': heartbeat\n\n');
}
catch (error) {
logger.error(error, `Heartbeat error for session ${sessionId}:`);
clearInterval(heartbeat);
}
}, 30000);
req.on('close', () => clearInterval(heartbeat));
res.on('close', () => clearInterval(heartbeat));
}
}
catch (error) {
logger.error(error, `SSE transport error for session ${sessionId}:`);
}
}
else if (req.method === 'DELETE') {
const sessionId = req.headers['mcp-session-id'];
if (!sessionId || !transports[sessionId]) {
res.writeHead(400);
res.end('Invalid or missing session ID');
return;
}
const transport = transports[sessionId];
await transport.handleRequest(req, res);
}
else {

@@ -446,0 +313,0 @@ res.writeHead(405);

+10
-28

@@ -19,6 +19,4 @@ #!/usr/bin/env node --experimental-strip-types

const baseUrl = (process.env['MCP_URL'] || 'http://localhost:3000').replace(/\/$/, '');
const sessionId = `test-session-${Date.now()}`;
console.log('Testing Socket MCP in HTTP mode...');
console.log(`Server URL: ${baseUrl}`);
console.log(`Session ID: ${sessionId}`);
try {

@@ -50,5 +48,3 @@ console.log('\n1. Initializing connection...');

console.log('Initialize response:', JSON.stringify(initResult, null, 2));
const serverSessionId = initResponse.headers.get('mcp-session-id');
const actualSessionId = serverSessionId || sessionId;
console.log('Session ID:', actualSessionId);
console.log('Initialized (stateless)');
console.log('\n2. Listing available tools...');

@@ -65,4 +61,3 @@ const toolsRequest = {

'Content-Type': 'application/json',
Accept: 'application/json, text/event-stream',
'mcp-session-id': actualSessionId
Accept: 'application/json, text/event-stream'
},

@@ -73,2 +68,8 @@ body: JSON.stringify(toolsRequest)

console.log('Available tools:', JSON.stringify(toolsResult, null, 2));
if (!toolsResult ||
!toolsResult.result ||
!Array.isArray(toolsResult.result.tools) ||
!toolsResult.result.tools.some((tool) => tool.name === 'depscore')) {
throw new Error('depscore tool not found in available tools');
}
console.log('\n3. Calling depscore tool...');

@@ -94,4 +95,3 @@ const depscoreRequest = {

'Content-Type': 'application/json',
Accept: 'application/json, text/event-stream',
'mcp-session-id': actualSessionId
Accept: 'application/json, text/event-stream'
},

@@ -102,21 +102,3 @@ body: JSON.stringify(depscoreRequest)

console.log('Depscore result:', JSON.stringify(depscoreResult, null, 2));
console.log('\n4. Testing SSE stream connection...');
const sseResponse = await fetch(`${baseUrl}/`, {
method: 'GET',
headers: {
'mcp-session-id': actualSessionId,
Accept: 'text/event-stream'
}
});
if (sseResponse.ok) {
console.log('SSE stream connected successfully');
}
console.log('\n5. Cleaning up session...');
const cleanupResponse = await fetch(`${baseUrl}/`, {
method: 'DELETE',
headers: {
'mcp-session-id': actualSessionId
}
});
console.log('Session cleanup:', cleanupResponse.status === 200 ? 'Success' : 'Failed');
console.log('\n4. HTTP mode test complete (no sessions)');
}

@@ -123,0 +105,0 @@ catch (error) {

{
"name": "@socketsecurity/mcp",
"version": "0.0.11",
"version": "0.0.12",
"type": "module",

@@ -31,4 +31,4 @@ "main": "./index.js",

"debug-http": "node --experimental-strip-types ./mock-client/http-client.ts",
"server-stdio": "SOCKET_API_KEY=${SOCKET_API_KEY} --experimental-strip-types ./index.ts",
"server-http": "MCP_HTTP_MODE=true SOCKET_API_KEY=${SOCKET_API_KEY} ./build/index.js"
"server-stdio": "SOCKET_API_KEY=${SOCKET_API_KEY} node --experimental-strip-types ./index.ts",
"server-http": "MCP_HTTP_MODE=true SOCKET_API_KEY=${SOCKET_API_KEY} node --experimental-strip-types ./index.ts"
},

@@ -50,3 +50,3 @@ "keywords": [],

"dependencies": {
"@modelcontextprotocol/sdk": "^1.11.3",
"@modelcontextprotocol/sdk": "^1.18.0",
"pino": "^9.7.0",

@@ -58,3 +58,2 @@ "pino-pretty": "^13.0.0",

"devDependencies": {
"neostandard": "^0.12.0",
"@anthropic-ai/dxt": "^0.2.0",

@@ -65,2 +64,3 @@ "@types/node": "^24.0.7",

"c8": "^10.0.0",
"neostandard": "^0.12.0",
"npm-run-all2": "^8.0.1",

@@ -67,0 +67,0 @@ "typescript": "~5.9.2"

@@ -28,3 +28,3 @@ # Socket MCP Server

[![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"})
[![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=socket-mcp&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vbWNwLnNvY2tldC5kZXYifQ%3D%3D)
[![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=socket-mcp&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vbWNwLnNvY2tldC5kZXYvIn0%3D)

@@ -153,3 +153,3 @@

[![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"})
[![Install in Cursor (stdio)](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=socket-mcp-stdio&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyJAc29ja2V0c2VjdXJpdHkvbWNwQGxhdGVzdCJdLCJlbnYiOnsiU09DS0VUX0FQSV9LRVkiOiJ5b3VyLWFwaS1rZXktaGVyZSJ9fQ==)
[![Install in Cursor (stdio)](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=socket-mcp&config=eyJjb21tYW5kIjoibnB4IEBzb2NrZXRzZWN1cml0eS9tY3BAbGF0ZXN0IiwiZW52Ijp7IlNPQ0tFVF9BUElfS0VZIjoieW91ci1hcGkta2V5LWhlcmUifX0%3D)

@@ -379,1 +379,10 @@ Claude Code (stdio mode) can be set up with the following command:

- 💬 [Community Support](https://github.com/SocketDev/socket-mcp/discussions)
<br/>
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="logo-white.png">
<source media="(prefers-color-scheme: light)" srcset="logo-black.png">
<img width="324" height="108" alt="Socket Logo" src="logo-black.png">
</picture>
</div>