import http from 'node:http'; import { URL } from 'node:url'; const baseUrl = process.env.MCP_HTTP_URL ?? 'http://127.0.0.1:3940'; const authToken = process.env.MCP_HTTP_TOKEN; function request(path, body, headers = {}) { return new Promise((resolve, reject) => { const url = new URL(path, baseUrl); const postData = body ? JSON.stringify(body) : undefined; const req = http.request( { hostname: url.hostname, port: url.port, path: url.pathname, method: body ? 'POST' : 'GET', headers: { Accept: 'application/json, text/event-stream', 'Content-Type': 'application/json', ...(authToken ? { Authorization: `Bearer ${authToken}` } : {}), ...headers, ...(postData ? { 'Content-Length': Buffer.byteLength(postData) } : {}), }, }, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { const parsedBody = parseSseBody(data); resolve({ status: res.statusCode, headers: res.headers, body: parsedBody }); }); }, ); req.on('error', reject); if (postData) req.write(postData); req.end(); }); } function parseSseBody(raw) { if (!raw.includes('event:')) return raw; const lines = raw.split(/\r?\n/); const dataLines = lines.filter((line) => line.startsWith('data:')).map((line) => line.slice(5).trim()); return dataLines.join(''); } async function main() { const health = await request('/healthz'); console.log('healthz:', health.status, health.body); const init = await request('/mcp', { jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'http-smoke', version: '0.0.1' }, }, }); console.log('initialize:', init.status, init.body); if (init.status !== 200) { throw new Error(`initialize failed: ${init.body}`); } const initResult = JSON.parse(init.body); const sessionId = init.headers['mcp-session-id']; console.log('sessionId:', sessionId); const notif = await request('/mcp', { jsonrpc: '2.0', method: 'notifications/initialized', }, { 'mcp-session-id': sessionId }); console.log('notifications/initialized:', notif.status, notif.body); const resources = await request('/mcp', { jsonrpc: '2.0', id: 2, method: 'resources/list' }, { 'mcp-session-id': sessionId }); console.log('resources/list:', resources.status, resources.body); const prompts = await request('/mcp', { jsonrpc: '2.0', id: 3, method: 'prompts/list' }, { 'mcp-session-id': sessionId }); console.log('prompts/list:', prompts.status, prompts.body); const read = await request( '/mcp', { jsonrpc: '2.0', id: 4, method: 'resources/read', params: { uri: 'workspace://project.json' } }, { 'mcp-session-id': sessionId }, ); console.log('resources/read:', read.status, read.body); const expectedResourceUris = ['workspace://project.json']; const expectedPrompts = ['new-feature', 'new-laravel-resource', 'new-codeigniter-resource', 'new-react-component']; let failed = false; const resourcesResult = JSON.parse(resources.body); const promptsResult = JSON.parse(prompts.body); const readResult = JSON.parse(read.body); const staticUris = resourcesResult?.result?.resources?.map((r) => r.uri) ?? []; for (const uri of expectedResourceUris) { if (!staticUris.includes(uri)) { console.error(`Missing static resource: ${uri}`); failed = true; } } const promptNames = promptsResult?.result?.prompts?.map((p) => p.name) ?? []; for (const name of expectedPrompts) { if (!promptNames.includes(name)) { console.error(`Missing prompt: ${name}`); failed = true; } } if (!readResult?.result?.contents?.[0]?.text) { console.error('resources/read failed', readResult); failed = true; } console.log('Result:', failed ? 'FAILED' : 'OK'); process.exit(failed ? 1 : 0); } main().catch((error) => { console.error(error); process.exit(1); });