Company Logo
MCIP

Build AI Agent

MCIP is the Machine Customer Interaction Protocol — a universal commerce protocol that gives AI agents shopping superpowers. Product discovery is the first implemented capability. Connect your agent to MCIP's search endpoints via simple HTTP calls, or explore the Playground Agent — our reference implementation that adds query refinement, structured comparison, and Multi-Criteria Optimization (MCOP) for mathematically-grounded product ranking.

The MCIP Mental Model

MCIP is the Machine Customer Interaction Protocol — a universal commerce enablement system that provides AI agents with semantic understanding capabilities. Think of it as giving your AI agent the shopping expertise of a seasoned buyer.

Product discovery is the first step. MCIP provides intelligent search through two modes:

ModeEndpointBest ForLatency
Simple Vector SearchGET /searchFast queries, straightforward searches~300ms
Agentic SearchGET /hard-filtering/searchNatural language with implicit filters~500ms

Your agent provides conversational intelligence. MCIP provides commerce expertise. Together, they create something neither could achieve alone.


Part 1: Understanding the Two Search Modes

Direct vector similarity search in Qdrant. Fast, low-latency, no LLM calls:

# Simple search
curl "http://localhost:8080/search?q=gaming+laptop&take=10"

When to use: Straightforward queries where the user's intent is clear and no filter extraction is needed.

Full 4-stage LangGraph workflow with intelligent filter extraction:

# Agentic search with automatic filter extraction
curl "http://localhost:8080/hard-filtering/search?q=nike+shoes+under+100"

The 4-Stage Pipeline:

User query: "Nike shoes under $100"

┌─────────────────────────────────────────┐
│ Stage 1: Parallel Filter Extraction     │
│ (GPT-4o-mini extracts in parallel)      │
│  • brand: ["Nike"]                      │
│  • category: ["Shoes"]                  │
│  • priceMax: 100
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│ Stage 2: Brand Validation               │
│ (Qdrant facet search)                   │
│  • Validates "Nike" exists in catalog   │
│  • If not found → returns empty         │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│ Stage 3: Hybrid Search                  │
│ (Vector similarity + payload filtering) │
│  • 1536-dim embedding generation        │
│  • Qdrant hybrid search                 │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│ Stage 4: LLM Verification               │
│ (GPT-4o-mini semantic filtering)        │
│  • Verifies results match intent        │
│  • Returns top 5 verified products      │
└─────────────────────────────────────────┘

When to use: Natural language queries with implicit filters like "laptops except Apple" or "running shoes between $50 and $150".


Part 2: Response Format

Both search modes return a unified response structure:

{
  "meta": {
    "count": 5,
    "take": 10,
    "skip": 0,
    "q": "nike shoes under 100",
    "filteringStatus": "AI_FILTERED",
    "appliedFilters": {
      "brand": ["Nike"],
      "priceRange": {
        "min": null,
        "max": 100,
        "currency": "UAH"
      }
    }
  },
  "items": [
    {
      "externalId": "prod_123",
      "url": "https://store.com/products/nike-air-max",
      "title": "Nike Air Max 90",
      "description": "Classic sneakers with Air cushioning",
      "brand": "Nike",
      "category": "Shoes",
      "price": {
        "amount": 89.99,
        "currency": "USD"
      },
      "mainImage": "https://cdn.store.com/images/nike-air-max.jpg",
      "attributes": [
        { "name": "Color", "value": "White" },
        { "name": "Material", "value": "Leather" }
      ],
      "variants": [
        { "sku": "NAM90-W-42", "title": "White / 42", "price": null, "available": true }
      ],
      "keywords": ["nike", "sneakers", "running", "air max"],
      "score": 0.892
    }
  ]
}

Filtering Status Values

StatusMeaningSearch Mode
AI_FILTEREDAgentic workflow extracted and applied filtersAgentic
VECTOR_ONLYPure vector similarity searchSimple
FALLBACKDegraded mode (e.g., embedding API failure)Either

