UNPKG

amazon-seller-mcp

Version:

Model Context Protocol (MCP) client for Amazon Selling Partner API

328 lines 16.7 kB
/** * Inventory resources for Amazon Selling Partner API */ import { InventoryClient } from '../../api/inventory-client.js'; import { error, info } from '../../utils/logger.js'; /** * Register inventory resources with the resource manager * * @param resourceManager Resource registration manager * @param authConfig Authentication configuration */ export function registerInventoryResources(resourceManager, authConfig) { const inventoryClient = new InventoryClient(authConfig); // Register inventory collection resource const inventoryTemplate = resourceManager.createResourceTemplate('amazon-inventory://{sku}', 'amazon-inventory://', { // Completion function for SKU parameter sku: async (value) => { if (!value || value.length < 2) { return []; } try { // Get all inventory items and filter by the partial SKU const result = await inventoryClient.getInventory(); // Filter and return matching SKUs return result.items .filter((item) => item.sku.toLowerCase().includes(value.toLowerCase())) .map((item) => item.sku) .slice(0, 10); // Limit to 10 results } catch (err) { error('Error completing SKU:', { error: err }); return []; } }, }); resourceManager.registerResource('amazon-inventory', inventoryTemplate, { title: 'Amazon Inventory', description: 'Manage and view your Amazon inventory levels', }, async (uri, params) => { try { const { sku } = params; // If SKU is provided, get a specific inventory item if (sku) { const inventoryItem = await inventoryClient.getInventoryBySku(sku); // Format the response as markdown let markdown = `# Amazon Inventory: ${sku}\n\n`; // Add basic information markdown += `## Basic Information\n\n`; markdown += `**SKU:** ${inventoryItem.sku}\n\n`; if (inventoryItem.asin) { markdown += `**ASIN:** [${inventoryItem.asin}](amazon-catalog://${inventoryItem.asin})\n\n`; } if (inventoryItem.condition) { markdown += `**Condition:** ${inventoryItem.condition}\n\n`; } markdown += `**Last Updated:** ${new Date(inventoryItem.lastUpdatedTime).toLocaleString()}\n\n`; // Add inventory details markdown += `## Inventory Details\n\n`; inventoryItem.inventoryDetails.forEach((detail) => { markdown += `### ${detail.fulfillmentChannelCode} Fulfillment\n\n`; markdown += `**Available Quantity:** ${detail.quantity}\n\n`; if (detail.reservedQuantity !== undefined) { markdown += `**Reserved Quantity:** ${detail.reservedQuantity}\n\n`; } if (detail.restockDate) { markdown += `**Restock Date:** ${new Date(detail.restockDate).toLocaleDateString()}\n\n`; } // Add replenishment settings if available if (detail.replenishmentSettings) { markdown += `#### Replenishment Settings\n\n`; if (detail.replenishmentSettings.restockLevel !== undefined) { markdown += `**Restock Level:** ${detail.replenishmentSettings.restockLevel}\n\n`; } if (detail.replenishmentSettings.targetLevel !== undefined) { markdown += `**Target Level:** ${detail.replenishmentSettings.targetLevel}\n\n`; } if (detail.replenishmentSettings.maximumLevel !== undefined) { markdown += `**Maximum Level:** ${detail.replenishmentSettings.maximumLevel}\n\n`; } if (detail.replenishmentSettings.leadTimeDays !== undefined) { markdown += `**Lead Time:** ${detail.replenishmentSettings.leadTimeDays} days\n\n`; } } }); return { contents: [ { uri: `amazon-inventory://${sku}`, text: markdown, mimeType: 'text/markdown', }, ], }; } // If no SKU is provided, list all inventory items else { // Get query parameters from the URI const url = new URL(uri.toString()); const fulfillmentChannels = url.searchParams.get('fulfillmentChannels')?.split(','); const nextToken = url.searchParams.get('nextToken') || undefined; // Get inventory with optional filters const result = await inventoryClient.getInventory({ fulfillmentChannels, nextToken, }); // Format the response as markdown let markdown = `# Amazon Inventory\n\n`; if (result.items.length === 0) { markdown += `No inventory items found.\n`; } else { markdown += `Found ${result.items.length} inventory items\n\n`; // Add filtering options markdown += `## Filter Options\n\n`; markdown += `- [All Inventory](amazon-inventory://)\n`; markdown += `- [Amazon Fulfilled](amazon-inventory://?fulfillmentChannels=AMAZON)\n`; markdown += `- [Seller Fulfilled](amazon-inventory://?fulfillmentChannels=SELLER)\n\n`; // Add pagination info if available if (result.nextToken) { const nextPageUrl = new URL(uri.toString()); nextPageUrl.searchParams.set('nextToken', result.nextToken); markdown += `[Next Page](${nextPageUrl.toString()})\n\n`; } // Add inventory items markdown += `## Inventory Items\n\n`; result.items.forEach((item, index) => { markdown += `### ${index + 1}. [${item.sku}](amazon-inventory://${item.sku})\n\n`; if (item.asin) { markdown += `**ASIN:** [${item.asin}](amazon-catalog://${item.asin})\n\n`; } if (item.condition) { markdown += `**Condition:** ${item.condition}\n\n`; } // Add inventory levels by fulfillment channel markdown += `**Inventory Levels:**\n`; item.inventoryDetails.forEach((detail) => { markdown += `- ${detail.fulfillmentChannelCode}: ${detail.quantity} units`; if (detail.reservedQuantity !== undefined) { markdown += ` (${detail.reservedQuantity} reserved)`; } if (detail.restockDate) { markdown += ` - Restock Date: ${new Date(detail.restockDate).toLocaleDateString()}`; } markdown += '\n'; }); markdown += `\n**Last Updated:** ${new Date(item.lastUpdatedTime).toLocaleString()}\n\n`; markdown += `[View Details](amazon-inventory://${item.sku})\n\n`; markdown += `---\n\n`; }); } return { contents: [ { uri: 'amazon-inventory://', text: markdown, mimeType: 'text/markdown', }, ], }; } } catch (err) { error('Error retrieving inventory:', { error: err }); return { contents: [ { uri: uri.toString(), text: `# Error\n\nFailed to retrieve inventory: ${err.message}`, mimeType: 'text/markdown', }, ], }; } }); // Register inventory filter resource const inventoryFilterTemplate = resourceManager.createResourceTemplate('amazon-inventory-filter://{filter}', 'amazon-inventory-filter://'); resourceManager.registerResource('amazon-inventory-filter', inventoryFilterTemplate, { title: 'Amazon Inventory Filter', description: 'Filter and view your Amazon inventory by various criteria', }, async (uri, params) => { try { const { filter } = params; // Parse the filter string to determine the filter type and value let filterType; let filterValue; // Handle URL-encoded filter parameter from the URI path let filterParam = filter; if (!filterParam) { // Extract filter from URI path if not in params const pathParts = uri.pathname.split('/').filter((part) => part); if (pathParts.length > 0) { filterParam = decodeURIComponent(pathParts[pathParts.length - 1]); } } if (filterParam && filterParam.includes(':')) { [filterType, filterValue] = filterParam.split(':', 2); } else { // Default to showing filter options filterType = ''; filterValue = ''; } // If a specific filter is provided if (filterType && filterValue) { // Get query parameters from the URI const url = new URL(uri.toString()); const nextToken = url.searchParams.get('nextToken') || undefined; // Prepare filter parameters const filterParams = { nextToken }; // Apply the appropriate filter switch (filterType.toLowerCase()) { case 'sku': filterParams.sellerSkus = [filterValue]; break; case 'asin': filterParams.asins = [filterValue]; break; case 'channel': if (['AMAZON', 'SELLER'].includes(filterValue.toUpperCase())) { filterParams.fulfillmentChannels = [filterValue.toUpperCase()]; } break; case 'date': // Format should be YYYY-MM-DD try { const date = new Date(filterValue); if (isNaN(date.getTime())) { throw new Error(`Invalid date format. Use YYYY-MM-DD.`); } filterParams.startDateTime = new Date(date.setHours(0, 0, 0, 0)); filterParams.endDateTime = new Date(date.setHours(23, 59, 59, 999)); } catch { throw new Error(`Invalid date format. Use YYYY-MM-DD.`); } break; default: throw new Error(`Unknown filter type: ${filterType}`); } // Get filtered inventory const result = await inventoryClient.getInventory(filterParams); // Format the response as markdown let markdown = `# Amazon Inventory: ${filterType.charAt(0).toUpperCase() + filterType.slice(1)} Filter - ${filterValue}\n\n`; if (result.items.length === 0) { markdown += `No inventory items found matching the filter.\n`; } else { markdown += `Found ${result.items.length} inventory items\n\n`; // Add pagination info if available if (result.nextToken) { const nextPageUrl = new URL(uri.toString()); nextPageUrl.searchParams.set('nextToken', result.nextToken); markdown += `[Next Page](${nextPageUrl.toString()})\n\n`; } // Add inventory items markdown += `## Inventory Items\n\n`; result.items.forEach((item, index) => { markdown += `### ${index + 1}. [${item.sku}](amazon-inventory://${item.sku})\n\n`; if (item.asin) { markdown += `**ASIN:** [${item.asin}](amazon-catalog://${item.asin})\n\n`; } // Add inventory levels by fulfillment channel markdown += `**Inventory Levels:**\n`; item.inventoryDetails.forEach((detail) => { markdown += `- ${detail.fulfillmentChannelCode}: ${detail.quantity} units`; if (detail.reservedQuantity !== undefined) { markdown += ` (${detail.reservedQuantity} reserved)`; } markdown += '\n'; }); markdown += `\n**Last Updated:** ${new Date(item.lastUpdatedTime).toLocaleString()}\n\n`; markdown += `[View Details](amazon-inventory://${item.sku})\n\n`; markdown += `---\n\n`; }); } return { contents: [ { uri: `amazon-inventory-filter://${encodeURIComponent(filterType + ':' + filterValue)}`, text: markdown, mimeType: 'text/markdown', }, ], }; } // If no specific filter is provided, show filter options else { // Format the response as markdown let markdown = `# Amazon Inventory Filters\n\n`; markdown += `Use these filters to narrow down your inventory view:\n\n`; markdown += `## Filter by SKU\n\n`; markdown += `Enter a SKU to filter by: [amazon-inventory-filter://sku:YOUR_SKU]\n\n`; markdown += `## Filter by ASIN\n\n`; markdown += `Enter an ASIN to filter by: [amazon-inventory-filter://asin:YOUR_ASIN]\n\n`; markdown += `## Filter by Fulfillment Channel\n\n`; markdown += `- [Amazon Fulfilled](amazon-inventory-filter://channel:AMAZON)\n`; markdown += `- [Seller Fulfilled](amazon-inventory-filter://channel:SELLER)\n\n`; markdown += `## Filter by Update Date\n\n`; markdown += `Enter a date (YYYY-MM-DD) to filter by: [amazon-inventory-filter://date:YYYY-MM-DD]\n\n`; markdown += `## View All Inventory\n\n`; markdown += `- [View All Inventory](amazon-inventory://)\n`; return { contents: [ { uri: 'amazon-inventory-filter://', text: markdown, mimeType: 'text/markdown', }, ], }; } } catch (err) { error('Error filtering inventory:', { error: err }); return { contents: [ { uri: uri.toString(), text: `# Error\n\nFailed to filter inventory: ${err.message}`, mimeType: 'text/markdown', }, ], }; } }); info('Registered inventory resources'); } //# sourceMappingURL=inventory-resources.js.map