import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { ToastAPIClient } from './api-client.js'; import { registerOrdersTools } from './tools/orders-tools.js'; import { registerMenusTools } from './tools/menus-tools.js'; import { registerEmployeesTools } from './tools/employees-tools.js'; import { registerLaborTools } from './tools/labor-tools.js'; import { registerRestaurantTools } from './tools/restaurant-tools.js'; import { registerPaymentsTools } from './tools/payments-tools.js'; import { registerInventoryTools } from './tools/inventory-tools.js'; import { registerCustomersTools } from './tools/customers-tools.js'; import { registerReportingTools } from './tools/reporting-tools.js'; import { registerCashTools } from './tools/cash-tools.js'; import { apps } from './apps/index.js'; export class ToastMCPServer { private server: Server; private client: ToastAPIClient; private tools: any[]; constructor() { // Get configuration from environment const apiToken = process.env.TOAST_API_TOKEN; const restaurantGuid = process.env.TOAST_RESTAURANT_GUID; const baseUrl = process.env.TOAST_BASE_URL; if (!apiToken || !restaurantGuid) { throw new Error('TOAST_API_TOKEN and TOAST_RESTAURANT_GUID environment variables are required'); } // Initialize Toast API client this.client = new ToastAPIClient({ apiToken, restaurantGuid, baseUrl, }); // Initialize MCP server this.server = new Server( { name: 'toast-mcp-server', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, }, } ); // Register all tools this.tools = [ ...registerOrdersTools(this.client), ...registerMenusTools(this.client), ...registerEmployeesTools(this.client), ...registerLaborTools(this.client), ...registerRestaurantTools(this.client), ...registerPaymentsTools(this.client), ...registerInventoryTools(this.client), ...registerCustomersTools(this.client), ...registerReportingTools(this.client), ...registerCashTools(this.client), ]; this.setupHandlers(); } private setupHandlers() { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: this.tools.map((tool) => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema, })), })); // Execute tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const tool = this.tools.find((t) => t.name === request.params.name); if (!tool) { throw new Error(`Tool not found: ${request.params.name}`); } try { return await tool.execute(request.params.arguments); } catch (error: any) { return { content: [ { type: 'text', text: `Error executing ${request.params.name}: ${error.message}`, }, ], isError: true, }; } }); // List resources (MCP apps) this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({ resources: apps.map((app) => ({ uri: `toast://apps/${app.name}`, name: app.name, description: app.description, mimeType: 'application/json', })), })); // Read resource (get app definition) this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const appName = request.params.uri.replace('toast://apps/', ''); const app = apps.find((a) => a.name === appName); if (!app) { throw new Error(`App not found: ${appName}`); } return { contents: [ { uri: request.params.uri, mimeType: 'application/json', text: JSON.stringify(app, null, 2), }, ], }; }); // Error handling this.server.onerror = (error) => { console.error('[MCP Error]', error); }; process.on('SIGINT', async () => { await this.server.close(); process.exit(0); }); } async start() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('Toast MCP Server running on stdio'); } }