Part 3: Basic Integration

Discovering MCIP Tools

MCIP exposes tools through the Model Context Protocol (MCP). Your agent discovers available tools, then calls them as needed:

// src/mcip-client.ts

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

export class MCIPClient {
  private client: Client;
  private sessionId: string;
  private baseUrl: string;

  constructor(baseUrl: string = "http://localhost:8080") {
    this.client = new Client(
      { name: "shopping-agent", version: "1.0.0" },
      { capabilities: { tools: {} } }
    );
    this.baseUrl = baseUrl;
    this.sessionId = this.generateSessionId();
  }

  async connect(): Promise<void> {
    const transport = new StdioClientTransport({
      command: "node",
      args: ["path/to/mcip-server"],
    });

    await this.client.connect(transport);
    console.log("Connected to MCIP");
  }

  async discoverTools(): Promise<Tool[]> {
    const response = await this.client.listTools();
    return response.tools;
  }

  private generateSessionId(): string {
    return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
}

Choosing Your Search Mode

Add methods for both search modes:

// Continuing MCIPClient class

// Mode 1: Simple Vector Search (fast, ~300ms)
async searchSimple(
  query: string,
  options?: { take?: number; skip?: number }
): Promise<SearchResponse> {
  const params = new URLSearchParams({
    q: query,
    take: String(options?.take ?? 10),
    skip: String(options?.skip ?? 0),
  });

  const response = await fetch(`${this.baseUrl}/search?${params}`);
  return response.json();
}

// Mode 2: Agentic Search (intelligent, ~500ms)
async searchAgentic(
  query: string,
  options?: { take?: number; skip?: number }
): Promise<SearchResponse> {
  const params = new URLSearchParams({
    q: query,
    take: String(options?.take ?? 10),
    skip: String(options?.skip ?? 0),
  });

  const response = await fetch(`${this.baseUrl}/hard-filtering/search?${params}`);
  return response.json();
}

Part 4: Reference Implementation — The Playground Agent

For production-grade implementations, we've built the MCIP Playground Agent — a real product search and recommendation engine that demonstrates how to build sophisticated AI agents on top of MCIP. It bridges the gap between unstructured web data and precise, mathematically-grounded decision making by combining LLMs with Multi-Criteria Optimization.

This is a working NestJS application that you can clone, deploy, and extend. It's intentionally straightforward — a practical example of how any team can implement an intelligent commerce agent using MCIP as the product discovery backbone.

Source: The Playground Agent ships with its own Technical Documentation covering architecture, modules, and deployment.

Goals of the Playground Agent

The Playground Agent was designed with five core objectives:

