Skip to main content
Glama

PubNub MCP Server

by pubnub
test_tools_consistency.js4.08 kB
#!/usr/bin/env node import assert from 'assert'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; const RESET = '\x1b[0m'; const FG_GREEN = '\x1b[32m'; const FG_RED = '\x1b[31m'; const FG_YELLOW = '\x1b[33m'; const FG_BLUE = '\x1b[34m'; function log(message, color = RESET) { console.log(`${color}${message}${RESET}`); } async function getToolsViaSSE() { const HTTP_PORT = process.env.HTTP_PORT || 3000; const SERVER_URL = `http://localhost:${HTTP_PORT}`; const MCP_ENDPOINT = `${SERVER_URL}/mcp`; try { await fetch(SERVER_URL); } catch (err) { throw new Error( `SSE server is not running at ${SERVER_URL}. Start with: HTTP_PORT=${HTTP_PORT} node index.js` ); } // Initialize a new SSE session log('Initializing SSE session...', FG_BLUE); const initRequest = { jsonrpc: '2.0', method: 'initialize', params: { protocolVersion: '0.1.0', capabilities: { tools: {}, sampling: {} }, clientInfo: { name: 'test-client', version: '1.0.0' } }, id: 1 }; const initRes = await fetch(MCP_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json, text/event-stream' }, body: JSON.stringify(initRequest) }); const sessionId = initRes.headers.get('mcp-session-id'); const initText = await initRes.text(); let initPayload; if (initText.startsWith('event:')) { const dataLine = initText.split('\n').find((l) => l.startsWith('data:')); initPayload = dataLine ? JSON.parse(dataLine.substring(5).trim()) : null; } else { initPayload = JSON.parse(initText); } if (!sessionId || initPayload?.error || !initPayload?.result?.serverInfo) { throw new Error(`Failed to initialize SSE session: ${initText}`); } // Request the tools list over the SSE session log('Fetching tools via SSE mode...', FG_BLUE); const listRequest = { jsonrpc: '2.0', method: 'tools/list', params: {}, id: 2 }; const listRes = await fetch(MCP_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json, text/event-stream', 'mcp-session-id': sessionId }, body: JSON.stringify(listRequest) }); const listText = await listRes.text(); let listPayload; if (listText.startsWith('event:')) { const dataLine = listText.split('\n').find((l) => l.startsWith('data:')); listPayload = dataLine ? JSON.parse(dataLine.substring(5).trim()) : null; } else { listPayload = JSON.parse(listText); } if (!listPayload?.result?.tools || !Array.isArray(listPayload.result.tools)) { throw new Error(`Unexpected SSE tools response: ${listText}`); } // Close the SSE session await fetch(MCP_ENDPOINT, { method: 'DELETE', headers: { 'mcp-session-id': sessionId } }); return listPayload.result.tools; } async function getToolsViaStdio() { log('Fetching tools via STDIO JSONRPC mode...', FG_BLUE); const client = new Client({ name: 'test-client', version: '1.0.0' }); const transport = new StdioClientTransport({ command: 'node', args: ['index.js'] }); await client.connect(transport); const { tools } = await client.listTools(); return tools; } async function main() { try { const [sseTools, stdioTools] = await Promise.all([ getToolsViaSSE(), getToolsViaStdio(), ]); const sortByName = (a, b) => a.name.localeCompare(b.name); const sseSorted = [...sseTools].sort(sortByName); const stdioSorted = [...stdioTools].sort(sortByName); log(`SSE tools count: ${sseSorted.length}`, FG_YELLOW); log(`STDIO tools count: ${stdioSorted.length}`, FG_YELLOW); assert.deepStrictEqual( stdioSorted, sseSorted, 'Mismatch between SSE and STDIO tools lists' ); log('✓ SSE and STDIO JSONRPC tools lists are identical', FG_GREEN); process.exit(0); } catch (err) { log(`❌ ${err.message}`, FG_RED); process.exit(1); } } main();

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pubnub/pubnub-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server