UNPKG

@atlas-kitchen/atlas-mcp

Version:

Model Context Protocol server for Atlas restaurant management system - enables Claude to interact with restaurant orders, menus, and reports

188 lines 6.41 kB
#!/usr/bin/env node // Check Node.js version before proceeding const nodeVersion = process.versions.node; const major = parseInt(nodeVersion.split('.')[0], 10); if (major < 18) { console.error(`Error: Node.js version ${nodeVersion} is not supported.`); console.error('This package requires Node.js 18.0.0 or higher.'); console.error('Please upgrade your Node.js version.'); process.exit(1); } // Load environment variables before any other imports import dotenv from 'dotenv'; dotenv.config(); // Verify that fetch and Headers are available if (typeof fetch === 'undefined' || typeof Headers === 'undefined') { console.error('Error: fetch or Headers API is not available.'); console.error('Please ensure you are using Node.js 18.0.0 or higher with --experimental-fetch flag if needed.'); console.error(`Current Node.js version: ${nodeVersion}`); process.exit(1); } import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { AuthManager } from './auth.js'; import { AtlasClient } from './client.js'; import { saveCache, loadCache, clearCache } from './token-cache.js'; import { createAuthTools } from './tools/auth.js'; import { createOrderTools } from './tools/orders.js'; import { createMenuTools } from './tools/menu.js'; import { createReportingTools } from './tools/reports.js'; const server = new Server({ name: 'atlas-mcp', version: '1.0.0', }, { capabilities: { tools: {}, }, }); const authManager = new AuthManager(); const atlasClient = new AtlasClient(authManager); // --- Auth helpers --- async function authenticate() { const apiKey = process.env.ATLAS_API_KEY; if (!apiKey) { console.error('ATLAS_API_KEY is not set. Authentication will not be attempted.'); return false; } try { const result = await atlasClient.apiKeyLogin(apiKey); authManager.setTokens({ accessToken: result.accessToken, refreshToken: result.refreshToken, }); // Persist tokens (and existing context if any) const cached = loadCache(); saveCache({ accessToken: result.accessToken, refreshToken: result.refreshToken, merchantId: cached?.merchantId, outletId: cached?.outletId, }); return true; } catch (error) { console.error('API key authentication failed:', error.message); return false; } } async function tryRefreshToken() { const tokens = authManager.getTokens(); if (!tokens?.refreshToken) return false; try { const result = await atlasClient.refreshToken(tokens.refreshToken); authManager.setTokens({ accessToken: result.accessToken, refreshToken: result.refreshToken, }); const cached = loadCache(); saveCache({ accessToken: result.accessToken, refreshToken: result.refreshToken, merchantId: cached?.merchantId, outletId: cached?.outletId, }); return true; } catch { return false; } } // Wire auto-recovery: refresh → re-auth with API key atlasClient.onAuthFailure = async () => { const refreshed = await tryRefreshToken(); if (refreshed) return true; clearCache(); return await authenticate(); }; // --- Tool registration --- const allTools = [ ...createAuthTools(atlasClient, authManager, authenticate), ...createOrderTools(atlasClient, authManager), ...createMenuTools(atlasClient), ...createReportingTools(atlasClient), ]; server.setRequestHandler(CallToolRequestSchema, async (request) => { const tool = allTools.find(t => t.name === request.params.name); if (!tool) { throw new Error(`Tool ${request.params.name} not found`); } try { return { content: [ { type: 'text', text: JSON.stringify(await tool.handler(request.params.arguments)), }, ], }; } catch (error) { return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: error.message || 'An unexpected error occurred', }), }, ], }; } }); server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: allTools.map(tool => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema, })), }; }); // --- Startup --- async function main() { // 1. Try loading cached tokens + context const cached = loadCache(); if (cached) { authManager.setTokens({ accessToken: cached.accessToken, refreshToken: cached.refreshToken, }); if (cached.merchantId) { authManager.setMerchantContext(cached.merchantId, cached.outletId); } console.error('Loaded cached tokens and context.'); } else { // 2. No cache — authenticate with API key const ok = await authenticate(); if (ok) { console.error('Authenticated with API key.'); } } // 3. Override merchant context from env vars (first run only — if no cached context) if (!authManager.getMerchantId() && process.env.ATLAS_MERCHANT_ID) { authManager.setMerchantContext(process.env.ATLAS_MERCHANT_ID, process.env.ATLAS_OUTLET_ID); // Persist the env-derived context const tokens = authManager.getTokens(); if (tokens) { saveCache({ accessToken: tokens.accessToken, refreshToken: tokens.refreshToken, merchantId: process.env.ATLAS_MERCHANT_ID, outletId: process.env.ATLAS_OUTLET_ID, }); } } const transport = new StdioServerTransport(); await server.connect(transport); process.stdin.resume(); } main().catch((error) => { console.error('Server error:', error); process.exit(1); }); //# sourceMappingURL=index.js.map