@atlas-kitchen/atlas-mcp
Version:
Model Context Protocol server for Atlas restaurant management system - enables Claude to interact with restaurant orders, menus, and reports
176 lines • 7.79 kB
JavaScript
import { z } from 'zod';
import { saveCache, loadCache, clearCache } from '../token-cache.js';
const SwitchMerchantSchema = z.object({
merchant: z.string(),
outletId: z.string().optional(),
});
export function createAuthTools(client, authManager, reauthenticate) {
return [
{
name: 'atlas_switch_merchant',
description: 'Switch active merchant context. Accepts a merchant name, identifier, or ID - fuzzy matching is supported. Optionally set an outlet ID for POS operations.',
inputSchema: {
type: 'object',
properties: {
merchant: { type: 'string', description: 'Merchant name, identifier, or ID to switch to (fuzzy matched)' },
outletId: { type: 'string', description: 'Outlet ID (optional)' },
},
required: ['merchant'],
},
handler: async (input) => {
const { merchant, outletId } = SwitchMerchantSchema.parse(input);
try {
const merchants = await client.getMerchants();
const needle = merchant.toLowerCase();
// Try exact match first (id or identifier), then fuzzy name match
const match = merchants.find((m) => m.id === merchant ||
m.identifier === merchant ||
m.identifier?.toLowerCase() === needle ||
m.name?.toLowerCase() === needle) || merchants.find((m) => m.name?.toLowerCase().includes(needle) ||
m.identifier?.toLowerCase().includes(needle) ||
m.brandAndEntityNames?.some((b) => b.toLowerCase().includes(needle)));
if (!match) {
return {
success: false,
error: `No merchant matching "${merchant}". Available merchants: ${merchants.map((m) => `${m.name} (${m.identifier})`).join(', ')}`,
};
}
authManager.setMerchantContext(match.identifier, outletId);
// Persist context to cache
const tokens = authManager.getTokens();
if (tokens) {
saveCache({
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken,
merchantId: match.identifier,
outletId: outletId,
});
}
return {
success: true,
message: `Switched to merchant: ${match.name} (${match.identifier})`,
context: {
merchantId: match.id,
merchantName: match.name,
merchantIdentifier: match.identifier,
outletId: authManager.getOutletId(),
},
};
}
catch (error) {
return {
success: false,
error: error.message || 'Failed to switch merchant',
};
}
},
},
{
name: 'atlas_list_merchants',
description: 'List all merchants the authenticated user can access, showing each merchant\'s name, identifier, and ID. Use this to find the right merchant before calling atlas_switch_merchant.',
inputSchema: {
type: 'object',
properties: {},
},
handler: async () => {
try {
const merchants = await client.getMerchants();
const currentMerchantId = authManager.getMerchantId();
return {
success: true,
currentMerchantId,
merchants: merchants.map((m) => ({
id: m.id,
name: m.name,
identifier: m.identifier,
brandAndEntityNames: m.brandAndEntityNames,
})),
};
}
catch (error) {
return {
success: false,
error: error.message || 'Failed to list merchants',
};
}
},
},
{
name: 'atlas_list_outlets',
description: 'List all outlets for the current merchant, showing each outlet\'s id, identifier, label, archived status, and config. Use this to find outlet IDs for operations that require a specific outlet context.',
inputSchema: {
type: 'object',
properties: {},
},
handler: async () => {
try {
const outlets = await client.getOutlets();
return {
success: true,
outlets,
};
}
catch (error) {
return {
success: false,
error: error.message || 'Failed to list outlets',
};
}
},
},
{
name: 'atlas_reauth',
description: 'Force re-authentication by clearing all cached tokens and merchant context, then re-authenticating with the API key. Use this when API calls fail due to stale or expired tokens.',
inputSchema: {
type: 'object',
properties: {},
},
handler: async () => {
try {
authManager.clear();
clearCache();
const ok = await reauthenticate();
if (ok) {
return {
success: true,
message: 'Re-authenticated successfully. Merchant context was cleared — use atlas_switch_merchant to set it again.',
};
}
return {
success: false,
error: 'Re-authentication failed. Check that ATLAS_API_KEY is set and valid.',
};
}
catch (error) {
return {
success: false,
error: error.message || 'Re-authentication failed',
};
}
},
},
{
name: 'atlas_auth_status',
description: 'Show current authentication state, active merchant ID, outlet ID, and whether cached tokens exist. Use this to verify which merchant/outlet context is active before making API calls.',
inputSchema: {
type: 'object',
properties: {},
},
handler: async () => {
const authenticated = authManager.isAuthenticated();
const merchantId = authManager.getMerchantId();
const outletId = authManager.getOutletId();
const cached = loadCache();
return {
success: true,
authenticated,
merchantId,
outletId,
hasCachedTokens: cached !== null,
hasCachedContext: cached?.merchantId != null,
};
},
},
];
}
//# sourceMappingURL=auth.js.map