// Vercel Serverless Function for AITable MCP
import type { VercelRequest, VercelResponse } from '@vercel/node';
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { registerAITableTools } from "../src/aitable-tools.js";
const API_TOKEN = process.env.AITABLE_API_TOKEN;
const SPACE_ID = process.env.SPACE_ID;
if (!API_TOKEN || !SPACE_ID) {
throw new Error("Missing required environment variables");
}
export default async function handler(req: VercelRequest, res: VercelResponse) {
// Handle CORS
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
res.status(200).end();
return;
}
// Health check
if (req.method === 'GET' && req.url === '/api/health') {
res.status(200).json({ status: 'ok', server: 'aitable-mcp' });
return;
}
// MCP request
if (req.method === 'POST') {
const server = new McpServer({
name: "aitable-mcp",
version: "1.0.0",
});
registerAITableTools(server, API_TOKEN!, SPACE_ID!);
try {
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
enableJsonResponse: true,
});
await server.connect(transport);
await transport.handleRequest(req as any, res as any, req.body);
} catch (error) {
console.error("Error handling MCP request:", error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: "2.0",
error: {
code: -32603,
message: "Internal server error",
},
id: null,
});
}
}
} else {
res.status(405).json({ error: 'Method not allowed' });
}
}