  1. Intelligent Search: Move beyond keyword matching to understand user intent through query refinement and history analysis
  2. Data Aggregation: Unified access to multiple heterogeneous product sources (stores) via MCIP
  3. Structured Comparison: Transform unstructured product descriptions into structured feature matrices for objective comparison
  4. Mathematical Ranking: Use proven decision-making algorithms (Pareto set, normalization, weighted scoring) to eliminate bias and provide optimal results
  5. Transparent Reasoning: Provide clear, AI-generated explanations for why specific products were recommended

Core Modules

The Playground Agent follows a modular NestJS architecture, emphasizing separation of concerns and dependency injection. It has seven core modules:

ModuleResponsibility
Decision Making LayerCentral orchestrator managing the end-to-end search flow
Query SummaryAnalyzes current and previous queries to refine search intent
Search EngineQueries multiple registered stores (via MCIP's Store Directory) in parallel and aggregates results into a unified format
Data TransformerUses AI to parse raw product data into structured feature matrices
Data PreprocessingFilters irrelevant parameters and prepares numerical data for analysis
MCOP ServiceImplements Multi-Criteria Optimization algorithms
AI ClientWrapper around LLM services for reasoning and transformation tasks

Architecture Overview

The Playground Agent follows a modular NestJS architecture, emphasizing separation of concerns and dependency injection:

┌─────────────────────────────────────────────────────────────────┐
MCIP Playground Agent                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌────────────────┐    ┌────────────────┐    ┌────────────────┐ │
│  │  Query Summary │    │  Search Engine │    │ Data Transformer│ │
│  │  (Refines      │───▶│  (Calls MCIP   │───▶│  (Structures   │ │
│  │   intent)      │    │   via Store    │    │   features)    │ │
│  │                │    │   Directory)   │    │                │ │
│  └────────────────┘    └────────────────┘    └────────────────┘ │
│         │                                            │          │
│         ▼                                            ▼          │
│  ┌────────────────┐    ┌────────────────┐    ┌────────────────┐ │
│  │ Session History│    │  MCOP Service  │◀───│    Data        │ │
│  │                │    │  (Pareto set,  │    │ Preprocessing  │ │
│  │                │    │   normalize,   │    │  (Numerical    │ │
│  │                │    │   score)       │    │   conversion)  │ │
│  └────────────────┘    └────────────────┘    └────────────────┘ │
│                               │                                  │
│                               ▼                                  │
│                      ┌────────────────┐                          │
│                      │   AI Client    │                          │
│                      │   (Generates   │                          │
│                      │   reasoning)   │                          │
│                      └────────────────┘                          │
│                                                                  │
│              ┌────────────────────────────────┐                  │
│              │     Decision Making Layer      │                  │
│              │   (Orchestrates entire flow)   │                  │
│              └────────────────────────────────┘                  │
└─────────────────────────────────────────────────────────────────┘
Axios (HTTP)

                    ┌──────────────────┐
MCIP Server    │
                    │  (Vector Search  │
+ Agentic)      │
                    └──────────────────┘

Stage 1: Query Refinement

When a user submits a query, the Query Summary module examines it alongside previous queries in the session. It uses an LLM to generate a "refined query" that better captures the user's ultimate goal:

// Query refinement example
interface QueryContext {
  currentQuery: string;
  previousQueries: string[];
  sessionPreferences: Record<string, any>;
}

async function refineQuery(context: QueryContext): Promise<string> {
  const response = await openai.chat.completions.create({
    model: "gpt-4o",
    messages: [
      {
        role: "system",
        content: `Analyze the user's current query in context of their session history.
                  Generate a refined search query that captures their true intent.
                  
                  Previous queries: ${context.previousQueries.join(", ")}
                  Current query: ${context.currentQuery}`
      }
    ],
    response_format: { type: "json_object" },
  });

  return JSON.parse(response.choices[0].message.content!).refinedQuery;
}

// Example:
// "Find a lightweight laptop" + "under $1000" 
// → "High-performance lightweight laptop under $1000"

Stage 2: Product Aggregation via MCIP

The Search Engine queries multiple registered stores defined in the Store Directory through MCIP's endpoints in parallel. It fetches raw product data and validates it against the UnifiedProduct schema using Zod, ensuring consistency across different sources:

import { z } from "zod";

const UnifiedProductSchema = z.object({
  externalId: z.string(),
  url: z.string(),
  title: z.string().min(3),
  description: z.string(),
  brand: z.string().optional(),
  category: z.string().optional(),
  price: z.object({
    amount: z.number(),
    currency: z.enum(["UAH", "USD", "EUR"]),
  }),
  mainImage: z.string(),
  attributes: z.array(z.object({
    name: z.string(),
    value: z.union([z.string(), z.number(), z.boolean()]),
  })),
  variants: z.array(z.object({
    sku: z.string(),
    title: z.string(),
    price: z.object({ amount: z.number(), currency: z.string() }).nullable(),
    available: z.boolean(),
  })),
  keywords: z.array(z.string()),
  score: z.number().optional(),
});

async function aggregateProducts(refinedQuery: string): Promise<UnifiedProduct[]> {
  const response = await mcip.searchAgentic(refinedQuery, { take: 20 });
  
  // Validate each product against schema
  return response.items
    .map(item => {
      const result = UnifiedProductSchema.safeParse(item);
      return result.success ? result.data : null;
    })
    .filter(Boolean);
}

Stage 3: Data Transformation & Preprocessing

Raw product descriptions are often messy and unstructured. This stage converts them into a structured, numerical representation that can be mathematically analyzed. It has two parts:

Part A: Data Transformer — The Data Transformer sends product data to an LLM to extract a structured feature matrix:

interface FeatureMatrix {
  products: string[];           // Product IDs
  features: string[];           // Feature names
  values: (number | null)[][];  // Feature values per product
  weights: number[];            // Feature importance (0-1)
  directions: ("max" | "min")[]; // Higher or lower is better
}

async function transformToFeatureMatrix(
  products: UnifiedProduct[],
  userIntent: string
): Promise<FeatureMatrix> {
  const extractionResponse = await openai.chat.completions.create({
    model: "gpt-4o",
    messages: [
      {
        role: "system",
        content: `Extract comparable features from these products.
                  User is looking for: ${userIntent}
                  
                  For each feature, determine:
                  - The numerical value for each product
                  - Whether higher ("max") or lower ("min") is better
                  - The weight (0-1) based on relevance to user intent`
      },
      {
        role: "user",
        content: JSON.stringify(products.map(p => ({
          id: p.externalId,
          title: p.title,
          description: p.description,
          price: p.price.amount,
          attributes: p.attributes,
        })))
      }
    ],
    response_format: { type: "json_object" },
  });

  return JSON.parse(extractionResponse.choices[0].message.content!);
}

Part B: Data Preprocessing — The Data Preprocessing stage then:

  • Identifies relevant features: Filters out features not relevant to the user's query
  • Converts to numerical values: Transforms text-based features into numbers
  • Determines benefit direction: Decides whether higher or lower is better for each feature
  • Assigns weights: Sets importance weights based on relevance to user intent
interface PreprocessedData {
  matrix: number[][];           // Numerical feature matrix
  featureNames: string[];       // Feature names (filtered)
  directions: ("max" | "min")[];// Benefit directions
  weights: number[];            // Importance weights (sum to 1)
}

function preprocessFeatureMatrix(
  rawMatrix: FeatureMatrix,
  userIntent: string
): PreprocessedData {
  // Filter irrelevant features based on user intent
  const relevantIndices = rawMatrix.features
    .map((f, i) => ({ feature: f, index: i, weight: rawMatrix.weights[i] }))
    .filter(f => f.weight > 0.1)  // Threshold for relevance
    .map(f => f.index);

  // Extract only relevant columns
  const filteredMatrix = rawMatrix.values.map(row =>
    relevantIndices.map(i => row[i] ?? 0)  // Replace null with 0
  );

  // Normalize weights to sum to 1
  const relevantWeights = relevantIndices.map(i => rawMatrix.weights[i]);
  const weightSum = relevantWeights.reduce((a, b) => a + b, 0);
  const normalizedWeights = relevantWeights.map(w => w / weightSum);

  return {
    matrix: filteredMatrix,
    featureNames: relevantIndices.map(i => rawMatrix.features[i]),
    directions: relevantIndices.map(i => rawMatrix.directions[i]),
    weights: normalizedWeights,
  };
}

Stage 4: Multi-Criteria Optimization (MCOP)

This is the mathematical heart of the Playground Agent. Instead of a "black box" AI ranking, MCOP uses a three-step mathematical process:

// MCOP Service Implementation

interface MCOPResult {
  rankedProducts: string[];  // Product IDs in order
  scores: number[];          // Objective scores
  paretoSet: string[];       // Non-dominated products
}

class MCOPService {
  /**
   * Step 1: Pareto Set Computation
   * Filters out "dominated" products — those worse than another in ALL criteria
   */
  computeParetoSet(matrix: FeatureMatrix): string[] {
    const dominated = new Set<number>();

    for (let i = 0; i < matrix.products.length; i++) {
      for (let j = 0; j < matrix.products.length; j++) {
        if (i === j) continue;
        if (this.dominates(matrix, j, i)) {
          dominated.add(i);
          break;
        }
      }
    }

    return matrix.products.filter((_, i) => !dominated.has(i));
  }

  private dominates(matrix: FeatureMatrix, a: number, b: number): boolean {
    let dominated = true;
    let strictlyBetter = false;

    for (let f = 0; f < matrix.features.length; f++) {
      const valA = matrix.values[a][f];
      const valB = matrix.values[b][f];
      if (valA === null || valB === null) continue;

      const direction = matrix.directions[f];
      const aIsBetter = direction === "max" ? valA > valB : valA < valB;
      const aIsEqual = valA === valB;

      if (!aIsBetter && !aIsEqual) dominated = false;
      if (aIsBetter) strictlyBetter = true;
    }

    return dominated && strictlyBetter;
  }

  /**
   * Step 2: Normalization
   * Scales different units (price in $, weight in kg) to common range (0-1)
   */
  normalize(matrix: FeatureMatrix): number[][] {
    const normalized: number[][] = [];

    for (let f = 0; f < matrix.features.length; f++) {
      const values = matrix.values.map(row => row[f]).filter(v => v !== null) as number[];
      const min = Math.min(...values);
      const max = Math.max(...values);
      const range = max - min || 1;

      const normalizedColumn = matrix.values.map(row => {
        const val = row[f];
        if (val === null) return 0;
        
        const norm = (val - min) / range;
        // Invert if lower is better
        return matrix.directions[f] === "min" ? 1 - norm : norm;
      });

      normalized.push(normalizedColumn);
    }

    return normalized;
  }

  /**
   * Step 3: Weighted Scoring
   * Applies user-specific weights to calculate final objective score
   */
  calculateScores(normalizedMatrix: number[][], weights: number[]): number[] {
    const productCount = normalizedMatrix[0]?.length || 0;
    const scores: number[] = [];

    for (let p = 0; p < productCount; p++) {
      let score = 0;
      for (let f = 0; f < normalizedMatrix.length; f++) {
        score += normalizedMatrix[f][p] * weights[f];
      }
      scores.push(score);
    }

    return scores;
  }

  /**
   * Main ranking function
   */
  rank(matrix: FeatureMatrix): MCOPResult {
    const paretoSet = this.computeParetoSet(matrix);
    const normalized = this.normalize(matrix);
    const scores = this.calculateScores(normalized, matrix.weights);

    const ranked = matrix.products
      .map((id, i) => ({ id, score: scores[i] }))
      .sort((a, b) => b.score - a.score);

    return {
      rankedProducts: ranked.map(r => r.id),
      scores: ranked.map(r => r.score),
      paretoSet,
    };
  }
}

Stage 5: Reasoning & Results

Finally, the top-ranked products are sent back to the LLM. The AI Client generates a natural language explanation (Reasoning) that justifies the ranking, highlighting the pros and cons of the top choices in relation to the user's query. The result is returned as a structured JSON object or as a real-time stream of status updates and results via RxJS observables:

interface RecommendationResult {
  products: UnifiedProduct[];
  reasoning: string;
  paretoSet: string[];
  scores: Record<string, number>;
}

async function generateReasoning(
  rankedProducts: UnifiedProduct[],
  userQuery: string,
  mcopResult: MCOPResult
): Promise<RecommendationResult> {
  const top5 = rankedProducts.slice(0, 5);

  const reasoningResponse = await openai.chat.completions.create({
    model: "gpt-4o",
    messages: [
      {
        role: "system",
        content: `Generate a clear, helpful explanation for why these products 
                  are recommended for the user's query: "${userQuery}"
                  
                  Highlight:
                  - Why the #1 pick is best
                  - Trade-offs between top options
                  - Which products are in the Pareto-optimal set (non-dominated)
                  
                  Be concise but informative.`
      },
      {
        role: "user",
        content: JSON.stringify({
          products: top5.map(p => ({
            id: p.externalId,
            title: p.title,
            price: p.price,
            score: mcopResult.scores[mcopResult.rankedProducts.indexOf(p.externalId)],
          })),
          paretoSet: mcopResult.paretoSet,
        })
      }
    ],
  });

  return {
    products: top5,
    reasoning: reasoningResponse.choices[0].message.content!,
    paretoSet: mcopResult.paretoSet,
    scores: Object.fromEntries(
      mcopResult.rankedProducts.map((id, i) => [id, mcopResult.scores[i]])
    ),
  };
}

Why MCOP Matters: Eliminating AI Bias

Traditional AI-only ranking is a "black box" — you can't explain why Product A ranked higher than Product B. MCOP provides:

AspectAI-Only RankingMCOP Ranking
TransparencyOpaqueClear mathematical formula
ReproducibilityMay varyDeterministic given same inputs
BiasLLM biases affect rankingPure mathematical optimization
Explainability"AI thinks this is better""Score: 0.87 based on price (0.3), weight (0.2)..."
User ControlLimitedAdjustable weights per criterion

Putting It All Together

// src/decision-making.service.ts

class DecisionMakingService {
  constructor(
    private querySummary: QuerySummaryService,
    private searchEngine: SearchEngineService,
    private dataTransformer: DataTransformerService,
    private mcopService: MCOPService,
    private aiClient: AIClientService,
  ) {}

  async processSearch(
    query: string,
    sessionHistory: string[]
  ): Promise<RecommendationResult> {
    // Stage 1: Refine query based on session context
    const refinedQuery = await this.querySummary.refine({
      currentQuery: query,
      previousQueries: sessionHistory,
    });

    // Stage 2: Aggregate products from MCIP
    const products = await this.searchEngine.search(refinedQuery);

    // Stage 3: Transform to feature matrix
    const featureMatrix = await this.dataTransformer.transform(
      products,
      refinedQuery
    );

    // Stage 4: MCOP ranking
    const mcopResult = this.mcopService.rank(featureMatrix);

    // Stage 5: Generate reasoning
    const rankedProducts = mcopResult.rankedProducts
      .map(id => products.find(p => p.externalId === id)!)
      .filter(Boolean);

    return this.aiClient.generateReasoning(
      rankedProducts,
      refinedQuery,
      mcopResult
    );
  }
}

Deployment

The Playground Agent is containerized using Docker and can be deployed using the provided docker-compose.yml or the build-and-push.sh script for cloud environments. It connects to your MCIP server instance via HTTP (Axios), so make sure MCIP is running and accessible before starting the agent.


Part 5: Session Management

Why Sessions Matter

Without sessions, every interaction starts fresh. Sessions maintain state across conversations — search history, viewed products, and user preferences. The Playground Agent uses session history for query refinement.

// src/session-manager.ts

export class SessionManager {
  private sessions: Map<string, SessionData> = new Map();
  private readonly TTL_MS = 24 * 60 * 60 * 1000; // 24 hours

  createSession(userId: string): string {
    const sessionId = `sess_${userId}_${Date.now()}`;

    this.sessions.set(sessionId, {
      id: sessionId,
      userId,
      createdAt: new Date(),
      lastActivity: new Date(),
      context: {
        searchHistory: [],
        viewedProducts: [],
        lastSearchMode: null,
        preferences: {},
      },
    });

    return sessionId;
  }

  recordSearch(
    sessionId: string,
    query: string,
    mode: "VECTOR_ONLY" | "AI_FILTERED",
    results: UnifiedProduct[]
  ): void {
    const session = this.getSession(sessionId);
    if (session) {
      session.context.searchHistory.push({
        query,
        mode,
        resultCount: results.length,
        timestamp: new Date(),
      });
      session.context.viewedProducts = results.map(p => p.externalId);
      session.context.lastSearchMode = mode;
    }
  }

  // Get previous queries for refinement
  getPreviousQueries(sessionId: string, limit: number = 5): string[] {
    const session = this.getSession(sessionId);
    if (!session) return [];
    
    return session.context.searchHistory
      .slice(-limit)
      .map(s => s.query);
  }
}

Part 6: Production Considerations

Performance Benchmarks

MCIP delivers consistent performance at scale:

MetricP50P95P99
Embedding Generation145ms189ms212ms
Vector Search238ms287ms342ms
Total (Simple)~300ms~400ms~450ms
Total (Agentic)421ms498ms587ms

Throughput: 1,247 requests/second

Error Handling

Graceful degradation keeps conversations flowing:

async function safeSearch(
  mcip: MCIPClient,
  query: string,
  useAgentic: boolean
): Promise<{ results: SearchResponse | null; hadError: boolean; fallbackUsed: boolean }> {
  try {
    const results = useAgentic
      ? await mcip.searchAgentic(query)
      : await mcip.searchSimple(query);

    const fallbackUsed = results.meta.filteringStatus === "FALLBACK";
    return { results, hadError: false, fallbackUsed };
  } catch (error) {
    console.error(`Search error:`, error);

    // Try fallback to simple search if agentic failed
    if (useAgentic) {
      try {
        const fallbackResults = await mcip.searchSimple(query);
        return { results: fallbackResults, hadError: true, fallbackUsed: true };
      } catch {
        // Both failed
      }
    }

    return { results: null, hadError: true, fallbackUsed: false };
  }
}

Scaling Considerations

ScaleArchitectureSession StorageNotes
PrototypeSingle instanceIn-memoryFine for development
Small (< 100 concurrent)Single instanceRedisAdd persistence
Medium (100-1000)2-3 instances + LBRedis clusterHorizontal scaling
Large (1000+)Auto-scaling groupRedis cluster + shardingFull production setup

Part 7: Platform-Specific Integration

OpenAI GPT Actions

# openapi.yaml for GPT Action
openapi: 3.0.0
info:
  title: MCIP Shopping Assistant API
  version: 1.0.0
servers:
  - url: https://your-mcip-server.com
paths:
  /search:
    get:
      operationId: simpleSearch
      summary: Fast vector search for products
      parameters:
        - name: q
          in: query
          required: true
          schema:
            type: string
  /hard-filtering/search:
    get:
      operationId: agenticSearch
      summary: Intelligent search with automatic filter extraction
      parameters:
        - name: q
          in: query
          required: true
          schema:
            type: string

Claude Tool Use

const tools = [
  {
    name: "simple_search",
    description: "Fast vector search for straightforward product queries.",
    input_schema: {
      type: "object",
      properties: {
        query: { type: "string", description: "Product search query" },
        limit: { type: "number", default: 10 },
      },
      required: ["query"],
    },
  },
  {
    name: "agentic_search",
    description: "Intelligent search with automatic brand, category, and price filter extraction.",
    input_schema: {
      type: "object",
      properties: {
        query: { type: "string", description: "Natural language search query with filters" },
        limit: { type: "number", default: 10 },
      },
      required: ["query"],
    },
  },
];

Troubleshooting

"Agentic search returns empty but simple search works"

Cause: Brand validation failed — the extracted brand doesn't exist in the catalog

Solution: Check meta.appliedFilters to see what was extracted.

"MCOP scores are all similar"

Cause: Feature weights not properly calibrated to user intent

Solution: Review the weight extraction in Data Transformer stage.

"Responses are slow (>1s)"

Cause: Multiple LLM calls in Playground Agent pipeline

Solution: Cache query refinements, parallelize where possible.

"filteringStatus shows FALLBACK"

Cause: MCIP encountered an error and degraded gracefully

Solution: Check MCIP server logs. Results are still valid but may be less precise.