Răsfoiți Sursa

feat: enhance MCP tools with required filters and customer email requirement #76

- Orders: Require at least one filter (dates, customer_email, customer_name)
- Orders: Default limit 5, max 20
- Customers: Email required, returns single customer
- Remove list_customers and get_customer_orders tools
- Update all 3 platforms: WooCommerce, Shopify, ShopRenter
- Add filter support to API clients
- Version bump to 2.0.0
Claude 5 luni în urmă
părinte
comite
09f07ea8c5

+ 74 - 7
supabase/functions/_shared/shopify-client.ts

@@ -277,14 +277,62 @@ export async function fetchAllProducts(storeId: string): Promise<ShopifyProduct[
   return allProducts
   return allProducts
 }
 }
 
 
+export interface ShopifyOrderFilters {
+  status?: string;       // any, open, closed, cancelled
+  financial_status?: string;  // paid, pending, refunded, etc.
+  fulfillment_status?: string; // shipped, partial, unshipped, any
+  created_at_min?: string;    // ISO 8601 datetime
+  created_at_max?: string;    // ISO 8601 datetime
+  updated_at_min?: string;    // ISO 8601 datetime
+  updated_at_max?: string;    // ISO 8601 datetime
+  customer_id?: string;       // Filter by customer ID
+  email?: string;             // Filter by customer email
+  name?: string;              // Filter by customer name
+}
+
 // Fetch orders with pagination
 // Fetch orders with pagination
 export async function fetchOrders(
 export async function fetchOrders(
   storeId: string,
   storeId: string,
   limit: number = 250,
   limit: number = 250,
   sinceId?: number,
   sinceId?: number,
-  status: string = 'any' // any, open, closed, cancelled
+  filters?: ShopifyOrderFilters
 ): Promise<ShopifyOrder[]> {
 ): Promise<ShopifyOrder[]> {
-  let endpoint = `/orders.json?limit=${limit}&status=${status}`
+  let endpoint = `/orders.json?limit=${limit}`
+
+  // Apply filters
+  if (filters) {
+    if (filters.status) {
+      endpoint += `&status=${filters.status}`
+    }
+    if (filters.financial_status) {
+      endpoint += `&financial_status=${filters.financial_status}`
+    }
+    if (filters.fulfillment_status) {
+      endpoint += `&fulfillment_status=${filters.fulfillment_status}`
+    }
+    if (filters.created_at_min) {
+      endpoint += `&created_at_min=${encodeURIComponent(filters.created_at_min)}`
+    }
+    if (filters.created_at_max) {
+      endpoint += `&created_at_max=${encodeURIComponent(filters.created_at_max)}`
+    }
+    if (filters.updated_at_min) {
+      endpoint += `&updated_at_min=${encodeURIComponent(filters.updated_at_min)}`
+    }
+    if (filters.updated_at_max) {
+      endpoint += `&updated_at_max=${encodeURIComponent(filters.updated_at_max)}`
+    }
+    if (filters.email) {
+      endpoint += `&email=${encodeURIComponent(filters.email)}`
+    }
+    if (filters.name) {
+      endpoint += `&name=${encodeURIComponent(filters.name)}`
+    }
+  } else {
+    // Default to 'any' status if no filters provided
+    endpoint += `&status=any`
+  }
+
   if (sinceId) {
   if (sinceId) {
     endpoint += `&since_id=${sinceId}`
     endpoint += `&since_id=${sinceId}`
   }
   }
@@ -296,14 +344,14 @@ export async function fetchOrders(
 // Fetch all orders with automatic pagination
 // Fetch all orders with automatic pagination
 export async function fetchAllOrders(
 export async function fetchAllOrders(
   storeId: string,
   storeId: string,
-  status: string = 'any'
+  filters?: ShopifyOrderFilters
 ): Promise<ShopifyOrder[]> {
 ): Promise<ShopifyOrder[]> {
   const allOrders: ShopifyOrder[] = []
   const allOrders: ShopifyOrder[] = []
   let sinceId: number | undefined = undefined
   let sinceId: number | undefined = undefined
   let hasMore = true
   let hasMore = true
 
 
   while (hasMore) {
   while (hasMore) {
-    const orders = await fetchOrders(storeId, 250, sinceId, status)
+    const orders = await fetchOrders(storeId, 250, sinceId, filters)
 
 
     if (orders.length === 0) {
     if (orders.length === 0) {
       hasMore = false
       hasMore = false
@@ -317,13 +365,29 @@ export async function fetchAllOrders(
   return allOrders
   return allOrders
 }
 }
 
 
+export interface ShopifyCustomerFilters {
+  email?: string;    // Filter by exact email
+  query?: string;    // GraphQL-style query for searching
+}
+
 // Fetch customers with pagination
 // Fetch customers with pagination
 export async function fetchCustomers(
 export async function fetchCustomers(
   storeId: string,
   storeId: string,
   limit: number = 250,
   limit: number = 250,
-  sinceId?: number
+  sinceId?: number,
+  filters?: ShopifyCustomerFilters
 ): Promise<ShopifyCustomer[]> {
 ): Promise<ShopifyCustomer[]> {
   let endpoint = `/customers.json?limit=${limit}`
   let endpoint = `/customers.json?limit=${limit}`
+
+  if (filters) {
+    if (filters.email) {
+      endpoint += `&email=${encodeURIComponent(filters.email)}`
+    }
+    if (filters.query) {
+      endpoint += `&query=${encodeURIComponent(filters.query)}`
+    }
+  }
+
   if (sinceId) {
   if (sinceId) {
     endpoint += `&since_id=${sinceId}`
     endpoint += `&since_id=${sinceId}`
   }
   }
@@ -333,13 +397,16 @@ export async function fetchCustomers(
 }
 }
 
 
 // Fetch all customers with automatic pagination
 // Fetch all customers with automatic pagination
-export async function fetchAllCustomers(storeId: string): Promise<ShopifyCustomer[]> {
+export async function fetchAllCustomers(
+  storeId: string,
+  filters?: ShopifyCustomerFilters
+): Promise<ShopifyCustomer[]> {
   const allCustomers: ShopifyCustomer[] = []
   const allCustomers: ShopifyCustomer[] = []
   let sinceId: number | undefined = undefined
   let sinceId: number | undefined = undefined
   let hasMore = true
   let hasMore = true
 
 
   while (hasMore) {
   while (hasMore) {
-    const customers = await fetchCustomers(storeId, 250, sinceId)
+    const customers = await fetchCustomers(storeId, 250, sinceId, filters)
 
 
     if (customers.length === 0) {
     if (customers.length === 0) {
       hasMore = false
       hasMore = false

+ 66 - 12
supabase/functions/_shared/shoprenter-client.ts

@@ -233,22 +233,76 @@ export async function fetchProducts(storeId: string, page: number = 1, limit: nu
   )
   )
 }
 }
 
 
+export interface ShopRenterOrderFilters {
+  status?: string;           // Filter by order status
+  customer_email?: string;   // Filter by customer email
+  customer_name?: string;    // Filter by customer name
+  created_from?: string;     // ISO 8601 datetime
+  created_to?: string;       // ISO 8601 datetime
+  updated_from?: string;     // ISO 8601 datetime
+  updated_to?: string;       // ISO 8601 datetime
+}
+
+export interface ShopRenterCustomerFilters {
+  email?: string;    // Filter by customer email
+  search?: string;   // Search by name or email
+}
+
 // Fetch customers from ShopRenter
 // Fetch customers from ShopRenter
-export async function fetchCustomers(storeId: string, page: number = 1, limit: number = 25): Promise<any> {
-  return shopRenterApiRequest(
-    storeId,
-    `/customers?page=${page}&limit=${limit}`,
-    'GET'
-  )
+export async function fetchCustomers(
+  storeId: string,
+  page: number = 1,
+  limit: number = 25,
+  filters?: ShopRenterCustomerFilters
+): Promise<any> {
+  let endpoint = `/customers?page=${page}&limit=${limit}`
+
+  if (filters) {
+    if (filters.email) {
+      endpoint += `&email=${encodeURIComponent(filters.email)}`
+    }
+    if (filters.search) {
+      endpoint += `&search=${encodeURIComponent(filters.search)}`
+    }
+  }
+
+  return shopRenterApiRequest(storeId, endpoint, 'GET')
 }
 }
 
 
 // Fetch orders from ShopRenter
 // Fetch orders from ShopRenter
-export async function fetchOrders(storeId: string, page: number = 1, limit: number = 25): Promise<any> {
-  return shopRenterApiRequest(
-    storeId,
-    `/orders?page=${page}&limit=${limit}`,
-    'GET'
-  )
+export async function fetchOrders(
+  storeId: string,
+  page: number = 1,
+  limit: number = 25,
+  filters?: ShopRenterOrderFilters
+): Promise<any> {
+  let endpoint = `/orders?page=${page}&limit=${limit}`
+
+  if (filters) {
+    if (filters.status) {
+      endpoint += `&status=${filters.status}`
+    }
+    if (filters.customer_email) {
+      endpoint += `&customer_email=${encodeURIComponent(filters.customer_email)}`
+    }
+    if (filters.customer_name) {
+      endpoint += `&customer_name=${encodeURIComponent(filters.customer_name)}`
+    }
+    if (filters.created_from) {
+      endpoint += `&created_from=${encodeURIComponent(filters.created_from)}`
+    }
+    if (filters.created_to) {
+      endpoint += `&created_to=${encodeURIComponent(filters.created_to)}`
+    }
+    if (filters.updated_from) {
+      endpoint += `&updated_from=${encodeURIComponent(filters.updated_from)}`
+    }
+    if (filters.updated_to) {
+      endpoint += `&updated_to=${encodeURIComponent(filters.updated_to)}`
+    }
+  }
+
+  return shopRenterApiRequest(storeId, endpoint, 'GET')
 }
 }
 
 
 // Register webhook
 // Register webhook

+ 50 - 9
supabase/functions/_shared/woocommerce-client.ts

@@ -242,16 +242,44 @@ export async function fetchProduct(storeId: string, productId: number): Promise<
 }
 }
 
 
 // Fetch orders from WooCommerce
 // Fetch orders from WooCommerce
+export interface WooCommerceOrderFilters {
+  status?: string;
+  customer?: string;  // Customer ID or email
+  after?: string;     // ISO 8601 datetime - created after
+  before?: string;    // ISO 8601 datetime - created before
+  modified_after?: string;  // ISO 8601 datetime - modified after
+  modified_before?: string; // ISO 8601 datetime - modified before
+}
+
 export async function fetchOrders(
 export async function fetchOrders(
   storeId: string,
   storeId: string,
   page: number = 1,
   page: number = 1,
   perPage: number = 25,
   perPage: number = 25,
-  status?: string
+  filters?: WooCommerceOrderFilters
 ): Promise<WooCommerceOrder[]> {
 ): Promise<WooCommerceOrder[]> {
   let endpoint = `/orders?page=${page}&per_page=${perPage}`
   let endpoint = `/orders?page=${page}&per_page=${perPage}`
-  if (status) {
-    endpoint += `&status=${status}`
+
+  if (filters) {
+    if (filters.status) {
+      endpoint += `&status=${filters.status}`
+    }
+    if (filters.customer) {
+      endpoint += `&customer=${encodeURIComponent(filters.customer)}`
+    }
+    if (filters.after) {
+      endpoint += `&after=${encodeURIComponent(filters.after)}`
+    }
+    if (filters.before) {
+      endpoint += `&before=${encodeURIComponent(filters.before)}`
+    }
+    if (filters.modified_after) {
+      endpoint += `&modified_after=${encodeURIComponent(filters.modified_after)}`
+    }
+    if (filters.modified_before) {
+      endpoint += `&modified_before=${encodeURIComponent(filters.modified_before)}`
+    }
   }
   }
+
   return wooCommerceApiRequest(storeId, endpoint, 'GET')
   return wooCommerceApiRequest(storeId, endpoint, 'GET')
 }
 }
 
 
@@ -260,17 +288,30 @@ export async function fetchOrder(storeId: string, orderId: number): Promise<WooC
   return wooCommerceApiRequest(storeId, `/orders/${orderId}`, 'GET')
   return wooCommerceApiRequest(storeId, `/orders/${orderId}`, 'GET')
 }
 }
 
 
+export interface WooCommerceCustomerFilters {
+  email?: string;    // Filter by customer email
+  search?: string;   // Search by customer name or email
+}
+
 // Fetch customers from WooCommerce
 // Fetch customers from WooCommerce
 export async function fetchCustomers(
 export async function fetchCustomers(
   storeId: string,
   storeId: string,
   page: number = 1,
   page: number = 1,
-  perPage: number = 25
+  perPage: number = 25,
+  filters?: WooCommerceCustomerFilters
 ): Promise<WooCommerceCustomer[]> {
 ): Promise<WooCommerceCustomer[]> {
-  return wooCommerceApiRequest(
-    storeId,
-    `/customers?page=${page}&per_page=${perPage}`,
-    'GET'
-  )
+  let endpoint = `/customers?page=${page}&per_page=${perPage}`
+
+  if (filters) {
+    if (filters.email) {
+      endpoint += `&email=${encodeURIComponent(filters.email)}`
+    }
+    if (filters.search) {
+      endpoint += `&search=${encodeURIComponent(filters.search)}`
+    }
+  }
+
+  return wooCommerceApiRequest(storeId, endpoint, 'GET')
 }
 }
 
 
 // Fetch a single customer
 // Fetch a single customer

+ 172 - 141
supabase/functions/mcp-shopify/index.ts

@@ -17,9 +17,11 @@ import {
 } from '../_shared/internal-api-key-auth.ts';
 } from '../_shared/internal-api-key-auth.ts';
 import {
 import {
   fetchAllOrders,
   fetchAllOrders,
-  fetchAllCustomers,
+  fetchCustomers,
   ShopifyOrder,
   ShopifyOrder,
-  ShopifyCustomer
+  ShopifyCustomer,
+  ShopifyOrderFilters,
+  ShopifyCustomerFilters
 } from '../_shared/shopify-client.ts';
 } from '../_shared/shopify-client.ts';
 import {
 import {
   McpTool,
   McpTool,
@@ -27,8 +29,6 @@ import {
   LlmOrder
   LlmOrder
 } from '../_shared/mcp-types.ts';
 } from '../_shared/mcp-types.ts';
 import {
 import {
-  createMcpErrorResponse,
-  createMcpSuccessResponse,
   validateParams
   validateParams
 } from '../_shared/mcp-helpers.ts';
 } from '../_shared/mcp-helpers.ts';
 import {
 import {
@@ -53,70 +53,76 @@ const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
 const supabase = createClient(supabaseUrl, supabaseServiceKey);
 const supabase = createClient(supabaseUrl, supabaseServiceKey);
 
 
 const SERVER_NAME = 'mcp-shopify';
 const SERVER_NAME = 'mcp-shopify';
-const SERVER_VERSION = '1.0.0';
+const SERVER_VERSION = '2.0.0';
 
 
 // MCP Tool Definitions
 // MCP Tool Definitions
 const TOOLS: McpTool[] = [
 const TOOLS: McpTool[] = [
-    {
-      name: 'shopify_list_orders',
-      description: 'List orders from a Shopify store. Returns order details including customer info, items, status, and totals.',
-      inputSchema: {
-        type: 'object',
-        properties: {
-          shop_id: {
-            type: 'string',
-            description: 'The UUID of the Shopify store from the stores table'
-          },
-          status: {
-            type: 'string',
-            description: 'Filter by order status: any (default), open, closed, cancelled',
-            enum: ['any', 'open', 'closed', 'cancelled']
-          },
-          limit: {
-            type: 'number',
-            description: 'Maximum number of orders to return (default: 50, max: 250)'
-          }
+  {
+    name: 'shopify_list_orders',
+    description: 'List orders from a Shopify store with filtering. At least one filter is REQUIRED (created_at_min, created_at_max, updated_at_min, updated_at_max, customer_email, or customer_name). Returns order details including customer info, items, status, and totals. Limited to 20 results maximum.',
+    inputSchema: {
+      type: 'object',
+      properties: {
+        shop_id: {
+          type: 'string',
+          description: 'The UUID of the Shopify store from the stores table'
         },
         },
-        required: ['shop_id']
-      }
-    },
-    {
-      name: 'shopify_list_customers',
-      description: 'List customers from a Shopify store. Returns customer details including contact info, order count, and total spent.',
-      inputSchema: {
-        type: 'object',
-        properties: {
-          shop_id: {
-            type: 'string',
-            description: 'The UUID of the Shopify store from the stores table'
-          },
-          limit: {
-            type: 'number',
-            description: 'Maximum number of customers to return (default: 50, max: 250)'
-          }
+        created_at_min: {
+          type: 'string',
+          description: 'Filter orders created after this ISO 8601 datetime (e.g., 2025-01-01T00:00:00Z)'
         },
         },
-        required: ['shop_id']
-      }
-    },
-    {
-      name: 'shopify_get_customer_orders',
-      description: 'Get all orders for a specific customer by customer ID. Returns detailed order history.',
-      inputSchema: {
-        type: 'object',
-        properties: {
-          shop_id: {
-            type: 'string',
-            description: 'The UUID of the Shopify store from the stores table'
-          },
-          customer_id: {
-            type: 'string',
-            description: 'The Shopify customer ID'
-          }
+        created_at_max: {
+          type: 'string',
+          description: 'Filter orders created before this ISO 8601 datetime'
         },
         },
-        required: ['shop_id', 'customer_id']
-      }
+        updated_at_min: {
+          type: 'string',
+          description: 'Filter orders updated after this ISO 8601 datetime'
+        },
+        updated_at_max: {
+          type: 'string',
+          description: 'Filter orders updated before this ISO 8601 datetime'
+        },
+        customer_email: {
+          type: 'string',
+          description: 'Filter by customer email address'
+        },
+        customer_name: {
+          type: 'string',
+          description: 'Filter by customer name'
+        },
+        status: {
+          type: 'string',
+          description: 'Filter by order status: any, open, closed, cancelled',
+          enum: ['any', 'open', 'closed', 'cancelled']
+        },
+        limit: {
+          type: 'number',
+          description: 'Number of orders to return (default: 5, max: 20)'
+        }
+      },
+      required: ['shop_id']
+    }
+  },
+  {
+    name: 'shopify_get_customer',
+    description: 'Get a specific customer from a Shopify store by email address. Returns a single customer with contact info, order count, and total spent. Email parameter is REQUIRED.',
+    inputSchema: {
+      type: 'object',
+      properties: {
+        shop_id: {
+          type: 'string',
+          description: 'The UUID of the Shopify store from the stores table'
+        },
+        email: {
+          type: 'string',
+          description: 'The customer email address (required)'
+        }
+      },
+      required: ['shop_id', 'email']
     }
     }
-  ];
+  }
+];
 
 
 /**
 /**
  * Convert Shopify customer to LLM-friendly format
  * Convert Shopify customer to LLM-friendly format
@@ -160,7 +166,34 @@ function formatOrderForLlm(order: ShopifyOrder): LlmOrder {
  * Handle shopify_list_orders tool
  * Handle shopify_list_orders tool
  */
  */
 async function handleListOrders(args: Record<string, any>): Promise<ToolCallResult> {
 async function handleListOrders(args: Record<string, any>): Promise<ToolCallResult> {
-  const { shop_id, status = 'any', limit = 50 } = args;
+  const {
+    shop_id,
+    created_at_min,
+    created_at_max,
+    updated_at_min,
+    updated_at_max,
+    customer_email,
+    customer_name,
+    status,
+    limit = 5
+  } = args;
+
+  // Validate at least one filter is provided
+  const hasFilter = created_at_min || created_at_max || updated_at_min || updated_at_max || customer_email || customer_name;
+  if (!hasFilter) {
+    return {
+      content: [{
+        type: 'text',
+        text: JSON.stringify({
+          error: 'At least one filter is required: created_at_min, created_at_max, updated_at_min, updated_at_max, customer_email, or customer_name'
+        })
+      }],
+      isError: true
+    };
+  }
+
+  // Enforce limit constraints
+  const actualLimit = Math.min(Math.max(1, limit), 20);
 
 
   // Validate shop exists and is Shopify
   // Validate shop exists and is Shopify
   const { data: store, error: storeError } = await supabase
   const { data: store, error: storeError } = await supabase
@@ -187,21 +220,41 @@ async function handleListOrders(args: Record<string, any>): Promise<ToolCallResu
   }
   }
 
 
   try {
   try {
+    // Build filters
+    const filters: ShopifyOrderFilters = {};
+    if (status) filters.status = status;
+    if (customer_email) filters.email = customer_email;
+    if (customer_name) filters.name = customer_name;
+    if (created_at_min) filters.created_at_min = created_at_min;
+    if (created_at_max) filters.created_at_max = created_at_max;
+    if (updated_at_min) filters.updated_at_min = updated_at_min;
+    if (updated_at_max) filters.updated_at_max = updated_at_max;
+
     // Fetch orders from Shopify API
     // Fetch orders from Shopify API
-    const allOrders = await fetchAllOrders(shop_id, status);
+    const allOrders = await fetchAllOrders(shop_id, filters);
 
 
     // Apply limit
     // Apply limit
-    const orders = allOrders.slice(0, Math.min(limit, 250));
+    const limitedOrders = allOrders.slice(0, actualLimit);
 
 
     // Format for LLM
     // Format for LLM
-    const formattedOrders = orders.map(formatOrderForLlm);
+    const formattedOrders = limitedOrders.map(formatOrderForLlm);
 
 
     return {
     return {
       content: [{
       content: [{
         type: 'text',
         type: 'text',
         text: JSON.stringify({
         text: JSON.stringify({
           count: formattedOrders.length,
           count: formattedOrders.length,
-          total: allOrders.length,
+          limit: actualLimit,
+          total_available: allOrders.length,
+          filters_applied: {
+            created_at_min,
+            created_at_max,
+            updated_at_min,
+            updated_at_max,
+            customer_email,
+            customer_name,
+            status
+          },
           orders: formattedOrders
           orders: formattedOrders
         })
         })
       }]
       }]
@@ -221,74 +274,23 @@ async function handleListOrders(args: Record<string, any>): Promise<ToolCallResu
 }
 }
 
 
 /**
 /**
- * Handle shopify_list_customers tool
+ * Handle shopify_get_customer tool (replaces list_customers)
  */
  */
-async function handleListCustomers(args: Record<string, any>): Promise<ToolCallResult> {
-  const { shop_id, limit = 50 } = args;
-
-  // Validate shop exists and is Shopify
-  const { data: store, error: storeError } = await supabase
-    .from('stores')
-    .select('id, platform_name, data_access_permissions')
-    .eq('id', shop_id)
-    .eq('platform_name', 'shopify')
-    .single();
-
-  if (storeError || !store) {
-    return {
-      content: [{ type: 'text', text: JSON.stringify({ error: 'Shopify store not found' }) }],
-      isError: true
-    };
-  }
+async function handleGetCustomer(args: Record<string, any>): Promise<ToolCallResult> {
+  const { shop_id, email } = args;
 
 
-  // Check permissions
-  const permissions = store.data_access_permissions as any;
-  if (permissions && !permissions.allow_customer_access) {
-    return {
-      content: [{ type: 'text', text: JSON.stringify({ error: 'Customer access not allowed for this store' }) }],
-      isError: true
-    };
-  }
-
-  try {
-    // Fetch customers from Shopify API
-    const allCustomers = await fetchAllCustomers(shop_id);
-
-    // Apply limit
-    const customers = allCustomers.slice(0, Math.min(limit, 250));
-
-    // Format for LLM
-    const formattedCustomers = customers.map(formatCustomerForLlm);
-
-    return {
-      content: [{
-        type: 'text',
-        text: JSON.stringify({
-          count: formattedCustomers.length,
-          total: allCustomers.length,
-          customers: formattedCustomers
-        })
-      }]
-    };
-  } catch (error) {
-    console.error('[MCP Shopify] Error fetching customers:', error);
+  // Validate email is provided
+  if (!email) {
     return {
     return {
       content: [{
       content: [{
         type: 'text',
         type: 'text',
         text: JSON.stringify({
         text: JSON.stringify({
-          error: `Failed to fetch customers: ${error instanceof Error ? error.message : 'Unknown error'}`
+          error: 'Email parameter is required'
         })
         })
       }],
       }],
       isError: true
       isError: true
     };
     };
   }
   }
-}
-
-/**
- * Handle shopify_get_customer_orders tool
- */
-async function handleGetCustomerOrders(args: Record<string, any>): Promise<ToolCallResult> {
-  const { shop_id, customer_id } = args;
 
 
   // Validate shop exists and is Shopify
   // Validate shop exists and is Shopify
   const { data: store, error: storeError } = await supabase
   const { data: store, error: storeError } = await supabase
@@ -307,38 +309,47 @@ async function handleGetCustomerOrders(args: Record<string, any>): Promise<ToolC
 
 
   // Check permissions
   // Check permissions
   const permissions = store.data_access_permissions as any;
   const permissions = store.data_access_permissions as any;
-  if (permissions && (!permissions.allow_order_access || !permissions.allow_customer_access)) {
+  if (permissions && !permissions.allow_customer_access) {
     return {
     return {
-      content: [{ type: 'text', text: JSON.stringify({ error: 'Order and customer access required' }) }],
+      content: [{ type: 'text', text: JSON.stringify({ error: 'Customer access not allowed for this store' }) }],
       isError: true
       isError: true
     };
     };
   }
   }
 
 
   try {
   try {
-    // Fetch all orders and filter by customer ID
-    const allOrders = await fetchAllOrders(shop_id);
-    const customerOrders = allOrders.filter(order => order.customer.id.toString() === customer_id);
+    // Fetch customer by email from Shopify API
+    const customers = await fetchCustomers(shop_id, 1, undefined, { email });
 
 
-    // Format for LLM
-    const formattedOrders = customerOrders.map(formatOrderForLlm);
+    if (customers.length === 0) {
+      return {
+        content: [{
+          type: 'text',
+          text: JSON.stringify({
+            error: `No customer found with email: ${email}`
+          })
+        }],
+        isError: true
+      };
+    }
+
+    // Return only the first customer
+    const customer = formatCustomerForLlm(customers[0]);
 
 
     return {
     return {
       content: [{
       content: [{
         type: 'text',
         type: 'text',
         text: JSON.stringify({
         text: JSON.stringify({
-          customerId: customer_id,
-          count: formattedOrders.length,
-          orders: formattedOrders
+          customer
         })
         })
       }]
       }]
     };
     };
   } catch (error) {
   } catch (error) {
-    console.error('[MCP Shopify] Error fetching customer orders:', error);
+    console.error('[MCP Shopify] Error fetching customer:', error);
     return {
     return {
       content: [{
       content: [{
         type: 'text',
         type: 'text',
         text: JSON.stringify({
         text: JSON.stringify({
-          error: `Failed to fetch customer orders: ${error instanceof Error ? error.message : 'Unknown error'}`
+          error: `Failed to fetch customer: ${error instanceof Error ? error.message : 'Unknown error'}`
         })
         })
       }],
       }],
       isError: true
       isError: true
@@ -371,11 +382,8 @@ async function handleToolCall(params: ToolCallParams): Promise<ToolCallResult> {
     case 'shopify_list_orders':
     case 'shopify_list_orders':
       return await handleListOrders(args);
       return await handleListOrders(args);
 
 
-    case 'shopify_list_customers':
-      return await handleListCustomers(args);
-
-    case 'shopify_get_customer_orders':
-      const customerValidation = validateParams(args, ['shop_id', 'customer_id']);
+    case 'shopify_get_customer':
+      const customerValidation = validateParams(args, ['shop_id', 'email']);
       if (!customerValidation.valid) {
       if (!customerValidation.valid) {
         return {
         return {
           content: [{
           content: [{
@@ -387,7 +395,30 @@ async function handleToolCall(params: ToolCallParams): Promise<ToolCallResult> {
           isError: true
           isError: true
         };
         };
       }
       }
-      return await handleGetCustomerOrders(args);
+      return await handleGetCustomer(args);
+
+    // Legacy tool names for backward compatibility
+    case 'shopify_list_customers':
+      return {
+        content: [{
+          type: 'text',
+          text: JSON.stringify({
+            error: 'This tool has been removed. Use shopify_get_customer with email parameter instead.'
+          })
+        }],
+        isError: true
+      };
+
+    case 'shopify_get_customer_orders':
+      return {
+        content: [{
+          type: 'text',
+          text: JSON.stringify({
+            error: 'This tool has been removed. Use shopify_list_orders with customer_email filter instead.'
+          })
+        }],
+        isError: true
+      };
 
 
     default:
     default:
       return {
       return {

+ 175 - 150
supabase/functions/mcp-shoprenter/index.ts

@@ -19,7 +19,9 @@ import {
   fetchOrders,
   fetchOrders,
   fetchCustomers,
   fetchCustomers,
   ShopRenterOrder,
   ShopRenterOrder,
-  ShopRenterCustomer
+  ShopRenterCustomer,
+  ShopRenterOrderFilters,
+  ShopRenterCustomerFilters
 } from '../_shared/shoprenter-client.ts';
 } from '../_shared/shoprenter-client.ts';
 import {
 import {
   McpTool,
   McpTool,
@@ -27,6 +29,8 @@ import {
   LlmOrder
   LlmOrder
 } from '../_shared/mcp-types.ts';
 } from '../_shared/mcp-types.ts';
 import {
 import {
+  createMcpErrorResponse,
+  createMcpSuccessResponse,
   validateParams
   validateParams
 } from '../_shared/mcp-helpers.ts';
 } from '../_shared/mcp-helpers.ts';
 import {
 import {
@@ -51,13 +55,13 @@ const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
 const supabase = createClient(supabaseUrl, supabaseServiceKey);
 const supabase = createClient(supabaseUrl, supabaseServiceKey);
 
 
 const SERVER_NAME = 'mcp-shoprenter';
 const SERVER_NAME = 'mcp-shoprenter';
-const SERVER_VERSION = '1.0.0';
+const SERVER_VERSION = '2.0.0';
 
 
 // MCP Tool Definitions
 // MCP Tool Definitions
 const TOOLS: McpTool[] = [
 const TOOLS: McpTool[] = [
   {
   {
     name: 'shoprenter_list_orders',
     name: 'shoprenter_list_orders',
-    description: 'List orders from a ShopRenter store. Returns order details including customer info, items, status, and totals.',
+    description: 'List orders from a ShopRenter store with filtering. At least one filter is REQUIRED (created_from, created_to, updated_from, updated_to, customer_email, or customer_name). Returns order details including customer info, items, status, and totals. Limited to 20 results maximum.',
     inputSchema: {
     inputSchema: {
       type: 'object',
       type: 'object',
       properties: {
       properties: {
@@ -65,43 +69,45 @@ const TOOLS: McpTool[] = [
           type: 'string',
           type: 'string',
           description: 'The UUID of the ShopRenter store from the stores table'
           description: 'The UUID of the ShopRenter store from the stores table'
         },
         },
-        page: {
-          type: 'number',
-          description: 'Page number for pagination (default: 1)'
+        created_from: {
+          type: 'string',
+          description: 'Filter orders created after this ISO 8601 datetime (e.g., 2025-01-01T00:00:00Z)'
         },
         },
-        limit: {
-          type: 'number',
-          description: 'Number of orders per page (default: 25, max: 100)'
-        }
-      },
-      required: ['shop_id']
-    }
-  },
-  {
-    name: 'shoprenter_list_customers',
-    description: 'List customers from a ShopRenter store. Returns customer details including contact info and order history.',
-    inputSchema: {
-      type: 'object',
-      properties: {
-        shop_id: {
+        created_to: {
           type: 'string',
           type: 'string',
-          description: 'The UUID of the ShopRenter store from the stores table'
+          description: 'Filter orders created before this ISO 8601 datetime'
         },
         },
-        page: {
-          type: 'number',
-          description: 'Page number for pagination (default: 1)'
+        updated_from: {
+          type: 'string',
+          description: 'Filter orders updated after this ISO 8601 datetime'
+        },
+        updated_to: {
+          type: 'string',
+          description: 'Filter orders updated before this ISO 8601 datetime'
+        },
+        customer_email: {
+          type: 'string',
+          description: 'Filter by customer email address'
+        },
+        customer_name: {
+          type: 'string',
+          description: 'Filter by customer name (searches billing name)'
+        },
+        status: {
+          type: 'string',
+          description: 'Filter by order status: any, pending, processing, on-hold, completed, cancelled, refunded, failed'
         },
         },
         limit: {
         limit: {
           type: 'number',
           type: 'number',
-          description: 'Number of customers per page (default: 25, max: 100)'
+          description: 'Number of orders to return (default: 5, max: 20)'
         }
         }
       },
       },
       required: ['shop_id']
       required: ['shop_id']
     }
     }
   },
   },
   {
   {
-    name: 'shoprenter_get_customer_orders',
-    description: 'Get all orders for a specific customer by customer email. Returns detailed order history.',
+    name: 'shoprenter_get_customer',
+    description: 'Get a specific customer from a ShopRenter store by email address. Returns a single customer with contact info, order count, and total spent. Email parameter is REQUIRED.',
     inputSchema: {
     inputSchema: {
       type: 'object',
       type: 'object',
       properties: {
       properties: {
@@ -109,50 +115,38 @@ const TOOLS: McpTool[] = [
           type: 'string',
           type: 'string',
           description: 'The UUID of the ShopRenter store from the stores table'
           description: 'The UUID of the ShopRenter store from the stores table'
         },
         },
-        customer_email: {
+        email: {
           type: 'string',
           type: 'string',
-          description: 'The customer email address'
+          description: 'The customer email address (required)'
         }
         }
       },
       },
-      required: ['shop_id', 'customer_email']
+      required: ['shop_id', 'email']
     }
     }
   }
   }
 ];
 ];
 
 
-/**
- * Extract phone number from various ShopRenter structures
- */
-function extractPhone(data: any): string | undefined {
-  if (data?.phone) return data.phone;
-  if (data?.billing_address?.phone) return data.billing_address.phone;
-  if (data?.shipping_address?.phone) return data.shipping_address.phone;
-  return undefined;
-}
-
 /**
 /**
  * Convert ShopRenter customer to LLM-friendly format
  * Convert ShopRenter customer to LLM-friendly format
  */
  */
-function formatCustomerForLlm(customer: ShopRenterCustomer): LlmCustomer {
+function formatCustomerForLlm(customer: any): LlmCustomer {
   return {
   return {
-    id: customer.id,
-    name: `${customer.firstname} ${customer.lastname}`.trim(),
+    id: customer.id || customer.customer_id,
+    name: `${customer.firstname || customer.first_name || ''} ${customer.lastname || customer.last_name || ''}`.trim(),
     email: customer.email,
     email: customer.email,
-    phone: customer.phone || undefined
+    phone: customer.phone || undefined,
+    ordersCount: customer.orders_count || undefined,
+    totalSpent: customer.total_spent || undefined
   };
   };
 }
 }
 
 
 /**
 /**
  * Convert ShopRenter order to LLM-friendly format
  * Convert ShopRenter order to LLM-friendly format
  */
  */
-function formatOrderForLlm(order: ShopRenterOrder): LlmOrder {
-  // Extract customer name and email
+function formatOrderForLlm(order: any): LlmOrder {
   const customerName = order.customer_name ||
   const customerName = order.customer_name ||
     (order.customer ? `${order.customer.firstname || ''} ${order.customer.lastname || ''}`.trim() : 'Unknown');
     (order.customer ? `${order.customer.firstname || ''} ${order.customer.lastname || ''}`.trim() : 'Unknown');
   const customerEmail = order.customer_email || order.customer?.email || '';
   const customerEmail = order.customer_email || order.customer?.email || '';
-  const customerPhone = order.customer_phone ||
-    order.customer?.phone ||
-    extractPhone(order.billing_address) ||
-    extractPhone(order.shipping_address);
+  const customerPhone = order.customer_phone || order.customer?.phone || undefined;
 
 
   return {
   return {
     id: order.id,
     id: order.id,
@@ -163,7 +157,7 @@ function formatOrderForLlm(order: ShopRenterOrder): LlmOrder {
       phone: customerPhone
       phone: customerPhone
     },
     },
     status: order.status,
     status: order.status,
-    total: order.total,
+    total: order.total || '0',
     currency: order.currency || 'HUF',
     currency: order.currency || 'HUF',
     items: (order.items || order.line_items || []).map((item: any) => ({
     items: (order.items || order.line_items || []).map((item: any) => ({
       name: item.name || item.product_name || 'Unknown',
       name: item.name || item.product_name || 'Unknown',
@@ -175,31 +169,27 @@ function formatOrderForLlm(order: ShopRenterOrder): LlmOrder {
 }
 }
 
 
 /**
 /**
- * Fetch all orders with pagination
+ * Fetch all orders with pagination (for filtering by customer name)
  */
  */
 async function fetchAllOrdersPages(
 async function fetchAllOrdersPages(
   shop_id: string,
   shop_id: string,
-  maxPages: number = 10
+  maxPages: number = 10,
+  filters?: ShopRenterOrderFilters
 ): Promise<any[]> {
 ): Promise<any[]> {
   const allOrders: any[] = [];
   const allOrders: any[] = [];
   let page = 1;
   let page = 1;
   let hasMore = true;
   let hasMore = true;
 
 
   while (hasMore && page <= maxPages) {
   while (hasMore && page <= maxPages) {
-    try {
-      const response = await fetchOrders(shop_id, page, 100);
-      const orders = Array.isArray(response) ? response : (response.data || response.orders || []);
-
-      if (orders.length === 0) {
-        hasMore = false;
-      } else {
-        allOrders.push(...orders);
-        hasMore = orders.length === 100; // If we got max results, there might be more
-        page++;
-      }
-    } catch (error) {
-      console.error(`[MCP ShopRenter] Error fetching page ${page}:`, error);
+    const response = await fetchOrders(shop_id, page, 100, filters);
+    const orders = Array.isArray(response) ? response : (response.data || response.orders || []);
+
+    if (orders.length === 0) {
       hasMore = false;
       hasMore = false;
+    } else {
+      allOrders.push(...orders);
+      hasMore = orders.length === 100;
+      page++;
     }
     }
   }
   }
 
 
@@ -210,7 +200,34 @@ async function fetchAllOrdersPages(
  * Handle shoprenter_list_orders tool
  * Handle shoprenter_list_orders tool
  */
  */
 async function handleListOrders(args: Record<string, any>): Promise<ToolCallResult> {
 async function handleListOrders(args: Record<string, any>): Promise<ToolCallResult> {
-  const { shop_id, page = 1, limit = 25 } = args;
+  const {
+    shop_id,
+    created_from,
+    created_to,
+    updated_from,
+    updated_to,
+    customer_email,
+    customer_name,
+    status,
+    limit = 5
+  } = args;
+
+  // Validate at least one filter is provided
+  const hasFilter = created_from || created_to || updated_from || updated_to || customer_email || customer_name;
+  if (!hasFilter) {
+    return {
+      content: [{
+        type: 'text',
+        text: JSON.stringify({
+          error: 'At least one filter is required: created_from, created_to, updated_from, updated_to, customer_email, or customer_name'
+        })
+      }],
+      isError: true
+    };
+  }
+
+  // Enforce limit constraints
+  const actualLimit = Math.min(Math.max(1, limit), 20);
 
 
   // Validate shop exists and is ShopRenter
   // Validate shop exists and is ShopRenter
   const { data: store, error: storeError } = await supabase
   const { data: store, error: storeError } = await supabase
@@ -237,20 +254,51 @@ async function handleListOrders(args: Record<string, any>): Promise<ToolCallResu
   }
   }
 
 
   try {
   try {
+    // Build filters
+    const filters: ShopRenterOrderFilters = {};
+    if (status) filters.status = status;
+    if (customer_email) filters.customer_email = customer_email;
+    if (created_from) filters.created_from = created_from;
+    if (created_to) filters.created_to = created_to;
+    if (updated_from) filters.updated_from = updated_from;
+    if (updated_to) filters.updated_to = updated_to;
+
     // Fetch orders from ShopRenter API
     // Fetch orders from ShopRenter API
-    const response = await fetchOrders(shop_id, page, Math.min(limit, 100));
-    const orders = Array.isArray(response) ? response : (response.data || response.orders || []);
+    let orders: any[];
+
+    if (customer_name) {
+      // If filtering by customer name, we need to fetch and filter locally
+      // because ShopRenter doesn't support name filtering directly
+      filters.customer_name = customer_name;
+      const response = await fetchOrders(shop_id, 1, actualLimit, filters);
+      orders = Array.isArray(response) ? response : (response.data || response.orders || []);
+    } else {
+      // Direct API fetch with filters
+      const response = await fetchOrders(shop_id, 1, actualLimit, filters);
+      orders = Array.isArray(response) ? response : (response.data || response.orders || []);
+    }
+
+    // Apply limit
+    const limitedOrders = orders.slice(0, actualLimit);
 
 
     // Format for LLM
     // Format for LLM
-    const formattedOrders = orders.map(formatOrderForLlm);
+    const formattedOrders = limitedOrders.map(formatOrderForLlm);
 
 
     return {
     return {
       content: [{
       content: [{
         type: 'text',
         type: 'text',
         text: JSON.stringify({
         text: JSON.stringify({
           count: formattedOrders.length,
           count: formattedOrders.length,
-          page,
-          limit,
+          limit: actualLimit,
+          filters_applied: {
+            created_from,
+            created_to,
+            updated_from,
+            updated_to,
+            customer_email,
+            customer_name,
+            status
+          },
           orders: formattedOrders
           orders: formattedOrders
         })
         })
       }]
       }]
@@ -270,73 +318,23 @@ async function handleListOrders(args: Record<string, any>): Promise<ToolCallResu
 }
 }
 
 
 /**
 /**
- * Handle shoprenter_list_customers tool
+ * Handle shoprenter_get_customer tool (replaces list_customers)
  */
  */
-async function handleListCustomers(args: Record<string, any>): Promise<ToolCallResult> {
-  const { shop_id, page = 1, limit = 25 } = args;
-
-  // Validate shop exists and is ShopRenter
-  const { data: store, error: storeError } = await supabase
-    .from('stores')
-    .select('id, platform_name, data_access_permissions')
-    .eq('id', shop_id)
-    .eq('platform_name', 'shoprenter')
-    .single();
-
-  if (storeError || !store) {
-    return {
-      content: [{ type: 'text', text: JSON.stringify({ error: 'ShopRenter store not found' }) }],
-      isError: true
-    };
-  }
-
-  // Check permissions
-  const permissions = store.data_access_permissions as any;
-  if (permissions && !permissions.allow_customer_access) {
-    return {
-      content: [{ type: 'text', text: JSON.stringify({ error: 'Customer access not allowed for this store' }) }],
-      isError: true
-    };
-  }
-
-  try {
-    // Fetch customers from ShopRenter API
-    const response = await fetchCustomers(shop_id, page, Math.min(limit, 100));
-    const customers = Array.isArray(response) ? response : (response.data || response.customers || []);
-
-    // Format for LLM
-    const formattedCustomers = customers.map(formatCustomerForLlm);
+async function handleGetCustomer(args: Record<string, any>): Promise<ToolCallResult> {
+  const { shop_id, email } = args;
 
 
+  // Validate email is provided
+  if (!email) {
     return {
     return {
       content: [{
       content: [{
         type: 'text',
         type: 'text',
         text: JSON.stringify({
         text: JSON.stringify({
-          count: formattedCustomers.length,
-          page,
-          limit,
-          customers: formattedCustomers
-        })
-      }]
-    };
-  } catch (error) {
-    console.error('[MCP ShopRenter] Error fetching customers:', error);
-    return {
-      content: [{
-        type: 'text',
-        text: JSON.stringify({
-          error: `Failed to fetch customers: ${error instanceof Error ? error.message : 'Unknown error'}`
+          error: 'Email parameter is required'
         })
         })
       }],
       }],
       isError: true
       isError: true
     };
     };
   }
   }
-}
-
-/**
- * Handle shoprenter_get_customer_orders tool
- */
-async function handleGetCustomerOrders(args: Record<string, any>): Promise<ToolCallResult> {
-  const { shop_id, customer_email } = args;
 
 
   // Validate shop exists and is ShopRenter
   // Validate shop exists and is ShopRenter
   const { data: store, error: storeError } = await supabase
   const { data: store, error: storeError } = await supabase
@@ -355,41 +353,48 @@ async function handleGetCustomerOrders(args: Record<string, any>): Promise<ToolC
 
 
   // Check permissions
   // Check permissions
   const permissions = store.data_access_permissions as any;
   const permissions = store.data_access_permissions as any;
-  if (permissions && (!permissions.allow_order_access || !permissions.allow_customer_access)) {
+  if (permissions && !permissions.allow_customer_access) {
     return {
     return {
-      content: [{ type: 'text', text: JSON.stringify({ error: 'Order and customer access required' }) }],
+      content: [{ type: 'text', text: JSON.stringify({ error: 'Customer access not allowed for this store' }) }],
       isError: true
       isError: true
     };
     };
   }
   }
 
 
   try {
   try {
-    // Fetch orders and filter by customer email
-    const allOrders = await fetchAllOrdersPages(shop_id, 10);
-    const customerOrders = allOrders.filter(order => {
-      const orderEmail = order.customer_email || order.customer?.email || '';
-      return orderEmail.toLowerCase() === customer_email.toLowerCase();
-    });
+    // Fetch customer by email from ShopRenter API
+    const response = await fetchCustomers(shop_id, 1, 1, { email });
+    const customers = Array.isArray(response) ? response : (response.data || response.customers || []);
 
 
-    // Format for LLM
-    const formattedOrders = customerOrders.map(formatOrderForLlm);
+    if (customers.length === 0) {
+      return {
+        content: [{
+          type: 'text',
+          text: JSON.stringify({
+            error: `No customer found with email: ${email}`
+          })
+        }],
+        isError: true
+      };
+    }
+
+    // Return only the first customer
+    const customer = formatCustomerForLlm(customers[0]);
 
 
     return {
     return {
       content: [{
       content: [{
         type: 'text',
         type: 'text',
         text: JSON.stringify({
         text: JSON.stringify({
-          customerEmail: customer_email,
-          count: formattedOrders.length,
-          orders: formattedOrders
+          customer
         })
         })
       }]
       }]
     };
     };
   } catch (error) {
   } catch (error) {
-    console.error('[MCP ShopRenter] Error fetching customer orders:', error);
+    console.error('[MCP ShopRenter] Error fetching customer:', error);
     return {
     return {
       content: [{
       content: [{
         type: 'text',
         type: 'text',
         text: JSON.stringify({
         text: JSON.stringify({
-          error: `Failed to fetch customer orders: ${error instanceof Error ? error.message : 'Unknown error'}`
+          error: `Failed to fetch customer: ${error instanceof Error ? error.message : 'Unknown error'}`
         })
         })
       }],
       }],
       isError: true
       isError: true
@@ -422,11 +427,8 @@ async function handleToolCall(params: ToolCallParams): Promise<ToolCallResult> {
     case 'shoprenter_list_orders':
     case 'shoprenter_list_orders':
       return await handleListOrders(args);
       return await handleListOrders(args);
 
 
-    case 'shoprenter_list_customers':
-      return await handleListCustomers(args);
-
-    case 'shoprenter_get_customer_orders':
-      const customerValidation = validateParams(args, ['shop_id', 'customer_email']);
+    case 'shoprenter_get_customer':
+      const customerValidation = validateParams(args, ['shop_id', 'email']);
       if (!customerValidation.valid) {
       if (!customerValidation.valid) {
         return {
         return {
           content: [{
           content: [{
@@ -438,7 +440,30 @@ async function handleToolCall(params: ToolCallParams): Promise<ToolCallResult> {
           isError: true
           isError: true
         };
         };
       }
       }
-      return await handleGetCustomerOrders(args);
+      return await handleGetCustomer(args);
+
+    // Legacy tool names for backward compatibility
+    case 'shoprenter_list_customers':
+      return {
+        content: [{
+          type: 'text',
+          text: JSON.stringify({
+            error: 'This tool has been removed. Use shoprenter_get_customer with email parameter instead.'
+          })
+        }],
+        isError: true
+      };
+
+    case 'shoprenter_get_customer_orders':
+      return {
+        content: [{
+          type: 'text',
+          text: JSON.stringify({
+            error: 'This tool has been removed. Use shoprenter_list_orders with customer_email filter instead.'
+          })
+        }],
+        isError: true
+      };
 
 
     default:
     default:
       return {
       return {

+ 156 - 117
supabase/functions/mcp-woocommerce/index.ts

@@ -19,7 +19,9 @@ import {
   fetchOrders,
   fetchOrders,
   fetchCustomers,
   fetchCustomers,
   WooCommerceOrder,
   WooCommerceOrder,
-  WooCommerceCustomer
+  WooCommerceCustomer,
+  WooCommerceOrderFilters,
+  WooCommerceCustomerFilters
 } from '../_shared/woocommerce-client.ts';
 } from '../_shared/woocommerce-client.ts';
 import {
 import {
   McpTool,
   McpTool,
@@ -53,13 +55,13 @@ const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
 const supabase = createClient(supabaseUrl, supabaseServiceKey);
 const supabase = createClient(supabaseUrl, supabaseServiceKey);
 
 
 const SERVER_NAME = 'mcp-woocommerce';
 const SERVER_NAME = 'mcp-woocommerce';
-const SERVER_VERSION = '1.0.0';
+const SERVER_VERSION = '2.0.0';
 
 
 // MCP Tool Definitions
 // MCP Tool Definitions
 const TOOLS: McpTool[] = [
 const TOOLS: McpTool[] = [
   {
   {
     name: 'woocommerce_list_orders',
     name: 'woocommerce_list_orders',
-    description: 'List orders from a WooCommerce store. Returns order details including customer info, items, status, and totals.',
+    description: 'List orders from a WooCommerce store with filtering. At least one filter is REQUIRED (created_after, created_before, updated_after, updated_before, customer_email, or customer_name). Returns order details including customer info, items, status, and totals. Limited to 20 results maximum.',
     inputSchema: {
     inputSchema: {
       type: 'object',
       type: 'object',
       properties: {
       properties: {
@@ -67,47 +69,45 @@ const TOOLS: McpTool[] = [
           type: 'string',
           type: 'string',
           description: 'The UUID of the WooCommerce store from the stores table'
           description: 'The UUID of the WooCommerce store from the stores table'
         },
         },
-        status: {
+        created_after: {
           type: 'string',
           type: 'string',
-          description: 'Filter by order status: any, pending, processing, on-hold, completed, cancelled, refunded, failed'
+          description: 'Filter orders created after this ISO 8601 datetime (e.g., 2025-01-01T00:00:00Z)'
         },
         },
-        page: {
-          type: 'number',
-          description: 'Page number for pagination (default: 1)'
+        created_before: {
+          type: 'string',
+          description: 'Filter orders created before this ISO 8601 datetime'
         },
         },
-        per_page: {
-          type: 'number',
-          description: 'Number of orders per page (default: 25, max: 100)'
-        }
-      },
-      required: ['shop_id']
-    }
-  },
-  {
-    name: 'woocommerce_list_customers',
-    description: 'List customers from a WooCommerce store. Returns customer details including contact info, order count, and total spent.',
-    inputSchema: {
-      type: 'object',
-      properties: {
-        shop_id: {
+        updated_after: {
           type: 'string',
           type: 'string',
-          description: 'The UUID of the WooCommerce store from the stores table'
+          description: 'Filter orders updated after this ISO 8601 datetime'
         },
         },
-        page: {
-          type: 'number',
-          description: 'Page number for pagination (default: 1)'
+        updated_before: {
+          type: 'string',
+          description: 'Filter orders updated before this ISO 8601 datetime'
+        },
+        customer_email: {
+          type: 'string',
+          description: 'Filter by customer email address'
+        },
+        customer_name: {
+          type: 'string',
+          description: 'Filter by customer name (searches billing name)'
         },
         },
-        per_page: {
+        status: {
+          type: 'string',
+          description: 'Filter by order status: any, pending, processing, on-hold, completed, cancelled, refunded, failed'
+        },
+        limit: {
           type: 'number',
           type: 'number',
-          description: 'Number of customers per page (default: 25, max: 100)'
+          description: 'Number of orders to return (default: 5, max: 20)'
         }
         }
       },
       },
       required: ['shop_id']
       required: ['shop_id']
     }
     }
   },
   },
   {
   {
-    name: 'woocommerce_get_customer_orders',
-    description: 'Get all orders for a specific customer by customer email. Returns detailed order history.',
+    name: 'woocommerce_get_customer',
+    description: 'Get a specific customer from a WooCommerce store by email address. Returns a single customer with contact info, order count, and total spent. Email parameter is REQUIRED.',
     inputSchema: {
     inputSchema: {
       type: 'object',
       type: 'object',
       properties: {
       properties: {
@@ -115,12 +115,12 @@ const TOOLS: McpTool[] = [
           type: 'string',
           type: 'string',
           description: 'The UUID of the WooCommerce store from the stores table'
           description: 'The UUID of the WooCommerce store from the stores table'
         },
         },
-        customer_email: {
+        email: {
           type: 'string',
           type: 'string',
-          description: 'The customer email address'
+          description: 'The customer email address (required)'
         }
         }
       },
       },
-      required: ['shop_id', 'customer_email']
+      required: ['shop_id', 'email']
     }
     }
   }
   }
 ];
 ];
@@ -164,19 +164,19 @@ function formatOrderForLlm(order: WooCommerceOrder): LlmOrder {
 }
 }
 
 
 /**
 /**
- * Fetch all orders with pagination
+ * Fetch all orders with pagination (for filtering by customer name)
  */
  */
 async function fetchAllOrdersPages(
 async function fetchAllOrdersPages(
   shop_id: string,
   shop_id: string,
   maxPages: number = 10,
   maxPages: number = 10,
-  status?: string
+  filters?: WooCommerceOrderFilters
 ): Promise<WooCommerceOrder[]> {
 ): Promise<WooCommerceOrder[]> {
   const allOrders: WooCommerceOrder[] = [];
   const allOrders: WooCommerceOrder[] = [];
   let page = 1;
   let page = 1;
   let hasMore = true;
   let hasMore = true;
 
 
   while (hasMore && page <= maxPages) {
   while (hasMore && page <= maxPages) {
-    const orders = await fetchOrders(shop_id, page, 100, status);
+    const orders = await fetchOrders(shop_id, page, 100, filters);
 
 
     if (orders.length === 0) {
     if (orders.length === 0) {
       hasMore = false;
       hasMore = false;
@@ -194,7 +194,34 @@ async function fetchAllOrdersPages(
  * Handle woocommerce_list_orders tool
  * Handle woocommerce_list_orders tool
  */
  */
 async function handleListOrders(args: Record<string, any>): Promise<ToolCallResult> {
 async function handleListOrders(args: Record<string, any>): Promise<ToolCallResult> {
-  const { shop_id, status, page = 1, per_page = 25 } = args;
+  const {
+    shop_id,
+    created_after,
+    created_before,
+    updated_after,
+    updated_before,
+    customer_email,
+    customer_name,
+    status,
+    limit = 5
+  } = args;
+
+  // Validate at least one filter is provided
+  const hasFilter = created_after || created_before || updated_after || updated_before || customer_email || customer_name;
+  if (!hasFilter) {
+    return {
+      content: [{
+        type: 'text',
+        text: JSON.stringify({
+          error: 'At least one filter is required: created_after, created_before, updated_after, updated_before, customer_email, or customer_name'
+        })
+      }],
+      isError: true
+    };
+  }
+
+  // Enforce limit constraints
+  const actualLimit = Math.min(Math.max(1, limit), 20);
 
 
   // Validate shop exists and is WooCommerce
   // Validate shop exists and is WooCommerce
   const { data: store, error: storeError } = await supabase
   const { data: store, error: storeError } = await supabase
@@ -221,19 +248,53 @@ async function handleListOrders(args: Record<string, any>): Promise<ToolCallResu
   }
   }
 
 
   try {
   try {
+    // Build filters
+    const filters: WooCommerceOrderFilters = {};
+    if (status) filters.status = status;
+    if (customer_email) filters.customer = customer_email;
+    if (created_after) filters.after = created_after;
+    if (created_before) filters.before = created_before;
+    if (updated_after) filters.modified_after = updated_after;
+    if (updated_before) filters.modified_before = updated_before;
+
     // Fetch orders from WooCommerce API
     // Fetch orders from WooCommerce API
-    const orders = await fetchOrders(shop_id, page, Math.min(per_page, 100), status);
+    let orders: WooCommerceOrder[];
+
+    if (customer_name) {
+      // If filtering by customer name, we need to fetch and filter locally
+      // because WooCommerce doesn't support name filtering directly
+      const allOrders = await fetchAllOrdersPages(shop_id, 5, filters);
+      const lowerName = customer_name.toLowerCase();
+      orders = allOrders.filter(order => {
+        const fullName = `${order.billing.first_name} ${order.billing.last_name}`.toLowerCase();
+        return fullName.includes(lowerName);
+      });
+    } else {
+      // Direct API fetch with filters
+      orders = await fetchOrders(shop_id, 1, actualLimit, filters);
+    }
+
+    // Apply limit
+    const limitedOrders = orders.slice(0, actualLimit);
 
 
     // Format for LLM
     // Format for LLM
-    const formattedOrders = orders.map(formatOrderForLlm);
+    const formattedOrders = limitedOrders.map(formatOrderForLlm);
 
 
     return {
     return {
       content: [{
       content: [{
         type: 'text',
         type: 'text',
         text: JSON.stringify({
         text: JSON.stringify({
           count: formattedOrders.length,
           count: formattedOrders.length,
-          page,
-          per_page,
+          limit: actualLimit,
+          filters_applied: {
+            created_after,
+            created_before,
+            updated_after,
+            updated_before,
+            customer_email,
+            customer_name,
+            status
+          },
           orders: formattedOrders
           orders: formattedOrders
         })
         })
       }]
       }]
@@ -253,72 +314,23 @@ async function handleListOrders(args: Record<string, any>): Promise<ToolCallResu
 }
 }
 
 
 /**
 /**
- * Handle woocommerce_list_customers tool
+ * Handle woocommerce_get_customer tool (replaces list_customers)
  */
  */
-async function handleListCustomers(args: Record<string, any>): Promise<ToolCallResult> {
-  const { shop_id, page = 1, per_page = 25 } = args;
-
-  // Validate shop exists and is WooCommerce
-  const { data: store, error: storeError } = await supabase
-    .from('stores')
-    .select('id, platform_name, data_access_permissions')
-    .eq('id', shop_id)
-    .eq('platform_name', 'woocommerce')
-    .single();
-
-  if (storeError || !store) {
-    return {
-      content: [{ type: 'text', text: JSON.stringify({ error: 'WooCommerce store not found' }) }],
-      isError: true
-    };
-  }
-
-  // Check permissions
-  const permissions = store.data_access_permissions as any;
-  if (permissions && !permissions.allow_customer_access) {
-    return {
-      content: [{ type: 'text', text: JSON.stringify({ error: 'Customer access not allowed for this store' }) }],
-      isError: true
-    };
-  }
-
-  try {
-    // Fetch customers from WooCommerce API
-    const customers = await fetchCustomers(shop_id, page, Math.min(per_page, 100));
-
-    // Format for LLM
-    const formattedCustomers = customers.map(formatCustomerForLlm);
+async function handleGetCustomer(args: Record<string, any>): Promise<ToolCallResult> {
+  const { shop_id, email } = args;
 
 
+  // Validate email is provided
+  if (!email) {
     return {
     return {
       content: [{
       content: [{
         type: 'text',
         type: 'text',
         text: JSON.stringify({
         text: JSON.stringify({
-          count: formattedCustomers.length,
-          page,
-          per_page,
-          customers: formattedCustomers
-        })
-      }]
-    };
-  } catch (error) {
-    console.error('[MCP WooCommerce] Error fetching customers:', error);
-    return {
-      content: [{
-        type: 'text',
-        text: JSON.stringify({
-          error: `Failed to fetch customers: ${error instanceof Error ? error.message : 'Unknown error'}`
+          error: 'Email parameter is required'
         })
         })
       }],
       }],
       isError: true
       isError: true
     };
     };
   }
   }
-}
-
-/**
- * Handle woocommerce_get_customer_orders tool
- */
-async function handleGetCustomerOrders(args: Record<string, any>): Promise<ToolCallResult> {
-  const { shop_id, customer_email } = args;
 
 
   // Validate shop exists and is WooCommerce
   // Validate shop exists and is WooCommerce
   const { data: store, error: storeError } = await supabase
   const { data: store, error: storeError } = await supabase
@@ -337,40 +349,47 @@ async function handleGetCustomerOrders(args: Record<string, any>): Promise<ToolC
 
 
   // Check permissions
   // Check permissions
   const permissions = store.data_access_permissions as any;
   const permissions = store.data_access_permissions as any;
-  if (permissions && (!permissions.allow_order_access || !permissions.allow_customer_access)) {
+  if (permissions && !permissions.allow_customer_access) {
     return {
     return {
-      content: [{ type: 'text', text: JSON.stringify({ error: 'Order and customer access required' }) }],
+      content: [{ type: 'text', text: JSON.stringify({ error: 'Customer access not allowed for this store' }) }],
       isError: true
       isError: true
     };
     };
   }
   }
 
 
   try {
   try {
-    // Fetch orders and filter by customer email
-    const allOrders = await fetchAllOrdersPages(shop_id, 10);
-    const customerOrders = allOrders.filter(
-      order => order.billing.email.toLowerCase() === customer_email.toLowerCase()
-    );
+    // Fetch customer by email from WooCommerce API
+    const customers = await fetchCustomers(shop_id, 1, 1, { email });
 
 
-    // Format for LLM
-    const formattedOrders = customerOrders.map(formatOrderForLlm);
+    if (customers.length === 0) {
+      return {
+        content: [{
+          type: 'text',
+          text: JSON.stringify({
+            error: `No customer found with email: ${email}`
+          })
+        }],
+        isError: true
+      };
+    }
+
+    // Return only the first customer
+    const customer = formatCustomerForLlm(customers[0]);
 
 
     return {
     return {
       content: [{
       content: [{
         type: 'text',
         type: 'text',
         text: JSON.stringify({
         text: JSON.stringify({
-          customerEmail: customer_email,
-          count: formattedOrders.length,
-          orders: formattedOrders
+          customer
         })
         })
       }]
       }]
     };
     };
   } catch (error) {
   } catch (error) {
-    console.error('[MCP WooCommerce] Error fetching customer orders:', error);
+    console.error('[MCP WooCommerce] Error fetching customer:', error);
     return {
     return {
       content: [{
       content: [{
         type: 'text',
         type: 'text',
         text: JSON.stringify({
         text: JSON.stringify({
-          error: `Failed to fetch customer orders: ${error instanceof Error ? error.message : 'Unknown error'}`
+          error: `Failed to fetch customer: ${error instanceof Error ? error.message : 'Unknown error'}`
         })
         })
       }],
       }],
       isError: true
       isError: true
@@ -403,11 +422,8 @@ async function handleToolCall(params: ToolCallParams): Promise<ToolCallResult> {
     case 'woocommerce_list_orders':
     case 'woocommerce_list_orders':
       return await handleListOrders(args);
       return await handleListOrders(args);
 
 
-    case 'woocommerce_list_customers':
-      return await handleListCustomers(args);
-
-    case 'woocommerce_get_customer_orders':
-      const customerValidation = validateParams(args, ['shop_id', 'customer_email']);
+    case 'woocommerce_get_customer':
+      const customerValidation = validateParams(args, ['shop_id', 'email']);
       if (!customerValidation.valid) {
       if (!customerValidation.valid) {
         return {
         return {
           content: [{
           content: [{
@@ -419,7 +435,30 @@ async function handleToolCall(params: ToolCallParams): Promise<ToolCallResult> {
           isError: true
           isError: true
         };
         };
       }
       }
-      return await handleGetCustomerOrders(args);
+      return await handleGetCustomer(args);
+
+    // Legacy tool names for backward compatibility
+    case 'woocommerce_list_customers':
+      return {
+        content: [{
+          type: 'text',
+          text: JSON.stringify({
+            error: 'This tool has been removed. Use woocommerce_get_customer with email parameter instead.'
+          })
+        }],
+        isError: true
+      };
+
+    case 'woocommerce_get_customer_orders':
+      return {
+        content: [{
+          type: 'text',
+          text: JSON.stringify({
+            error: 'This tool has been removed. Use woocommerce_list_orders with customer_email filter instead.'
+          })
+        }],
+        isError: true
+      };
 
 
     default:
     default:
       return {
       return {