Skip to main content
Glama
transport.test.ts5.74 kB
import type { Server as HttpServer } from "node:http"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; describe("Transport Configuration", () => { let originalEnv: NodeJS.ProcessEnv; beforeEach(() => { originalEnv = { ...process.env }; }); afterEach(() => { process.env = originalEnv; }); describe("HTTP Port Validation", () => { it("should accept valid port numbers", () => { const validPorts = ["1", "80", "443", "3000", "8080", "65535"]; validPorts.forEach((port) => { const parsed = parseInt(port, 10); expect(parsed).toBeGreaterThanOrEqual(1); expect(parsed).toBeLessThanOrEqual(65535); expect(Number.isNaN(parsed)).toBe(false); }); }); it("should reject invalid port numbers", () => { const invalidCases = [ { port: "0", reason: "port 0 is reserved" }, { port: "-1", reason: "negative ports are invalid" }, { port: "65536", reason: "exceeds maximum port" }, { port: "99999", reason: "exceeds maximum port" }, { port: "abc", reason: "non-numeric input" }, { port: "", reason: "empty string" }, ]; invalidCases.forEach(({ port, reason }) => { const parsed = parseInt(port, 10); const isValid = !Number.isNaN(parsed) && parsed >= 1 && parsed <= 65535; expect(isValid, `Failed for ${port}: ${reason}`).toBe(false); }); }); it("should use default port 3000 when HTTP_PORT is not set", () => { const port = parseInt(process.env.HTTP_PORT || "3000", 10); expect(port).toBe(3000); }); it("should parse HTTP_PORT from environment", () => { process.env.HTTP_PORT = "8080"; const port = parseInt(process.env.HTTP_PORT || "3000", 10); expect(port).toBe(8080); }); }); describe("Transport Mode Validation", () => { it("should accept valid transport modes", () => { const validModes = ["stdio", "http", "STDIO", "HTTP"]; validModes.forEach((mode) => { const normalized = mode.toLowerCase(); expect(["stdio", "http"]).toContain(normalized); }); }); it("should reject invalid transport modes", () => { const invalidModes = ["tcp", "websocket", "grpc", ""]; invalidModes.forEach((mode) => { const normalized = mode.toLowerCase(); expect(["stdio", "http"]).not.toContain(normalized); }); }); it("should default to stdio when TRANSPORT_MODE is not set", () => { const mode = (process.env.TRANSPORT_MODE || "stdio").toLowerCase(); expect(mode).toBe("stdio"); }); }); describe("Request Size Limits", () => { it("should define request size limit for HTTP transport", () => { const limit = "10mb"; expect(limit).toMatch(/^\d+mb$/); }); it("should parse size limit correctly", () => { const limit = "10mb"; const sizeInBytes = parseInt(limit, 10) * 1024 * 1024; expect(sizeInBytes).toBe(10485760); }); }); }); describe("HTTP Server Configuration", () => { describe("Graceful Shutdown", () => { it("should handle shutdown signals", async () => { const mockServer = { close: vi.fn((callback) => { if (callback) callback(); }), } as unknown as HttpServer; const shutdown = () => { mockServer.close(() => { // Shutdown callback }); }; shutdown(); expect(mockServer.close).toHaveBeenCalled(); }); it("should support timeout for forced shutdown", () => { vi.useFakeTimers(); let forcedShutdown = false; const timeout = setTimeout(() => { forcedShutdown = true; }, 10000); vi.advanceTimersByTime(9999); expect(forcedShutdown).toBe(false); vi.advanceTimersByTime(1); expect(forcedShutdown).toBe(true); clearTimeout(timeout); vi.useRealTimers(); }); }); describe("Error Handling", () => { it("should return JSON-RPC 2.0 error format", () => { const error = { jsonrpc: "2.0", error: { code: -32603, message: "Internal server error", }, id: null, }; expect(error.jsonrpc).toBe("2.0"); expect(error.error.code).toBe(-32603); expect(error.error.message).toBeTruthy(); expect(error.id).toBeNull(); }); it("should use standard JSON-RPC error codes", () => { const errorCodes = { parseError: -32700, invalidRequest: -32600, methodNotFound: -32601, invalidParams: -32602, internalError: -32603, }; expect(errorCodes.parseError).toBe(-32700); expect(errorCodes.invalidRequest).toBe(-32600); expect(errorCodes.methodNotFound).toBe(-32601); expect(errorCodes.invalidParams).toBe(-32602); expect(errorCodes.internalError).toBe(-32603); }); }); }); describe("Transport Lifecycle", () => { it("should close transport on response close", () => { const mockTransport = { close: vi.fn(), }; const mockResponse = { on: vi.fn((event, callback) => { if (event === "close") { callback(); } }), }; mockResponse.on("close", () => { mockTransport.close(); }); expect(mockTransport.close).toHaveBeenCalled(); }); it("should handle transport connection", async () => { const mockServer = { connect: vi.fn().mockResolvedValue(undefined), }; const mockTransport = { handleRequest: vi.fn().mockResolvedValue(undefined), close: vi.fn(), }; await mockServer.connect(mockTransport); expect(mockServer.connect).toHaveBeenCalledWith(mockTransport); }); });

Latest Blog Posts

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/mhalder/qdrant-mcp-server'

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