Skip to main content
Glama
validator.test.ts8.12 kB
import { describe, expect, test } from "vitest"; import type { StdioTransportConfig, StreamableHttpTransportConfig, } from "../../../src/transport/config.js"; import { TransportConfigValidator } from "../../../src/transport/validator.js"; describe("TransportConfigValidator", () => { describe("stdio transport validation", () => { test("should validate valid stdio config", () => { const config: StdioTransportConfig = { type: "stdio", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(true); if (result.success) { expect(result.data.type).toBe("stdio"); } }); test("should reject stdio config with extra properties", () => { const config = { port: 6280, // Invalid for stdio type: "stdio", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(false); if (!result.success) { expect(result.error.message).toContain("validation failed"); } }); }); describe("streamable-http transport validation", () => { test("should validate valid minimal HTTP config", () => { const config: StreamableHttpTransportConfig = { endpoint: "/mcp", host: "127.0.0.1", port: 6280, type: "streamable-http", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(true); if (result.success) { expect(result.data.type).toBe("streamable-http"); expect(result.data.port).toBe(6280); expect(result.data.host).toBe("127.0.0.1"); expect(result.data.endpoint).toBe("/mcp"); } }); test("should validate HTTP config with session config", () => { const config: StreamableHttpTransportConfig = { endpoint: "/mcp", host: "localhost", port: 6280, sessionConfig: { cleanupInterval: 300000, enabled: true, ttl: 3600000, }, type: "streamable-http", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(true); if (result.success) { expect(result.data.sessionConfig?.enabled).toBe(true); expect(result.data.sessionConfig?.ttl).toBe(3600000); } }); test("should validate HTTP config without security config", () => { // SecurityConfig removed - DNS rebinding protection now handled by SDK middleware const config: StreamableHttpTransportConfig = { endpoint: "/api/mcp", host: "0.0.0.0", port: 6280, type: "streamable-http", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(true); if (result.success && result.data.type === "streamable-http") { expect(result.data.port).toBe(6280); expect(result.data.endpoint).toBe("/api/mcp"); } }); test("should reject HTTP config with invalid port (too low)", () => { const config = { endpoint: "/mcp", host: "127.0.0.1", port: 0, type: "streamable-http", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(false); if (!result.success) { expect(result.error.message).toContain("validation failed"); expect(result.error.message).toContain("port"); } }); test("should reject HTTP config with invalid port (too high)", () => { const config = { endpoint: "/mcp", host: "127.0.0.1", port: 70000, type: "streamable-http", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(false); if (!result.success) { expect(result.error.message).toContain("validation failed"); expect(result.error.message).toContain("65535"); } }); test("should reject HTTP config with empty host", () => { const config = { endpoint: "/mcp", host: "", port: 6280, type: "streamable-http", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(false); if (!result.success) { expect(result.error.message).toContain("validation failed"); expect(result.error.message).toContain("Host"); } }); test("should reject HTTP config with endpoint not starting with /", () => { const config = { endpoint: "mcp", host: "127.0.0.1", port: 6280, type: "streamable-http", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(false); if (!result.success) { expect(result.error.message).toContain("validation failed"); expect(result.error.message).toContain("Endpoint"); } }); test("should reject HTTP config with negative TTL", () => { const config = { endpoint: "/mcp", host: "127.0.0.1", port: 6280, sessionConfig: { enabled: true, ttl: -1000, }, type: "streamable-http", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(false); if (!result.success) { expect(result.error.message).toContain("validation failed"); } }); test("should reject HTTP config with negative cleanup interval", () => { const config = { endpoint: "/mcp", host: "127.0.0.1", port: 6280, sessionConfig: { cleanupInterval: -5000, enabled: true, }, type: "streamable-http", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(false); if (!result.success) { expect(result.error.message).toContain("validation failed"); } }); }); describe("discriminated union validation", () => { test("should reject config with unknown transport type", () => { const config = { port: 6280, type: "unknown-transport", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(false); if (!result.success) { expect(result.error.message).toContain("validation failed"); } }); test("should reject config with missing type field", () => { const config = { host: "127.0.0.1", port: 6280, }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(false); if (!result.success) { expect(result.error.message).toContain("validation failed"); } }); test("should reject null config", () => { const result = TransportConfigValidator.validate(null); expect(result.success).toBe(false); if (!result.success) { expect(result.error.message).toContain("validation failed"); } }); test("should reject undefined config", () => { const result = TransportConfigValidator.validate(undefined); expect(result.success).toBe(false); if (!result.success) { expect(result.error.message).toContain("validation failed"); } }); }); describe("validateAndMergeDefaults", () => { test("should validate stdio config without merging", () => { const config: StdioTransportConfig = { type: "stdio", }; const result = TransportConfigValidator.validateAndMergeDefaults(config); expect(result.success).toBe(true); if (result.success) { expect(result.data.type).toBe("stdio"); } }); test("should validate HTTP config and preserve all values", () => { const config: StreamableHttpTransportConfig = { endpoint: "/mcp", host: "127.0.0.1", port: 6280, sessionConfig: { enabled: false, }, type: "streamable-http", }; const result = TransportConfigValidator.validateAndMergeDefaults(config); expect(result.success).toBe(true); if (result.success) { expect(result.data.sessionConfig?.enabled).toBe(false); } }); }); describe("error message formatting", () => { test("should provide clear error message for multiple validation errors", () => { const config = { endpoint: "invalid", host: "", port: -1, type: "streamable-http", }; const result = TransportConfigValidator.validate(config); expect(result.success).toBe(false); if (!result.success) { const message = result.error.message; expect(message).toContain("validation failed"); expect(message).toContain("port"); expect(message).toContain("host"); expect(message).toContain("endpoint"); } }); }); });

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/8beeeaaat/touchdesigner-mcp'

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