McpServer catalog tools for Sitecore Ordercloud

How Catalog Tools Work: Making E-Commerce Catalogs Accessible to AI

A deep dive into the catalog management system that enables AI assistants to manage Sitecore OrderCloud catalogs through natural language

Published on November 20, 2025 | Technical Deep Dive | E-Commerce, API Integration, AI Tools

Introduction: What Are Catalogs in E-Commerce?

In e-commerce, a catalog is a collection of products organized for a specific purpose. Think of it as a curated storefront. In Sitecore OrderCloud, catalogs are powerful organizational structures that:

  • Group products into logical collections
  • Control visibility by assigning catalogs to buyers, user groups, or individual users
  • Enable multi-tenant commerce where different buyers see different product offerings
  • Support B2B scenarios where different customer segments get different catalogs

For example, a company might have:

  • A “Retail Catalog” for end consumers
  • A “Wholesale Catalog” for business customers
  • A “VIP Catalog” for premium customers

The Challenge: Making Catalogs AI-Accessible

The OrderCloud API provides comprehensive catalog management, but using it requires understanding REST API endpoints, knowing exact field names and data structures, handling authentication and error cases, and managing complex relationships.

Traditional API usage looks like this:

Traditional API Call (TypeScript)
const catalog = {
  Name: "Electronics Catalog",
  Description: "Consumer electronics products",
  Active: true
}
await axios.post('https://api.ordercloud.io/v1/catalogs', catalog, {
  headers: { Authorization: `Bearer ${token}` }
})

Our goal was to make this accessible through natural language:

Natural Language Request:
“Create a catalog called ‘Electronics Catalog’ with description ‘Consumer electronics products’ and make it active.”

The AI assistant handles everything automatically—no code required.

Architecture: Three-Layer Design

The catalog tools system follows a clean three-layer architecture:

Layer 1: Tool Registration – The AI Interface

The catalog-tools.ts file defines what AI assistants can do with catalogs. It’s the bridge between natural language and API calls.

How Tools Are Registered

Each tool follows this pattern:

Tool Registration Pattern (TypeScript)
server.registerTool(
  "tool_name",                    // Unique identifier
  {
    title: "Human-Readable Title",
    description: "What this tool does",
    inputSchema: {                // Zod schema for validation
      // Parameter definitions
    }
  },
  async (input) => {              // Handler function
    // Execute the operation
    // Return formatted response
  }
)

Example: The Create Catalog Tool

Let’s examine the complete implementation of the create_catalog tool:

