Skip to main content
Glama
capability-negotiation.test.ts3.04 kB
import { negotiateCapabilities, validateClientCapabilities } from '../capability-negotiation'; import { ClientCapabilities, DEFAULT_SERVER_CAPABILITIES } from '../../types/capabilities'; import { StructuredError } from '../../types/errors'; import { capabilityNegotiationTestCases, getMockClientCapabilities } from './fixtures'; describe('Capability Negotiation', () => { describe('negotiateCapabilities', () => { it('should return server defaults when no client capabilities are provided', () => { const negotiated = negotiateCapabilities(); expect(negotiated).toEqual(DEFAULT_SERVER_CAPABILITIES); }); it('should throw an error for incompatible protocol versions', () => { const clientCaps: ClientCapabilities = { protocolVersion: '0.1.0', // Different from server default }; expect(() => negotiateCapabilities(clientCaps)).toThrow(StructuredError); try { negotiateCapabilities(clientCaps); } catch (e) { const error = e as StructuredError; expect(error.code).toBe('INCOMPATIBLE_PROTOCOL_VERSION'); expect(error.data).toEqual({ serverVersion: DEFAULT_SERVER_CAPABILITIES.protocolVersion, clientVersion: clientCaps.protocolVersion, }); expect(error).toMatchSnapshot(); } }); test.each(capabilityNegotiationTestCases)( '$description', ({ clientCaps, expected }) => { const negotiated = negotiateCapabilities(clientCaps); expect(negotiated).toEqual(expected); }, ); it('should use server default when a client capability is not specified', () => { const clientCaps: ClientCapabilities = getMockClientCapabilities({ tools: {}, // Providing the category but not the specific capability }); const negotiated = negotiateCapabilities(clientCaps); // It should fallback to the server's default for 'call' expect(negotiated.tools?.call).toBe(DEFAULT_SERVER_CAPABILITIES.tools?.call); expect(negotiated).toMatchSnapshot(); }); }); describe('validateClientCapabilities', () => { const validCases: [string, object][] = [ ['full capabilities', { tools: { call: true }, logging: { level: 'warn', subscribe: false } }], ['partial capabilities', { tools: { call: true } }], ['empty capabilities', {}], ]; test.each(validCases)('should return true for valid capabilities: %s', (_, caps) => { expect(validateClientCapabilities(caps)).toBe(true); }); const invalidCases: [string, unknown][] = [ ['null', null], ['string', 'string'], ['number', 123], ['unknown category', { unknownCategory: { read: true } }], ['category not an object', { tools: 'not-an-object' }], ['invalid logging level', { logging: { level: 'invalid-level' } }], ]; test.each(invalidCases)('should return false for invalid capabilities: %s', (_, caps) => { expect(validateClientCapabilities(caps)).toBe(false); }); }); });

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/learnwithcc/tally-mcp'

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