Skip to main content
Glama

MCP Specification Server

by MCPJam
23
6
  • Apple
startHTTPServer.test.ts•5.91 kB
import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { EventSource } from "eventsource"; import { getRandomPort } from "get-port-please"; import { setTimeout as delay } from "node:timers/promises"; import { expect, it, vi } from "vitest"; import { proxyServer } from "./proxyServer.js"; import { startHTTPServer } from "./startHTTPServer.js"; if (!("EventSource" in global)) { // @ts-expect-error - figure out how to use --experimental-eventsource with vitest global.EventSource = EventSource; } it("proxies messages between HTTP stream and stdio servers", async () => { const stdioTransport = new StdioClientTransport({ args: ["src/fixtures/simple-stdio-server.ts"], command: "tsx", }); const stdioClient = new Client( { name: "mcp-proxy", version: "1.0.0", }, { capabilities: {}, }, ); await stdioClient.connect(stdioTransport); const serverVersion = stdioClient.getServerVersion() as { name: string; version: string; }; const serverCapabilities = stdioClient.getServerCapabilities() as { capabilities: Record<string, unknown>; }; const port = await getRandomPort(); const onConnect = vi.fn().mockResolvedValue(undefined); const onClose = vi.fn().mockResolvedValue(undefined); await startHTTPServer({ createServer: async () => { const mcpServer = new Server(serverVersion, { capabilities: serverCapabilities, }); await proxyServer({ client: stdioClient, server: mcpServer, serverCapabilities, }); return mcpServer; }, onClose, onConnect, port, }); const streamClient = new Client( { name: "stream-client", version: "1.0.0", }, { capabilities: {}, }, ); const transport = new StreamableHTTPClientTransport( new URL(`http://localhost:${port}/mcp`), ); await streamClient.connect(transport); const result = await streamClient.listResources(); expect(result).toEqual({ resources: [ { name: "Example Resource", uri: "file:///example.txt", }, ], }); expect( await streamClient.readResource({ uri: result.resources[0].uri }, {}), ).toEqual({ contents: [ { mimeType: "text/plain", text: "This is the content of the example resource.", uri: "file:///example.txt", }, ], }); expect(await streamClient.subscribeResource({ uri: "xyz" })).toEqual({}); expect(await streamClient.unsubscribeResource({ uri: "xyz" })).toEqual({}); expect(await streamClient.listResourceTemplates()).toEqual({ resourceTemplates: [ { description: "Specify the filename to retrieve", name: "Example resource template", uriTemplate: `file://{filename}`, }, ], }); expect(onConnect).toHaveBeenCalled(); expect(onClose).not.toHaveBeenCalled(); // the transport no requires the function terminateSession to be called but the client does not implement it // so we need to call it manually await transport.terminateSession(); await streamClient.close(); await delay(1000); expect(onClose).toHaveBeenCalled(); }); it("proxies messages between SSE and stdio servers", async () => { const stdioTransport = new StdioClientTransport({ args: ["src/fixtures/simple-stdio-server.ts"], command: "tsx", }); const stdioClient = new Client( { name: "mcp-proxy", version: "1.0.0", }, { capabilities: {}, }, ); await stdioClient.connect(stdioTransport); const serverVersion = stdioClient.getServerVersion() as { name: string; version: string; }; const serverCapabilities = stdioClient.getServerCapabilities() as { capabilities: Record<string, unknown>; }; const port = await getRandomPort(); const onConnect = vi.fn(); const onClose = vi.fn(); await startHTTPServer({ createServer: async () => { const mcpServer = new Server(serverVersion, { capabilities: serverCapabilities, }); await proxyServer({ client: stdioClient, server: mcpServer, serverCapabilities, }); return mcpServer; }, onClose, onConnect, port, }); const sseClient = new Client( { name: "sse-client", version: "1.0.0", }, { capabilities: {}, }, ); const transport = new SSEClientTransport( new URL(`http://localhost:${port}/sse`), ); await sseClient.connect(transport); const result = await sseClient.listResources(); expect(result).toEqual({ resources: [ { name: "Example Resource", uri: "file:///example.txt", }, ], }); expect( await sseClient.readResource({ uri: result.resources[0].uri }, {}), ).toEqual({ contents: [ { mimeType: "text/plain", text: "This is the content of the example resource.", uri: "file:///example.txt", }, ], }); expect(await sseClient.subscribeResource({ uri: "xyz" })).toEqual({}); expect(await sseClient.unsubscribeResource({ uri: "xyz" })).toEqual({}); expect(await sseClient.listResourceTemplates()).toEqual({ resourceTemplates: [ { description: "Specify the filename to retrieve", name: "Example resource template", uriTemplate: `file://{filename}`, }, ], }); expect(onConnect).toHaveBeenCalled(); expect(onClose).not.toHaveBeenCalled(); await sseClient.close(); await delay(100); expect(onClose).toHaveBeenCalled(); });

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/MCPJam/mcp-spec'

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