catalog-tools.ts – Create Catalog Tool
server.registerTool(
  "create_catalog",
  {
    title: "Create Catalog",
    description: "Create a new catalog in OrderCloud",
    inputSchema: {
      id: z.string().optional(),           // Optional custom ID
      name: z.string(),                    // Required name
      description: z.string().optional(),  // Optional description
      active: z.boolean().optional().default(true),  // Defaults to active
      xp: z.record(z.any()).optional(),    // Extended properties
    },
  },
  async (input) => {
    try {
      // Transform input to OrderCloud format
      const catalog = {
        ...(input.id && { ID: input.id }),
        Name: input.name,
        ...(input.description && { Description: input.description }),
        Active: input.active,
        ...(input.xp && { xp: input.xp }),
      }
      
      // Call the client
      const result = await orderCloudClient.catalogs.saveCatalogAssignment(assignment)

// Client Method
async saveCatalogAssignment(assignment: CatalogAssignment) {
  this.ensureAuthenticated()
  
  const response = await this.client.post<CatalogAssignment>(
    "v1/catalogs/assignments", 
    assignment
  )
  return response.data
}

// API Call
POST https://sandboxapi.ordercloud.io/v1/catalogs/assignments
Body: {
  "CatalogID": "summer-collection-001",
  "BuyerID": "retail-buyer"
}

Step 5: Response to User

AI formats the response:

✅ Created catalog “Summer Collection” (ID: summer-collection-001)
✅ Assigned catalog to Retail buyer

Advanced Features

1. Advanced Filtering and Search

The list_catalogs tool supports powerful query capabilities:

Advanced Search Example
// Search by name
{
  search: "Electronics",
  searchOn: ["Name"]
}

// Multiple sort fields
{
  sortBy: ["Name", "!ID"]  // Sort by Name ascending, then ID descending
}

// Complex filters
{
  filters: {
    Active: true,
    "CategoryCount": ">10"  // More than 10 categories
  }
}

The client transforms these into OrderCloud query parameters:

Resulting API Call
GET /v1/catalogs?search=Electronics&searchOn=Name&sortBy=Name,!ID&filters[Active]=true

2. Extended Properties (XP)

OrderCloud supports custom extended properties for storing additional metadata:

Using Extended Properties
{
  name: "Electronics Catalog",
  xp: {
    season: "Summer 2024",
    region: "North America",
    customField: "value",
    promotions: {
      enabled: true,
      discountPercent: 15
    }
  }
}

These are preserved and passed through to the API, enabling custom metadata without schema changes.

3. Comprehensive Error Handling

The system implements error handling at multiple levels:

Tool Level Error Handling
catch (error) {
  return {
    content: [{
      type: "text",
      text: `Error creating catalog: ${error.message}`
    }],
    isError: true
  }
}
Client Level Error Handling
catch (error) {
  const errorDetails = {
    message: error.message,
    response: {
      status: error.response?.status,
      data: error.response?.data
    }
  }
  DebugLogger.log("createCatalog_error", { catalog, errorDetails }, undefined, error)
  throw error
}

This provides:

  • User-friendly error messages for the AI to communicate
  • Detailed debugging information in logs
  • HTTP status codes for troubleshooting
  • Full API error responses

Real-World Use Cases

Use Case 1: Multi-Tenant Catalog Setup

Setting up catalogs for different customer segments:

Scenario: Creating Multiple Catalogs
// AI receives request:
// "Create three catalogs: 'Retail Catalog', 'Wholesale Catalog', 
//  and 'VIP Catalog'. Make them all active."

// AI executes three create_catalog calls:

await orderCloudClient.catalogs.create({
  Name: "Retail Catalog",
  Active: true
})

await orderCloudClient.catalogs.create({
  Name: "Wholesale Catalog",
  Active: true
})

await orderCloudClient.catalogs.create({
  Name: "VIP Catalog",
  Active: true
})

Use Case 2: Catalog Assignment Management

Assigning catalogs to multiple buyers:

Scenario: Multiple Assignments
// AI receives request:
// "Assign the 'Electronics Catalog' to the 'Retail Buyer' and 
//  the 'Wholesale Buyer'."

// AI executes two save_catalog_assignment calls:

await orderCloudClient.catalogs.saveCatalogAssignment({
  CatalogID: "electronics-catalog",
  BuyerID: "retail-buyer"
})

await orderCloudClient.catalogs.saveCatalogAssignment({
  CatalogID: "electronics-catalog",
  BuyerID: "wholesale-buyer"
})

Use Case 3: Bulk Catalog Operations

Updating multiple catalogs based on criteria:

Scenario: Bulk Updates
// AI receives request:
// "Find all catalogs with 'Summer' in the name and set them to inactive."

// Step 1: List catalogs with filter
const catalogs = await orderCloudClient.catalogs.listCatalogs({
  search: "Summer",
  searchOn: ["Name"]
})

// Step 2: Patch each catalog
for (const catalog of catalogs.Items) {
  await orderCloudClient.catalogs.patch(catalog.ID, {
    Active: false
  })
}

Use Case 4: Catalog Discovery with Complex Filtering

Scenario: Advanced Search
// AI receives request:
// "Show me all active catalogs that have more than 50 products."

const catalogs = await orderCloudClient.catalogs.listCatalogs({
  filters: {
    Active: true,
    "CategoryCount": ">50"
  },
  sortBy: ["CategoryCount"],
  pageSize: 100
})

// Returns structured data for AI to format

Design Patterns and Best Practices

1. Separation of Concerns

Each layer has a single, well-defined responsibility:

  • Tools Layer – AI interface, validation, response formatting
  • Client Layer – HTTP communication, data transformation
  • API Layer – Data persistence

This separation makes the code:

  • Easier to understand and maintain
  • Simple to test in isolation
  • Flexible to modify without ripple effects

2. Type Safety with TypeScript and Zod

Full TypeScript typing combined with Zod runtime validation ensures correctness:

Type Definitions
interface Catalog {
  ID?: string
  Name: string
  Description?: string
  Active?: boolean
  CategoryCount?: number
  xp?: Record<string, any>
}

interface ListResponse<T> {
  Items: T[]
  Meta: {
    Page: number
    PageSize: number
    TotalCount: number
    TotalPages: number
  }
}
Zod Schema Validation
const catalogSchema = {
  id: z.string().optional(),
  name: z.string().min(1, "Name is required"),
  description: z.string().optional(),
  active: z.boolean().optional().default(true),
  xp: z.record(z.any()).optional()
}

This provides:

  • Compile-time error checking
  • IDE autocomplete and IntelliSense
  • Self-documenting code
  • Runtime validation to catch invalid data

3. Graceful Error Recovery

Errors are handled at multiple levels with context-appropriate responses:

Multi-Level Error Handling
// Level 1: Validation errors (caught early)
if (!input.name) {
  throw new Error("Catalog name is required")
}

// Level 2: Client errors (network, auth)
try {
  const response = await this.client.post(...)
} catch (error) {
  if (error.response?.status === 401) {
    throw new Error("Authentication failed. Please check credentials.")
  }
  throw error
}

// Level 3: API errors (business logic)
if (response.data.Errors) {
  throw new Error(`API Error: ${response.data.Errors[0].Message}`)
}

4. Extensibility

The architecture makes it easy to add new capabilities:

Adding a New Tool
// 1. Add client method
async getCatalogStats(id: string): Promise<CatalogStats> {
  this.ensureAuthenticated()
  const response = await this.client.get(`v1/catalogs/${id}/stats`)
  return response.data
}

// 2. Register tool
server.registerTool(
  "get_catalog_stats",
  {
    title: "Get Catalog Statistics",
    description: "Get detailed statistics for a catalog",
    inputSchema: {
      catalogId: z.string()
    }
  },
  async (input) => {
    const stats = await orderCloudClient.catalogs.getCatalogStats(input.catalogId)
    return {
      content: [{ type: "text", text: JSON.stringify(stats, null, 2) }]
    }
  }
)

Testing and Debugging

Debug Tools

The system includes dedicated debug tools:

Debug Tool Implementation
server.registerTool(
  "get_debug_logs",
  {
    title: "Get Debug Logs",
    description: "Retrieve debug logs for troubleshooting",
    inputSchema: {
      includeParams: z.boolean().optional(),
      includeResults: z.boolean().optional(),
      maxLogs: z.number().optional().default(20)
    }
  },
  async (input) => {
    const logs = DebugLogger.getLogs({
      limit: input.maxLogs,
      includeParams: input.includeParams,
      includeResults: input.includeResults
    })
    
    return {
      content: [{ 
        type: "text", 
        text: JSON.stringify(logs, null, 2) 
      }]
    }
  }
)

server.registerTool(
  "test_api_connection",
  {
    title: "Test API Connection",
    description: "Test the connection to OrderCloud API",
    inputSchema: {}
  },
  async () => {
    try {
      await orderCloudClient.catalogs.listCatalogs({ pageSize: 1 })
      return {
        content: [{ 
          type: "text", 
          text: "✅ API connection successful" 
        }]
      }
    } catch (error) {
      return {
        content: [{ 
          type: "text", 
          text: `❌ API connection failed: ${error.message}` 
        }],
        isError: true
      }
    }
  }
)

Common Issues and Solutions

Issue Symptom Solution
Authentication Errors “Not authenticated” errors Ensure credentials are set in environment variables. Use test_api_connection tool.
Validation Errors Zod validation failures Check input schema requirements. Review error messages for missing/invalid fields.
API Errors 400/404/500 errors Check error response details in logs. Verify API endpoint and data format.
Network Errors Connection timeouts Check network connectivity. Verify API base URL is correct.

Performance Considerations

Pagination

All list operations support pagination to prevent loading excessive data:

Pagination Implementation
const catalogs = await orderCloudClient.catalogs.listCatalogs({
  page: 1,
  pageSize: 20  // Load 20 catalogs at a time
})

// Response includes metadata for pagination
console.log(catalogs.Meta)
// {
//   Page: 1,
//   PageSize: 20,
//   TotalCount: 157,
//   TotalPages: 8
// }

Request Optimization

The client uses efficient HTTP patterns:

  • Request Interceptors – Automatic token injection eliminates redundant auth code
  • Conditional Requests – Only send necessary parameters
  • Type-Safe Responses – No runtime parsing overhead
Efficient Parameter Building
const params: Record<string, any> = {}

// Only add parameters that have values
if (options?.search) params.search = options.search
if (options?.searchOn) params.searchOn = options.searchOn.join(",")
if (options?.sortBy) params.sortBy = options.sortBy.join(",")

// This prevents sending empty/undefined parameters

Future Enhancements

Potential improvements to the system:

1. Bulk Operations

Proposed Bulk API
// Create multiple catalogs in one call
async bulkCreate(catalogs: Catalog[]): Promise<Catalog[]> {
  const results = await Promise.all(
    catalogs.map(catalog => this.create(catalog))
  )
  return results
}

// Usage
const catalogs = await orderCloudClient.catalogs.bulkCreate([
  { Name: "Catalog 1", Active: true },
  { Name: "Catalog 2", Active: true },
  { Name: "Catalog 3", Active: true }
])

2. Catalog Templates

Template System Concept
// Pre-configured catalog structures
const templates = {
  retail: {
    Name: "Retail Catalog",
    Active: true,
    xp: {
      type: "retail",
      allowsPublicAccess: true
    }
  },
  wholesale: {
    Name: "Wholesale Catalog",
    Active: true,
    xp: {
      type: "wholesale",
      requiresApproval: true,
      minimumOrder: 1000
    }
  }
}

// Create from template
async createFromTemplate(
  templateName: string, 
  overrides?: Partial<Catalog>
): Promise<Catalog> {
  const template = templates[templateName]
  return this.create({ ...template, ...overrides })
}

3. Catalog Cloning

Cloning Implementation
async cloneCatalog(
  sourceId: string, 
  newName: string, 
  includeAssignments: boolean = true
): Promise<Catalog> {
  // Get source catalog
  const source = await this.get(sourceId)
  
  // Create new catalog
  const newCatalog = await this.create({
    Name: newName,
    Description: source.Description,
    Active: source.Active,
    xp: source.xp
  })
  
  // Clone assignments if requested
  if (includeAssignments) {
    const assignments = await this.listCatalogAssignments({
      catalogId: sourceId
    })
    
    for (const assignment of assignments.Items) {
      await this.saveCatalogAssignment({
        ...assignment,
        CatalogID: newCatalog.ID
      })
    }
  }
  
  return newCatalog
}

4. Catalog Analytics

Analytics Queries
interface CatalogAnalytics {
  totalCatalogs: number
  activeCatalogs: number
  inactiveCatalogs: number
  avgProductsPerCatalog: number
  topCatalogsByProducts: Catalog[]
  assignmentStats: {
    totalAssignments: number
    buyerAssignments: number
    userGroupAssignments: number
    userAssignments: number
  }
}

async getCatalogAnalytics(): Promise<CatalogAnalytics> {
  // Implementation would aggregate data across catalogs
}

Conclusion

The catalog tools system demonstrates a robust architecture for making complex e-commerce APIs accessible through AI. By implementing a clean three-layer design with proper separation of concerns, we’ve created a system that is:

  • Type-Safe – Full TypeScript coverage with Zod validation
  • Maintainable – Clear separation between AI interface, business logic, and API communication
  • Debuggable – Comprehensive logging at every level
  • Extensible – Easy to add new tools and capabilities
  • User-Friendly – Natural language interface eliminates the learning curve

The system scales from simple single-catalog operations to complex multi-tenant scenarios, all while maintaining code quality and developer experience.

Key Takeaway: By carefully architecting the system with proper abstractions, validation, error handling, and logging, we’ve transformed a developer-focused REST API into something anyone can use through conversation with an AI assistant.

Quick Reference

Complete Tool List

Available Tools Summary
// Basic CRUD Operations
list_catalogs(options)     - List with filtering, search, sort
get_catalog(id)            - Get by ID
create_catalog(catalog)    - Create new
update_catalog(id, catalog) - Full update (PUT)
patch_catalog(id, catalog)  - Partial update (PATCH)
delete_catalog(id)         - Delete

// Catalog Assignments
list_catalog_assignments(options)     - List assignments
save_catalog_assignment(assignment)   - Create/update assignment
delete_catalog_assignment(catalogId)  - Delete assignment

// Bundle Assignments
list_catalog_bundle_assignments(options)
save_catalog_bundle_assignment(assignment)
delete_catalog_bundle_assignment(catalogId, bundleId)

// Product Assignments
list_catalog_product_assignments(options)
save_catalog_product_assignment(assignment)
delete_catalog_product_assignment(catalogId, productId)

Example Code Snippets

Common Operations
// Create catalog with extended properties
await orderCloudClient.catalogs.create({
  Name: "Electronics",
  Description: "Consumer electronics",
  Active: true,
  xp: {
    region: "North America",
    season: "2024"
  }
})

// Search with multiple criteria
await orderCloudClient.catalogs.listCatalogs({
  search: "Electronics",
  searchOn: ["Name"],
  sortBy: ["Name"],
  filters: { Active: true },
  page: 1,
  pageSize: 20
})

// Assign to buyer
await orderCloudClient.catalogs.saveCatalogAssignment({
  CatalogID: "electronics-catalog",
  BuyerID: "retail-buyer"
})

This technical documentation provides a comprehensive guide to understanding and implementing the catalog tools system. For source code, see src/tools/catalogs/catalog-tools.ts and src/tools/clients/catalog-client.ts.

Leave a comment