@socketsecurity/mcp 0.0.7 → 0.0.9

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/index.js ADDED
@@ -0,0 +1,451 @@
1
+ #!/usr/bin/env node --experimental-strip-types
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
5
+ import { z } from 'zod';
6
+ import { pino } from 'pino';
7
+ import readline from 'readline';
8
+ import { join } from 'path';
9
+ import { readFileSync } from 'fs';
10
+ import { tmpdir } from 'os';
11
+ import { createServer } from 'http';
12
+ import { randomUUID } from 'crypto';
13
+ import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
14
+ const __dirname = import.meta.dirname;
15
+ const packageJson = JSON.parse(readFileSync(join(__dirname, './package.json'), 'utf8'));
16
+ const VERSION = packageJson.version || '0.0.1';
17
+ const logger = pino({
18
+ level: 'info',
19
+ transport: {
20
+ targets: [
21
+ {
22
+ target: 'pino/file',
23
+ options: { destination: join(tmpdir(), 'socket-mcp-error.log') },
24
+ level: 'error'
25
+ },
26
+ {
27
+ target: 'pino/file',
28
+ options: { destination: join(tmpdir(), 'socket-mcp.log') },
29
+ level: 'info'
30
+ }
31
+ ]
32
+ }
33
+ });
34
+ const SOCKET_API_URL = process.env['SOCKET_DEBUG'] === 'true'
35
+ ? 'http://localhost:8866/v0/purl?alerts=false&compact=false&fixable=false&licenseattrib=false&licensedetails=false'
36
+ : 'https://api.socket.dev/v0/purl?alerts=false&compact=false&fixable=false&licenseattrib=false&licensedetails=false';
37
+ async function getApiKeyInteractively() {
38
+ const rl = readline.createInterface({
39
+ input: process.stdin,
40
+ output: process.stderr
41
+ });
42
+ const apiKey = await new Promise((resolve) => {
43
+ rl.question('Please enter your Socket API key: ', (answer) => {
44
+ rl.close();
45
+ resolve(answer);
46
+ });
47
+ });
48
+ if (!apiKey) {
49
+ logger.error('No API key provided');
50
+ process.exit(1);
51
+ }
52
+ return apiKey;
53
+ }
54
+ let SOCKET_API_KEY = process.env['SOCKET_API_KEY'] || '';
55
+ const transports = {};
56
+ const server = new McpServer({
57
+ name: 'socket',
58
+ version: VERSION,
59
+ description: 'Socket MCP server',
60
+ capabilities: {
61
+ resources: {},
62
+ tools: {},
63
+ streaming: {}
64
+ },
65
+ });
66
+ server.tool('depscore', "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).", {
67
+ packages: z.array(z.object({
68
+ ecosystem: z.string().describe('The package ecosystem (e.g., npm, pypi)').default('npm'),
69
+ depname: z.string().describe('The name of the dependency'),
70
+ version: z.string().describe("The version of the dependency, use 'unknown' if not known").default('unknown'),
71
+ })).describe('Array of packages to check'),
72
+ }, async ({ packages }) => {
73
+ 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
+ const components = packages.map(pkg => {
81
+ const cleanedVersion = pkg.version.replace(/[\^~]/g, '');
82
+ let purl;
83
+ if (cleanedVersion === '1.0.0' || cleanedVersion === 'unknown' || !cleanedVersion) {
84
+ purl = `pkg:${pkg.ecosystem}/${pkg.depname}`;
85
+ }
86
+ else {
87
+ logger.info(`Using version ${cleanedVersion} for ${pkg.depname}`);
88
+ purl = `pkg:${pkg.ecosystem}/${pkg.depname}@${cleanedVersion}`;
89
+ }
90
+ return { purl };
91
+ });
92
+ try {
93
+ const response = await fetch(SOCKET_API_URL, {
94
+ method: 'POST',
95
+ headers: SOCKET_HEADERS,
96
+ body: JSON.stringify({ components })
97
+ });
98
+ const responseText = await response.text();
99
+ if (response.status !== 200) {
100
+ const errorMsg = `Error processing packages: [${response.status}] ${responseText}`;
101
+ logger.error(errorMsg);
102
+ return {
103
+ content: [{ type: 'text', text: errorMsg }],
104
+ isError: true
105
+ };
106
+ }
107
+ else if (!responseText.trim()) {
108
+ const errorMsg = 'No packages were found.';
109
+ logger.error(errorMsg);
110
+ return {
111
+ content: [{ type: 'text', text: errorMsg }],
112
+ isError: true
113
+ };
114
+ }
115
+ try {
116
+ const results = [];
117
+ if ((response.headers.get('content-type') || '').includes('x-ndjson')) {
118
+ const jsonLines = responseText.split('\n')
119
+ .filter(line => line.trim())
120
+ .map(line => JSON.parse(line));
121
+ if (!jsonLines.length) {
122
+ const errorMsg = 'No valid JSON objects found in NDJSON response';
123
+ return {
124
+ content: [{ type: 'text', text: errorMsg }],
125
+ isError: true
126
+ };
127
+ }
128
+ for (const jsonData of jsonLines) {
129
+ const purl = `pkg:${jsonData.type || 'unknown'}/${jsonData.name || 'unknown'}@${jsonData.version || 'unknown'}`;
130
+ if (jsonData.score && jsonData.score.overall !== undefined) {
131
+ const scoreEntries = Object.entries(jsonData.score)
132
+ .filter(([key]) => key !== 'overall' && key !== 'uuid')
133
+ .map(([key, value]) => {
134
+ const numValue = Number(value);
135
+ const displayValue = numValue <= 1 ? Math.round(numValue * 100) : numValue;
136
+ return `${key}: ${displayValue}`;
137
+ })
138
+ .join(', ');
139
+ results.push(`${purl}: ${scoreEntries}`);
140
+ }
141
+ else {
142
+ results.push(`${purl}: No score found`);
143
+ }
144
+ }
145
+ }
146
+ else {
147
+ const jsonData = JSON.parse(responseText);
148
+ const purl = `pkg:${jsonData.type || 'unknown'}/${jsonData.name || 'unknown'}@${jsonData.version || 'unknown'}`;
149
+ if (jsonData.score && jsonData.score.overall !== undefined) {
150
+ const scoreEntries = Object.entries(jsonData.score)
151
+ .filter(([key]) => key !== 'overall' && key !== 'uuid')
152
+ .map(([key, value]) => {
153
+ const numValue = Number(value);
154
+ const displayValue = numValue <= 1 ? Math.round(numValue * 100) : numValue;
155
+ return `${key}: ${displayValue}`;
156
+ })
157
+ .join(', ');
158
+ results.push(`${purl}: ${scoreEntries}`);
159
+ }
160
+ }
161
+ return {
162
+ content: [
163
+ {
164
+ type: 'text',
165
+ text: results.length > 0
166
+ ? `Dependency scores:\n${results.join('\n')}`
167
+ : 'No scores found for the provided packages'
168
+ }
169
+ ]
170
+ };
171
+ }
172
+ catch (e) {
173
+ const error = e;
174
+ const errorMsg = `JSON parsing error: ${error.message} -- Response: ${responseText}`;
175
+ logger.error(errorMsg);
176
+ return {
177
+ content: [{ type: 'text', text: 'Error parsing response from Socket API' }],
178
+ isError: true
179
+ };
180
+ }
181
+ }
182
+ catch (e) {
183
+ const error = e;
184
+ const errorMsg = `Error processing packages: ${error.message}`;
185
+ logger.error(errorMsg);
186
+ return {
187
+ content: [{ type: 'text', text: 'Error connecting to Socket API' }],
188
+ isError: true
189
+ };
190
+ }
191
+ });
192
+ const useHttp = process.env['MCP_HTTP_MODE'] === 'true' || process.argv.includes('--http');
193
+ const port = parseInt(process.env['MCP_PORT'] || '3000', 10);
194
+ if (!SOCKET_API_KEY) {
195
+ if (useHttp) {
196
+ logger.error('SOCKET_API_KEY environment variable is not set');
197
+ SOCKET_API_KEY = await getApiKeyInteractively();
198
+ }
199
+ else {
200
+ logger.error('SOCKET_API_KEY environment variable is required in stdio mode');
201
+ logger.error('Please set the SOCKET_API_KEY environment variable and try again');
202
+ process.exit(1);
203
+ }
204
+ }
205
+ if (useHttp) {
206
+ logger.info(`Starting HTTP server on port ${port}`);
207
+ const httpServer = createServer(async (req, res) => {
208
+ const origin = req.headers.origin;
209
+ const allowedOrigins = [
210
+ 'http://localhost:3000',
211
+ 'http://127.0.0.1:3000',
212
+ 'https://mcp.socket.dev',
213
+ 'https://mcp.socket-staging.dev'
214
+ ];
215
+ const isValidOrigin = !origin || allowedOrigins.includes(origin);
216
+ if (origin && !isValidOrigin) {
217
+ logger.warn(`Rejected request from invalid origin: ${origin}`);
218
+ res.writeHead(403, { 'Content-Type': 'application/json' });
219
+ res.end(JSON.stringify({
220
+ jsonrpc: '2.0',
221
+ error: { code: -32000, message: 'Forbidden: Invalid origin' },
222
+ id: null
223
+ }));
224
+ return;
225
+ }
226
+ if (origin && isValidOrigin) {
227
+ res.setHeader('Access-Control-Allow-Origin', origin);
228
+ }
229
+ else {
230
+ res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
231
+ }
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');
235
+ if (req.method === 'OPTIONS') {
236
+ res.writeHead(200);
237
+ res.end();
238
+ return;
239
+ }
240
+ const url = new URL(req.url, `http://localhost:${port}`);
241
+ if (url.pathname === '/health') {
242
+ res.writeHead(200, { 'Content-Type': 'application/json' });
243
+ res.end(JSON.stringify({
244
+ status: 'healthy',
245
+ service: 'socket-mcp',
246
+ version: VERSION,
247
+ timestamp: new Date().toISOString()
248
+ }));
249
+ return;
250
+ }
251
+ if (url.pathname === '/') {
252
+ if (req.method === 'POST') {
253
+ const acceptHeader = req.headers.accept;
254
+ if (!acceptHeader || (!acceptHeader.includes('application/json') && !acceptHeader.includes('text/event-stream'))) {
255
+ logger.warn(`Invalid Accept header: ${acceptHeader}`);
256
+ res.writeHead(400, { 'Content-Type': 'application/json' });
257
+ res.end(JSON.stringify({
258
+ jsonrpc: '2.0',
259
+ error: { code: -32000, message: 'Bad Request: Accept header must include application/json or text/event-stream' },
260
+ id: null
261
+ }));
262
+ return;
263
+ }
264
+ let body = '';
265
+ req.on('data', chunk => (body += chunk));
266
+ req.on('end', async () => {
267
+ try {
268
+ const jsonData = JSON.parse(body);
269
+ const sessionId = req.headers['mcp-session-id'];
270
+ if (sessionId && !/^[\x21-\x7E]+$/.test(sessionId)) {
271
+ logger.warn(`Invalid session ID format: ${sessionId}`);
272
+ res.writeHead(400, { 'Content-Type': 'application/json' });
273
+ res.end(JSON.stringify({
274
+ jsonrpc: '2.0',
275
+ error: { code: -32000, message: 'Bad Request: Session ID must contain only visible ASCII characters' },
276
+ id: jsonData.id || null
277
+ }));
278
+ return;
279
+ }
280
+ let transport;
281
+ if (sessionId && transports[sessionId]) {
282
+ transport = transports[sessionId];
283
+ }
284
+ else if (!sessionId) {
285
+ const newSessionId = randomUUID();
286
+ const isInit = isInitializeRequest(jsonData);
287
+ if (isInit) {
288
+ logger.info(`Creating new session for initialize request: ${newSessionId}`);
289
+ }
290
+ else {
291
+ logger.warn(`Creating fallback session for non-initialize request: ${newSessionId}`);
292
+ }
293
+ transport = new StreamableHTTPServerTransport({
294
+ sessionIdGenerator: () => newSessionId,
295
+ onsessioninitialized: (id) => {
296
+ transports[id] = transport;
297
+ logger.info(`Session initialized: ${id}`);
298
+ res.setHeader('mcp-session-id', id);
299
+ }
300
+ });
301
+ transport.onclose = () => {
302
+ const sid = transport.sessionId;
303
+ if (sid && transports[sid]) {
304
+ delete transports[sid];
305
+ logger.info(`Session closed: ${sid}`);
306
+ }
307
+ };
308
+ await server.connect(transport);
309
+ await transport.handleRequest(req, res, jsonData);
310
+ return;
311
+ }
312
+ else {
313
+ logger.error(`Invalid session ID: ${sessionId}. Active sessions count: ${Object.keys(transports).length}`);
314
+ res.writeHead(400);
315
+ res.end(JSON.stringify({
316
+ jsonrpc: '2.0',
317
+ error: {
318
+ code: -32000,
319
+ message: 'Bad Request: Invalid session ID. Please initialize a new session first.'
320
+ },
321
+ id: jsonData.id || null
322
+ }));
323
+ return;
324
+ }
325
+ await transport.handleRequest(req, res, jsonData);
326
+ }
327
+ catch (error) {
328
+ logger.error(`Error processing POST request: ${error}`);
329
+ if (!res.headersSent) {
330
+ res.writeHead(500);
331
+ res.end(JSON.stringify({
332
+ jsonrpc: '2.0',
333
+ error: { code: -32603, message: 'Internal server error' },
334
+ id: null
335
+ }));
336
+ }
337
+ }
338
+ });
339
+ }
340
+ else if (req.method === 'GET') {
341
+ const acceptHeader = req.headers.accept;
342
+ if (!acceptHeader || !acceptHeader.includes('text/event-stream')) {
343
+ logger.warn(`GET request without text/event-stream Accept header: ${acceptHeader}`);
344
+ res.writeHead(405, { 'Content-Type': 'application/json' });
345
+ res.end(JSON.stringify({
346
+ jsonrpc: '2.0',
347
+ error: { code: -32000, message: 'Method Not Allowed: GET requires Accept: text/event-stream' },
348
+ id: null
349
+ }));
350
+ return;
351
+ }
352
+ const sessionId = req.headers['mcp-session-id'];
353
+ if (sessionId && !/^[\x21-\x7E]+$/.test(sessionId)) {
354
+ logger.warn(`Invalid session ID format in GET request: ${sessionId}`);
355
+ res.writeHead(400, { 'Content-Type': 'application/json' });
356
+ res.end(JSON.stringify({
357
+ jsonrpc: '2.0',
358
+ error: { code: -32000, message: 'Bad Request: Session ID must contain only visible ASCII characters' },
359
+ id: null
360
+ }));
361
+ return;
362
+ }
363
+ if (!sessionId || !transports[sessionId]) {
364
+ logger.warn(`SSE request with invalid session ID: ${sessionId}`);
365
+ res.writeHead(400, { 'Content-Type': 'application/json' });
366
+ res.end(JSON.stringify({
367
+ jsonrpc: '2.0',
368
+ error: { code: -32000, message: 'Bad Request: Invalid or missing session ID for SSE stream' },
369
+ id: null
370
+ }));
371
+ return;
372
+ }
373
+ const lastEventId = req.headers['last-event-id'];
374
+ if (lastEventId) {
375
+ logger.info(`SSE resumability requested with Last-Event-ID: ${lastEventId}`);
376
+ }
377
+ logger.info(`Opening SSE stream for session: ${sessionId}`);
378
+ req.socket?.setTimeout(0);
379
+ req.socket?.setKeepAlive(true, 30000);
380
+ let streamClosed = false;
381
+ req.on('close', () => {
382
+ streamClosed = true;
383
+ logger.info(`Client disconnected SSE stream for session: ${sessionId}`);
384
+ });
385
+ req.on('aborted', () => {
386
+ streamClosed = true;
387
+ logger.info(`Client aborted SSE stream for session: ${sessionId}`);
388
+ });
389
+ const transport = transports[sessionId];
390
+ try {
391
+ await transport.handleRequest(req, res);
392
+ if (!streamClosed && !res.destroyed) {
393
+ logger.info(`Transport completed, maintaining SSE stream for session: ${sessionId}`);
394
+ const heartbeat = setInterval(() => {
395
+ if (streamClosed || res.destroyed) {
396
+ clearInterval(heartbeat);
397
+ return;
398
+ }
399
+ try {
400
+ res.write(': heartbeat\n\n');
401
+ }
402
+ catch (error) {
403
+ logger.error(`Heartbeat error for session ${sessionId}:`, error);
404
+ clearInterval(heartbeat);
405
+ }
406
+ }, 30000);
407
+ req.on('close', () => clearInterval(heartbeat));
408
+ res.on('close', () => clearInterval(heartbeat));
409
+ }
410
+ }
411
+ catch (error) {
412
+ logger.error(`SSE transport error for session ${sessionId}:`, error);
413
+ }
414
+ }
415
+ else if (req.method === 'DELETE') {
416
+ const sessionId = req.headers['mcp-session-id'];
417
+ if (!sessionId || !transports[sessionId]) {
418
+ res.writeHead(400);
419
+ res.end('Invalid or missing session ID');
420
+ return;
421
+ }
422
+ const transport = transports[sessionId];
423
+ await transport.handleRequest(req, res);
424
+ }
425
+ else {
426
+ res.writeHead(405);
427
+ res.end('Method not allowed');
428
+ }
429
+ }
430
+ else {
431
+ res.writeHead(404);
432
+ res.end('Not found');
433
+ }
434
+ });
435
+ httpServer.listen(port, () => {
436
+ logger.info(`Socket MCP HTTP server version ${VERSION} started successfully on port ${port}`);
437
+ logger.info(`Connect to: http://localhost:${port}/`);
438
+ });
439
+ }
440
+ else {
441
+ logger.info('Starting in stdio mode');
442
+ const transport = new StdioServerTransport();
443
+ server.connect(transport)
444
+ .then(() => {
445
+ logger.info(`Socket MCP server version ${VERSION} started successfully`);
446
+ })
447
+ .catch((error) => {
448
+ logger.error(`Failed to start Socket MCP server: ${error.message}`);
449
+ process.exit(1);
450
+ });
451
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node --experimental-strip-types
2
+ export {};
3
+ //# sourceMappingURL=debug-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-client.d.ts","sourceRoot":"","sources":["debug-client.ts"],"names":[],"mappings":""}
@@ -1,7 +1,7 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node --experimental-strip-types
2
2
  import { spawn } from 'child_process';
3
3
  import readline from 'readline';
4
- // Simple JSON-RPC client for testing MCP server
4
+ import { join } from 'path';
5
5
  class SimpleJSONRPCClient {
6
6
  process;
7
7
  rl;
@@ -60,17 +60,18 @@ class SimpleJSONRPCClient {
60
60
  }
61
61
  }
62
62
  async function main() {
63
- const apiKey = process.env.SOCKET_API_KEY;
63
+ const apiKey = process.env['SOCKET_API_KEY'];
64
64
  if (!apiKey) {
65
65
  console.error('Error: SOCKET_API_KEY environment variable is required');
66
66
  process.exit(1);
67
67
  }
68
68
  console.log('Starting MCP server debug client...');
69
- const client = new SimpleJSONRPCClient('./build/index.js', [], {
69
+ const serverPath = join(import.meta.dirname, '..', 'index.ts');
70
+ console.log(`Using server script: ${serverPath}`);
71
+ const client = new SimpleJSONRPCClient('node', ['--experimental-strip-types', serverPath], {
70
72
  SOCKET_API_KEY: apiKey
71
73
  });
72
74
  try {
73
- // Initialize the connection
74
75
  console.log('\n1. Initializing connection...');
75
76
  const initResult = await client.sendRequest('initialize', {
76
77
  protocolVersion: '0.1.0',
@@ -81,11 +82,9 @@ async function main() {
81
82
  }
82
83
  });
83
84
  console.log('Initialize response:', JSON.stringify(initResult, null, 2));
84
- // List available tools
85
85
  console.log('\n2. Listing available tools...');
86
86
  const toolsResult = await client.sendRequest('tools/list', {});
87
87
  console.log('Available tools:', JSON.stringify(toolsResult, null, 2));
88
- // Call the depscore tool
89
88
  console.log('\n3. Calling depscore tool...');
90
89
  const depscoreResult = await client.sendRequest('tools/call', {
91
90
  name: 'depscore',
@@ -100,7 +99,6 @@ async function main() {
100
99
  }
101
100
  });
102
101
  console.log('Depscore result:', JSON.stringify(depscoreResult, null, 2));
103
- // Test with minimal input
104
102
  console.log('\n4. Testing with minimal input (default to npm)...');
105
103
  const minimalResult = await client.sendRequest('tools/call', {
106
104
  name: 'depscore',
@@ -112,7 +110,6 @@ async function main() {
112
110
  }
113
111
  });
114
112
  console.log('Minimal input result:', JSON.stringify(minimalResult, null, 2));
115
- // Test error handling
116
113
  console.log('\n5. Testing error handling (empty packages)...');
117
114
  try {
118
115
  await client.sendRequest('tools/call', {
@@ -135,4 +132,3 @@ async function main() {
135
132
  }
136
133
  }
137
134
  main().catch(console.error);
138
- //# sourceMappingURL=debug-client.js.map
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node --experimental-strip-types
2
+ export {};
3
+ //# sourceMappingURL=http-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["http-client.ts"],"names":[],"mappings":""}
@@ -1,11 +1,9 @@
1
- #!/usr/bin/env node
2
- import fetch from 'node-fetch';
3
- // Helper function to parse SSE or JSON response
1
+ #!/usr/bin/env node --experimental-strip-types
2
+ import { join } from 'path';
4
3
  async function parseResponse(response) {
5
4
  const contentType = response.headers.get('content-type');
6
5
  const text = await response.text();
7
6
  if (contentType?.includes('text/event-stream')) {
8
- // Parse SSE format: "event: message\ndata: {json}\n"
9
7
  const dataMatch = text.match(/data: (.+)/);
10
8
  if (dataMatch) {
11
9
  return JSON.parse(dataMatch[1]);
@@ -16,15 +14,13 @@ async function parseResponse(response) {
16
14
  return JSON.parse(text);
17
15
  }
18
16
  }
19
- // Simple HTTP client for testing MCP server in HTTP mode
20
17
  async function testHTTPMode() {
21
- const baseUrl = (process.env.MCP_URL || 'http://localhost:3000').replace(/\/$/, ''); // Remove trailing slash
18
+ const baseUrl = (process.env['MCP_URL'] || 'http://localhost:3000').replace(/\/$/, '');
22
19
  const sessionId = `test-session-${Date.now()}`;
23
20
  console.log('Testing Socket MCP in HTTP mode...');
24
21
  console.log(`Server URL: ${baseUrl}`);
25
22
  console.log(`Session ID: ${sessionId}`);
26
23
  try {
27
- // 1. Initialize connection
28
24
  console.log('\n1. Initializing connection...');
29
25
  const initRequest = {
30
26
  jsonrpc: '2.0',
@@ -43,18 +39,16 @@ async function testHTTPMode() {
43
39
  method: 'POST',
44
40
  headers: {
45
41
  'Content-Type': 'application/json',
46
- 'Accept': 'application/json, text/event-stream',
42
+ Accept: 'application/json, text/event-stream',
47
43
  'User-Agent': 'socket-mcp-debug-client/1.0.0'
48
44
  },
49
45
  body: JSON.stringify(initRequest)
50
46
  });
51
47
  const initResult = await parseResponse(initResponse);
52
48
  console.log('Initialize response:', JSON.stringify(initResult, null, 2));
53
- // Extract session ID from response headers
54
49
  const serverSessionId = initResponse.headers.get('mcp-session-id');
55
50
  const actualSessionId = serverSessionId || sessionId;
56
51
  console.log('Session ID:', actualSessionId);
57
- // 2. List tools
58
52
  console.log('\n2. Listing available tools...');
59
53
  const toolsRequest = {
60
54
  jsonrpc: '2.0',
@@ -66,14 +60,13 @@ async function testHTTPMode() {
66
60
  method: 'POST',
67
61
  headers: {
68
62
  'Content-Type': 'application/json',
69
- 'Accept': 'application/json, text/event-stream',
63
+ Accept: 'application/json, text/event-stream',
70
64
  'mcp-session-id': actualSessionId
71
65
  },
72
66
  body: JSON.stringify(toolsRequest)
73
67
  });
74
68
  const toolsResult = await parseResponse(toolsResponse);
75
69
  console.log('Available tools:', JSON.stringify(toolsResult, null, 2));
76
- // 3. Call depscore
77
70
  console.log('\n3. Calling depscore tool...');
78
71
  const depscoreRequest = {
79
72
  jsonrpc: '2.0',
@@ -94,27 +87,24 @@ async function testHTTPMode() {
94
87
  method: 'POST',
95
88
  headers: {
96
89
  'Content-Type': 'application/json',
97
- 'Accept': 'application/json, text/event-stream',
90
+ Accept: 'application/json, text/event-stream',
98
91
  'mcp-session-id': actualSessionId
99
92
  },
100
93
  body: JSON.stringify(depscoreRequest)
101
94
  });
102
95
  const depscoreResult = await parseResponse(depscoreResponse);
103
96
  console.log('Depscore result:', JSON.stringify(depscoreResult, null, 2));
104
- // 4. Test SSE stream (optional)
105
97
  console.log('\n4. Testing SSE stream connection...');
106
98
  const sseResponse = await fetch(`${baseUrl}/`, {
107
99
  method: 'GET',
108
100
  headers: {
109
101
  'mcp-session-id': actualSessionId,
110
- 'Accept': 'text/event-stream'
102
+ Accept: 'text/event-stream'
111
103
  }
112
104
  });
113
105
  if (sseResponse.ok) {
114
106
  console.log('SSE stream connected successfully');
115
- // Note: In a real implementation, you'd parse the SSE stream
116
107
  }
117
- // 5. Clean up session
118
108
  console.log('\n5. Cleaning up session...');
119
109
  const cleanupResponse = await fetch(`${baseUrl}/`, {
120
110
  method: 'DELETE',
@@ -128,26 +118,24 @@ async function testHTTPMode() {
128
118
  console.error('Error:', error);
129
119
  }
130
120
  }
131
- // Usage instructions
132
121
  if (process.argv.includes('--help')) {
122
+ const serverScript = join(import.meta.dirname, '..', 'index.ts');
133
123
  console.log(`
134
124
  Socket MCP HTTP Client Debugger
135
125
 
136
126
  Usage:
137
127
  # Start the MCP server in HTTP mode first:
138
- MCP_HTTP_MODE=true SOCKET_API_KEY=your-api-key ./build/index.js
128
+ MCP_HTTP_MODE=true SOCKET_API_KEY=your-api-key node --experimental-strip-types ${serverScript}
139
129
 
140
130
  # Then run this client:
141
- npm run build
142
- node ./build/http-client.js
131
+ node --experimental-strip-types ./mock-client/http-client.ts
143
132
 
144
133
  Environment variables:
145
134
  MCP_URL - Server URL (default: http://localhost:3000)
146
135
 
147
136
  Example:
148
- MCP_URL=http://localhost:8080 node ./build/http-client.js
137
+ MCP_URL=http://localhost:8080 node --experimental-strip-types ./mock-client/http-client.ts
149
138
  `);
150
139
  process.exit(0);
151
140
  }
152
141
  testHTTPMode().catch(console.error);
153
- //# sourceMappingURL=http-client.js.map
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node --experimental-strip-types
2
+ export {};
3
+ //# sourceMappingURL=stdio-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio-client.d.ts","sourceRoot":"","sources":["stdio-client.ts"],"names":[],"mappings":""}