Skip to main content
Glama

airtable-mcp-server

mcpServer.test.ts4.9 kB
import { describe, test, expect, vi, beforeEach, afterEach, } from 'vitest'; import type { JSONRPCMessage, JSONRPCRequest, JSONRPCResponse, Tool, } from '@modelcontextprotocol/sdk/types.js'; import {InMemoryTransport} from '@modelcontextprotocol/sdk/inMemory.js'; import type {IAirtableService} from './types.js'; import {AirtableMCPServer} from './mcpServer.js'; describe('AirtableMCPServer', () => { let server: AirtableMCPServer; let mockAirtableService: IAirtableService; let serverTransport: InMemoryTransport; let clientTransport: InMemoryTransport; beforeEach(async () => { vi.clearAllMocks(); // Create mock AirtableService mockAirtableService = { listBases: vi.fn().mockResolvedValue({ bases: [ {id: 'base1', name: 'Test Base', permissionLevel: 'create'}, ], }), getBaseSchema: vi.fn().mockResolvedValue({ tables: [ { id: 'tbl1', name: 'Test Table', description: 'Test Description', fields: [], views: [], primaryFieldId: 'fld1', }, ], }), listRecords: vi.fn().mockResolvedValue([ {id: 'rec1', fields: {name: 'Test Record'}}, ]), getRecord: vi.fn().mockResolvedValue({ id: 'rec1', fields: {name: 'Test Record'}, }), createRecord: vi.fn().mockResolvedValue({ id: 'rec1', fields: {name: 'New Record'}, }), updateRecords: vi.fn().mockResolvedValue([ {id: 'rec1', fields: {name: 'Updated Record'}}, ]), deleteRecords: vi.fn().mockResolvedValue([ {id: 'rec1', deleted: true}, ]), createTable: vi.fn().mockResolvedValue({ id: 'tbl1', name: 'New Table', fields: [], }), updateTable: vi.fn().mockResolvedValue({ id: 'tbl1', name: 'Updated Table', fields: [], }), createField: vi.fn().mockResolvedValue({ id: 'fld1', name: 'New Field', type: 'singleLineText', }), updateField: vi.fn().mockResolvedValue({ id: 'fld1', name: 'Updated Field', type: 'singleLineText', }), searchRecords: vi.fn().mockResolvedValue([ {id: 'rec1', fields: {name: 'Test Result'}}, ]), }; // Create server instance with test transport server = new AirtableMCPServer(mockAirtableService); [serverTransport, clientTransport] = InMemoryTransport.createLinkedPair(); await server.connect(serverTransport); }); const sendRequest = async (message: JSONRPCRequest): Promise<JSONRPCResponse> => { return new Promise((resolve, reject) => { // Set up response handler clientTransport.onmessage = (response: JSONRPCMessage) => { resolve(response as JSONRPCResponse); }; clientTransport.onerror = (err: Error) => { reject(err); }; clientTransport.send(message).catch((err: unknown) => { reject(err instanceof Error ? err : new Error(String(err))); }); }); }; describe('server functionality', () => { test('handles list_resources request', async () => { const response = await sendRequest({ jsonrpc: '2.0', id: '1', method: 'resources/list', params: {}, }); expect(response.result).toEqual({ resources: [{ uri: 'airtable://base1/tbl1/schema', mimeType: 'application/json', name: 'Test Base: Test Table schema', description: 'Table schemas from Airtable bases', }], }); }); test('handles read_resource request', async () => { const response = await sendRequest({ jsonrpc: '2.0', id: '1', method: 'resources/read', params: { uri: 'airtable://base1/tbl1/schema', }, }); expect(response.result).toEqual({ contents: [{ uri: 'airtable://base1/tbl1/schema', mimeType: 'application/json', text: JSON.stringify({ baseId: 'base1', tableId: 'tbl1', name: 'Test Table', description: 'Test Description', primaryFieldId: 'fld1', fields: [], views: [], }), }], }); }); test('handles list_tools request', async () => { const response = await sendRequest({ jsonrpc: '2.0', id: '1', method: 'tools/list', params: {}, }); expect((response.result.tools as Tool[]).length).toBeGreaterThanOrEqual(12); expect((response.result.tools as Tool[])[0]).toMatchObject({ name: 'list_records', description: expect.any(String), inputSchema: expect.objectContaining({ type: 'object', }), }); }); test('handles list_records tool call', async () => { const response = await sendRequest({ jsonrpc: '2.0', id: '1', method: 'tools/call', params: { name: 'list_records', arguments: { baseId: 'base1', tableId: 'tbl1', maxRecords: 100, }, }, }); expect(response.result).toEqual({ content: [{ type: 'text', text: JSON.stringify([ {id: 'rec1', fields: {name: 'Test Record'}}, ]), }], }); }); }); afterEach(async () => { await server.close(); }); });

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/domdomegg/airtable-mcp-server'

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