Skip to main content
Glama

Amazon Order History CSV Download MCP

by marcusquinn
export-csv.ts8.67 kB
/** * CSV export functions for Amazon order data. */ import { writeFile } from "fs/promises"; import { homedir } from "os"; import { join } from "path"; import { toCSVWithColumns } from "../core/utils/csv"; import { Item } from "../core/types/item"; import { Shipment } from "../core/types/shipment"; import { Transaction } from "../core/types/transaction"; import { ORDER_CSV_COLUMNS, ITEM_CSV_COLUMNS, SHIPMENT_CSV_COLUMNS, TRANSACTION_CSV_COLUMNS, GIFT_CARD_CSV_COLUMNS, OrderCSVData, GiftCardTransactionCSVData, } from "./csv-columns"; /** * Export result returned by export functions. */ export interface ExportResult { success: boolean; filePath: string; rowCount: number; error?: string; } /** * Export orders to CSV file. */ export async function exportOrdersCSV( orders: OrderCSVData[], outputPath: string, ): Promise<ExportResult> { try { const csv = toCSVWithColumns(orders, ORDER_CSV_COLUMNS); await writeFile(outputPath, csv, "utf-8"); return { success: true, filePath: outputPath, rowCount: orders.length, }; } catch (error) { return { success: false, filePath: outputPath, rowCount: 0, error: String(error), }; } } /** * Export items to CSV file. */ export async function exportItemsCSV( items: Item[], outputPath: string, ): Promise<ExportResult> { try { const csv = toCSVWithColumns(items, ITEM_CSV_COLUMNS); await writeFile(outputPath, csv, "utf-8"); return { success: true, filePath: outputPath, rowCount: items.length, }; } catch (error) { return { success: false, filePath: outputPath, rowCount: 0, error: String(error), }; } } /** * Export shipments to CSV file. */ export async function exportShipmentsCSV( shipments: Shipment[], outputPath: string, ): Promise<ExportResult> { try { const csv = toCSVWithColumns(shipments, SHIPMENT_CSV_COLUMNS); await writeFile(outputPath, csv, "utf-8"); return { success: true, filePath: outputPath, rowCount: shipments.length, }; } catch (error) { return { success: false, filePath: outputPath, rowCount: 0, error: String(error), }; } } /** * Export transactions to CSV file. */ export async function exportTransactionsCSV( transactions: Transaction[], outputPath: string, ): Promise<ExportResult> { try { const csv = toCSVWithColumns(transactions, TRANSACTION_CSV_COLUMNS); await writeFile(outputPath, csv, "utf-8"); return { success: true, filePath: outputPath, rowCount: transactions.length, }; } catch (error) { return { success: false, filePath: outputPath, rowCount: 0, error: String(error), }; } } /** * Export gift card transactions to CSV file. */ export async function exportGiftCardTransactionsCSV( transactions: GiftCardTransactionCSVData[], outputPath: string, ): Promise<ExportResult> { try { const csv = toCSVWithColumns(transactions, GIFT_CARD_CSV_COLUMNS); await writeFile(outputPath, csv, "utf-8"); return { success: true, filePath: outputPath, rowCount: transactions.length, }; } catch (error) { return { success: false, filePath: outputPath, rowCount: 0, error: String(error), }; } } /** * Generate default filename for export. * Format: amazon-{region}-{type}-{startDate}-{endDate}.csv * Example: amazon-uk-orders-2024-2024-12-01.csv */ export function generateExportFilename( exportType: "orders" | "items" | "shipments" | "transactions" | "gift-cards", region: string, options?: { year?: number; startDate?: string; endDate?: string; }, ): string { const today = new Date().toISOString().split("T")[0]; let datePart: string; if (options?.startDate && options?.endDate) { // Use provided date range datePart = `${options.startDate}-${options.endDate}`; } else if (options?.year) { // Year specified - range from Jan 1 to today (or Dec 31 if past year) const currentYear = new Date().getFullYear(); const endDate = options.year < currentYear ? `${options.year}-12-31` : today; datePart = `${options.year}-${endDate}`; } else { // No year specified - use current year to today const currentYear = new Date().getFullYear(); datePart = `${currentYear}-${today}`; } return `amazon-${region}-${exportType}-${datePart}.csv`; } /** * Get default Downloads directory path. */ export function getDefaultDownloadsPath(): string { return join(homedir(), "Downloads"); } /** * Common MCP client timeout thresholds (in seconds). */ export const COMMON_TIMEOUTS = { claude: 120, // Claude Desktop default cursor: 300, // Cursor default opencode: 600, // OpenCode default (10 minutes) conservative: 60, // Conservative estimate }; /** * Estimated time per order for different extraction modes (in seconds). */ export const TIME_PER_ORDER = { listOnly: 0.5, // Just listing orders from order history pages invoiceExtraction: 2, // Invoice-based item extraction detailExtraction: 4, // Full detail page extraction withShipments: 5, // Including shipment tracking }; /** * Estimate extraction time and check against common timeouts. */ export interface TimeEstimate { estimatedSeconds: number; estimatedMinutes: number; formattedEstimate: string; warnings: string[]; recommendations: string[]; } export function estimateExtractionTime( orderCount: number, options: { includeItems?: boolean; includeShipments?: boolean; useInvoice?: boolean; } = {}, ): TimeEstimate { const { includeItems = false, includeShipments = false, useInvoice = true, } = options; // Calculate base time let timePerOrder = TIME_PER_ORDER.listOnly; if (includeItems || includeShipments) { if (includeShipments) { timePerOrder = TIME_PER_ORDER.withShipments; } else if (useInvoice) { timePerOrder = TIME_PER_ORDER.invoiceExtraction; } else { timePerOrder = TIME_PER_ORDER.detailExtraction; } } // Add overhead for pagination (roughly 2 seconds per 10 orders for page loads) const paginationOverhead = Math.ceil(orderCount / 10) * 2; const estimatedSeconds = Math.ceil( orderCount * timePerOrder + paginationOverhead, ); const estimatedMinutes = Math.ceil(estimatedSeconds / 60); const warnings: string[] = []; const recommendations: string[] = []; // Check against common timeouts if (estimatedSeconds > COMMON_TIMEOUTS.conservative) { if (estimatedSeconds > COMMON_TIMEOUTS.opencode) { warnings.push( `Estimated time (${estimatedMinutes}min) exceeds most client timeouts`, ); recommendations.push( `Consider using max_orders to limit batch size (e.g., max_orders: 100)`, ); recommendations.push( `Process in yearly batches for large order histories`, ); } else if (estimatedSeconds > COMMON_TIMEOUTS.cursor) { warnings.push( `Estimated time (${estimatedMinutes}min) may exceed some client timeouts`, ); recommendations.push( `If timeout occurs, try with max_orders: ${Math.floor(COMMON_TIMEOUTS.cursor / timePerOrder)}`, ); } else if (estimatedSeconds > COMMON_TIMEOUTS.claude) { warnings.push( `Estimated time (${estimatedMinutes}min) may exceed Claude Desktop timeout (2min)`, ); recommendations.push( `For Claude Desktop, consider max_orders: ${Math.floor(COMMON_TIMEOUTS.claude / timePerOrder)}`, ); } } // Format estimate string let formattedEstimate: string; if (estimatedSeconds < 60) { formattedEstimate = `~${estimatedSeconds} seconds`; } else if (estimatedMinutes < 60) { formattedEstimate = `~${estimatedMinutes} minutes`; } else { const hours = Math.floor(estimatedMinutes / 60); const mins = estimatedMinutes % 60; formattedEstimate = `~${hours}h ${mins}m`; } return { estimatedSeconds, estimatedMinutes, formattedEstimate, warnings, recommendations, }; } /** * Generate full output path with default directory. */ export function getOutputPath( outputPath: string | undefined, exportType: "orders" | "items" | "shipments" | "transactions" | "gift-cards", region: string, options?: { year?: number; startDate?: string; endDate?: string; }, ): string { if (outputPath) { return outputPath; } const filename = generateExportFilename(exportType, region, options); return join(getDefaultDownloadsPath(), filename); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/marcusquinn/amazon-order-history-csv-download-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server