@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
JavaScript
// 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