Skip to main content
Glama

Twilio MCP Server (Docker Edition with Auth Token Support)

by Twine2546
server.spec.ts•13.8 kB
// @ts-nocheck /* eslint-disable max-classes-per-file, class-methods-use-this */ import { Tool } from '@modelcontextprotocol/sdk/types.js'; import { beforeEach, describe, expect, it, Mock, vi } from 'vitest'; import { loadTools, readSpecs } from '@app/utils'; import { API } from '@app/types'; import OpenAPIMCPServer from '../src/server'; vi.mock('@modelcontextprotocol/sdk/server/index.js', () => { return { Server: vi.fn().mockImplementation(() => { return { connect: vi.fn().mockResolvedValue(undefined), setRequestHandler: vi.fn(), }; }), }; }); vi.mock('@app/utils', async () => { const actual = await vi.importActual('@app/utils'); return { ...actual, readSpecs: vi.fn(), loadTools: vi.fn(), logger: { child: () => ({ debug: vi.fn(), error: vi.fn(), }), }, Http: vi.fn().mockImplementation(() => ({ get: vi.fn(), post: vi.fn(), delete: vi.fn(), })), }; }); describe('OpenAPIMCPServer', () => { let mockConfig: any; let mockTool: Tool; let mockToolId: string; let server: OpenAPIMCPServer; beforeEach(() => { vi.clearAllMocks(); mockConfig = { server: { name: 'test-server', version: '1.0.0', capabilities: { tools: {}, }, }, openAPIDir: '/mock/path', }; mockToolId = 'mockService--mockOperationId'; mockTool = { id: mockToolId, name: mockToolId, description: 'Mock tool description', inputSchema: { type: 'object', properties: { param1: { type: 'string' }, }, }, }; const mockApi = { path: '/api/resource', method: 'GET', contentType: 'application/json', }; (readSpecs as Mock).mockResolvedValue([]); (loadTools as Mock).mockReturnValue({ tools: new Map([[mockToolId, mockTool]]), apis: new Map([[mockToolId, mockApi]]), }); server = new OpenAPIMCPServer(mockConfig); }); it('should load tools when started', async () => { class TestServer extends OpenAPIMCPServer { async start() { await this.load(); } get toolsMap() { return this.tools; } get apisMap() { return this.apis; } } const testServer = new TestServer(mockConfig); await testServer.start(); expect(readSpecs).toHaveBeenCalledWith( mockConfig.openAPIDir, mockConfig.openAPIDir, [], ); expect(loadTools).toHaveBeenCalled(); expect(testServer.toolsMap.size).toBe(1); expect(testServer.apisMap.size).toBe(1); expect(testServer.toolsMap.get(mockToolId)).toBe(mockTool); }); it('should initialize with the correct configuration', () => { expect(server.configuration).toBe(mockConfig); expect(server.capabilities).toHaveProperty('tools'); }); it('should check capabilities correctly', () => { const capabilitiesServer = new OpenAPIMCPServer({ ...mockConfig, server: { ...mockConfig.server, capabilities: { tools: {}, resources: {}, }, }, }); expect(capabilitiesServer.hasCapability('tools')).toBe(true); expect(capabilitiesServer.hasCapability('resources')).toBe(true); expect(capabilitiesServer.hasCapability('prompts')).toBe(false); expect(() => { capabilitiesServer.ensureCapability('resources'); }).not.toThrow(); expect(() => { capabilitiesServer.ensureCapability('prompts'); }).toThrow('prompts not supported'); }); it('should make GET requests via the http util', async () => { class TestServer extends OpenAPIMCPServer { async start() { await this.load(); } public testMakeRequest(id: string, api: any) { return this.makeRequest(id, api); } } const testServer = new TestServer(mockConfig); await testServer.start(); const mockResponseData = { result: 'success' }; const mockHttpResponse = { ok: true, data: mockResponseData, statusCode: 200, }; testServer.http.get = vi.fn().mockResolvedValue(mockHttpResponse); const result = await testServer.testMakeRequest('test-id', { path: '/api/test', method: 'GET', contentType: 'application/json', }); expect(testServer.http.get).toHaveBeenCalledWith('/api/test', { headers: { 'Content-Type': 'application/json' }, }); expect(result).toBe(mockHttpResponse); }); it('should make POST requests via the http util', async () => { class TestServer extends OpenAPIMCPServer { public testMakeRequest(id: string, api: API, body?: any) { return this.makeRequest(id, api, body); } } const testServer = new TestServer(mockConfig); const mockResponseData = { result: 'created' }; const mockHttpResponse = { ok: true, data: mockResponseData, statusCode: 201, }; const mockBody = { name: 'test' }; testServer.http.post = vi.fn().mockResolvedValue(mockHttpResponse); const result = await testServer.testMakeRequest( 'test-id', { path: '/api/test', method: 'POST', contentType: 'application/json' }, mockBody, ); expect(testServer.http.post).toHaveBeenCalledWith('/api/test', mockBody, { headers: { 'Content-Type': 'application/json' }, }); expect(result).toBe(mockHttpResponse); }); it('should make DELETE requests via the http util', async () => { class TestServer extends OpenAPIMCPServer { public testMakeRequest(id: string, api: API, body?: any) { return this.makeRequest(id, api, body); } } const testServer = new TestServer(mockConfig); const mockResponseData = { result: 'deleted' }; const mockHttpResponse = { ok: true, data: mockResponseData, statusCode: 200, }; testServer.http.delete = vi.fn().mockResolvedValue(mockHttpResponse); const result = await testServer.testMakeRequest('test-id', { path: '/api/test', method: 'DELETE', contentType: 'application/json', }); expect(testServer.http.delete).toHaveBeenCalledWith('/api/test', { headers: { 'Content-Type': 'application/json' }, }); expect(result).toBe(mockHttpResponse); }); it('should throw an error for unsupported HTTP methods', async () => { class TestServer extends OpenAPIMCPServer { public testMakeRequest(id: string, api: API, body?: any) { return this.makeRequest(id, api, body); } } const testServer = new TestServer(mockConfig); await expect( testServer.testMakeRequest('test-id', { path: '/api/test', method: 'PATCH' as any, contentType: 'application/json', }), ).rejects.toThrow('Unsupported method: PATCH'); }); it('should prepare the body for API calls via callToolBody hook', async () => { class CustomServer extends OpenAPIMCPServer { protected callToolBody( tool: Tool, api: API, body: Record<string, unknown>, ) { return { ...body, extra: 'value' }; } public testCallToolBody( tool: Tool, api: any, body: Record<string, unknown>, ) { return this.callToolBody(tool, api, body); } } const customServer = new CustomServer(mockConfig); const result = customServer.testCallToolBody( mockTool, { path: '/api/test', method: 'POST', contentType: 'application/json' }, { original: 'data' }, ); expect(result).toEqual({ original: 'data', extra: 'value' }); }); it('should prepare the response for API calls via callToolResponse hook', async () => { class CustomServer extends OpenAPIMCPServer { protected callToolResponse(httpResponse: any, response: any) { return { ...response, content: [{ type: 'text', text: 'Modified response' }], }; } public testCallToolResponse(httpResponse: any, response: any) { return this.callToolResponse(httpResponse, response); } } const customServer = new CustomServer(mockConfig); const result = customServer.testCallToolResponse( { ok: true, data: { result: 'success' }, statusCode: 200 }, { content: [{ type: 'text', text: 'Original' }] }, ); expect(result).toEqual({ content: [{ type: 'text', text: 'Modified response' }], }); }); it('should throw errors for unsupported resource capability', async () => { class TestServer extends OpenAPIMCPServer { public testHandleReadResource(request: any) { return this.handleReadResource(request); } } const noResourceServer = new TestServer({ ...mockConfig, server: { ...mockConfig.server, capabilities: { tools: {} }, }, }); await expect( noResourceServer.testHandleReadResource({ id: 'test' }), ).rejects.toThrow('resources not supported'); }); it('should throw errors for unsupported prompt capability', async () => { class TestServer extends OpenAPIMCPServer { public testHandleGetPrompt(request: any) { return this.handleGetPrompt(request); } } const noPromptServer = new TestServer({ ...mockConfig, server: { ...mockConfig.server, capabilities: { tools: {} }, }, }); await expect( noPromptServer.testHandleGetPrompt({ id: 'test' }), ).rejects.toThrow('prompts not supported'); }); it('should call loadCapabilities hook during startup', async () => { class CustomCapabilitiesServer extends OpenAPIMCPServer { public capabilitiesLoaded = false; protected async loadCapabilities() { this.capabilitiesLoaded = true; this.prompts.set('test-prompt', { id: 'test-prompt', name: 'Test Prompt', content: 'Test content', }); } public async testLoad() { await this.load(); } } const customServer = new CustomCapabilitiesServer(mockConfig); await customServer.testLoad(); expect(customServer.capabilitiesLoaded).toBe(true); expect(customServer.prompts.size).toBe(1); expect(customServer.prompts.get('test-prompt')).toBeDefined(); }); it('should handle tool calls correctly', async () => { class TestServer extends OpenAPIMCPServer { public async testLoad() { await this.load(); } public async testHandleCallTool(request: any) { return this.handleCallTool(request); } } const customServer = new TestServer(mockConfig); await customServer.testLoad(); const mockHttpResponse = { ok: true, data: { result: 'success' }, statusCode: 200, }; customServer.http.get = vi.fn().mockResolvedValue(mockHttpResponse); const result = await customServer.testHandleCallTool({ params: { name: mockToolId, arguments: { param1: 'value1' }, }, }); expect(customServer.http.get).toHaveBeenCalledWith('/api/resource', { headers: { 'Content-Type': 'application/json' }, }); expect(result).toEqual({ content: [ { type: 'text', text: JSON.stringify({ result: 'success' }, null, 2), }, ], }); }); it('should throw error when tool is not found', async () => { class TestServer extends OpenAPIMCPServer { public async testLoad() { await this.load(); } public async testHandleCallTool(request: any) { return this.handleCallTool(request); } } const customServer = new TestServer(mockConfig); await customServer.testLoad(); await expect( customServer.testHandleCallTool({ params: { name: 'nonExistentTool--unknown', arguments: {}, }, }), ).rejects.toThrow('Tool (nonExistentTool--unknown) not found: unknown'); }); it('should throw error when API call fails', async () => { class TestServer extends OpenAPIMCPServer { public async testLoad() { await this.load(); } public async testHandleCallTool(request: any) { return this.handleCallTool(request); } } const customServer = new TestServer(mockConfig); await customServer.testLoad(); const mockErrorResponse = { ok: false, error: { message: 'API error occurred' }, statusCode: 400, }; customServer.http.get = vi.fn().mockResolvedValue(mockErrorResponse); await expect( customServer.testHandleCallTool({ params: { name: mockToolId, arguments: {}, }, }), ).rejects.toThrow('API error occurred'); }); it('should check capabilities correctly', () => { class TestServer extends OpenAPIMCPServer { public testHasCapability(capability: string) { return this.hasCapability(capability as any); } public testEnsureCapability(capability: string) { return this.ensureCapability(capability as any); } } const customServer = new TestServer({ ...mockConfig, server: { ...mockConfig.server, capabilities: { tools: {}, resources: {}, }, }, }); expect(customServer.testHasCapability('tools')).toBe(true); expect(customServer.testHasCapability('resources')).toBe(true); expect(customServer.testHasCapability('prompts')).toBe(false); expect(() => { customServer.testEnsureCapability('resources'); }).not.toThrow(); expect(() => { customServer.testEnsureCapability('prompts'); }).toThrow('prompts not supported'); }); });

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/Twine2546/twilio-mcp-docker'

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