Skip to main content
Glama

Airtable MCP Server

by AM1010101
transport.ts3.1 kB
import http from 'node:http'; import type { AddressInfo } from 'node:net'; import assert from 'node:assert'; import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; import { AirtableMCPServer } from './mcpServer.js'; import { AirtableService } from './airtableService.js'; async function handleSSE(req: http.IncomingMessage, res: http.ServerResponse, url: URL, sessions: Map<string, SSEServerTransport>) { if (req.method === 'POST') { const sessionId = url.searchParams.get('sessionId'); if (!sessionId) { res.statusCode = 400; return res.end('Missing sessionId'); } const transport = sessions.get(sessionId); if (!transport) { res.statusCode = 404; return res.end('Session not found'); } return await transport.handlePostMessage(req, res); } else if (req.method === 'GET') { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { res.statusCode = 401; return res.end('Missing or invalid Authorization header. Expected: "Bearer <API_KEY>"'); } const apiKey = authHeader.substring('Bearer '.length); const airtableService = new AirtableService(apiKey); const server = new AirtableMCPServer(airtableService); const transport = new SSEServerTransport('/sse', res); sessions.set(transport.sessionId, transport); await server.connect(transport); res.on('close', () => { sessions.delete(transport.sessionId); }); return; } res.statusCode = 405; res.end('Method not allowed'); } export async function startHttpServer(config: { host?: string, port?: number }): Promise<http.Server> { const { host, port } = config; const httpServer = http.createServer(); await new Promise<void>((resolve, reject) => { httpServer.on('error', reject); httpServer.listen(port, host, () => { resolve(); httpServer.removeListener('error', reject); }); }); return httpServer; } export function httpAddressToString(address: string | AddressInfo | null): string { assert(address, 'Could not bind server socket'); if (typeof address === 'string') return address; const resolvedPort = address.port; let resolvedHost = address.family === 'IPv4' ? address.address : `[${address.address}]`; if (resolvedHost === '0.0.0.0' || resolvedHost === '[::]') resolvedHost = 'localhost'; return `http://${resolvedHost}:${resolvedPort}`; } export function startHttpTransport(httpServer: http.Server) { const sseSessions = new Map<string, SSEServerTransport>(); httpServer.on('request', async (req, res) => { const url = new URL(`http://localhost${req.url}`); await handleSSE(req, res, url, sseSessions); }); const url = httpAddressToString(httpServer.address()); const message = [ `Listening on ${url}`, 'Put this in your client config:', JSON.stringify({ 'mcpServers': { 'airtable': { 'url': `${url}/sse` } } }, undefined, 2), ].join('\n'); // eslint-disable-next-line no-console console.error(message); }

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/AM1010101/airtable-mcp-sse'

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