Published: 2026-05-04 | Reading Time: 12 minutes | Difficulty: Intermediate to Advanced

Introduction: Solving the Black Friday AI Customer Service Crisis

I remember the exact moment our e-commerce platform nearly collapsed. It was 11:47 PM on Black Friday 2025, and our AI customer service chatbot was drowning in 47,000 concurrent requests. The native OpenAI API was returning 503 errors faster than we could refresh the dashboard. Response times had ballooned from 800ms to over 28 seconds. Customers were abandoning carts, Twitter was filling with complaints, and our engineering team was scrambling. That night, I architected a solution that cut our AI inference costs by 87% while delivering sub-50ms response times—even during peak traffic. The secret? MCP Server tool calling connected through HolySheep AI's OpenAI-compatible multi-model aggregation gateway.

In this comprehensive guide, I'll walk you through exactly how to implement this architecture for your own projects, whether you're handling enterprise RAG systems, indie developer side projects, or high-traffic e-commerce platforms like we were.

Understanding MCP Server Tool Calling Architecture

The Model Context Protocol (MCP) represents a paradigm shift in how AI models interact with external tools and data sources. Unlike traditional API calls where the model generates a static response, MCP enables dynamic tool invocation where the AI can actually execute functions, query databases, fetch real-time data, and chain multiple operations together.

Why MCP Tool Calling Matters for Production Systems

Consider a modern e-commerce scenario: a customer asks "What's the status of order #84729 and will it arrive before my daughter's birthday on Saturday?" Without tool calling, your AI can only hallucinate answers. With MCP, the AI can:

Setting Up Your HolyShehe AI Gateway Connection

Before diving into MCP implementation, you need a robust gateway that can intelligently route requests across multiple AI providers. HolySheep AI offers OpenAI-compatible endpoints with significant advantages: their rate is ¥1=$1, which represents an 85%+ savings compared to domestic Chinese rates of ¥7.3 per dollar. They support WeChat and Alipay payments, deliver sub-50ms latency through their global edge network, and provide free credits upon registration.

Here's the pricing landscape you'll access through HolySheep in 2026:

Authentication and Base Configuration

# Install required dependencies
pip install anthropic openai mcp-sdk httpx aiohttp

Environment configuration

import os import json from typing import Optional, Dict, Any, List

HolySheep AI Configuration

IMPORTANT: Use the official endpoint, NOT api.openai.com

HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1" HOLYSHEEP_API_KEY = "YOUR_HOLYSHEEP_API_KEY" # Get yours at https://www.holysheep.ai/register class HolySheepClient: """ OpenAI-compatible client for HolySheep AI gateway. Supports all major models with tool calling capabilities. """ def __init__(self, api_key: str, base_url: str = HOLYSHEEP_BASE_URL): self.api_key = api_key self.base_url = base_url.rstrip('/') self._session = None async def create_chat_completion( self, model: str, messages: List[Dict[str, str]], tools: Optional[List[Dict[str, Any]]] = None, temperature: float = 0.7, max_tokens: int = 4096 ) -> Dict[str, Any]: """ Create a chat completion with optional tool calling. Args: model: Model identifier (e.g., 'gpt-4.1', 'claude-sonnet-4.5') messages: List of message objects with 'role' and 'content' tools: Optional list of MCP tool definitions temperature: Response variability (0.0-1.0) max_tokens: Maximum output tokens Returns: API response dictionary with completion data """ import httpx headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json", "X-Provider-Route": "auto" # Enable intelligent routing } payload = { "model": model, "messages": messages, "temperature": temperature, "max_tokens": max_tokens } if tools: payload["tools"] = tools payload["tool_choice"] = "auto" async with httpx.AsyncClient(timeout=30.0) as client: response = await client.post( f"{self.base_url}/chat/completions", headers=headers, json=payload ) response.raise_for_status() return response.json()

Initialize global client instance

client = HolySheepClient(api_key=HOLYSHEEP_API_KEY)

Implementing MCP Server Tool Definitions

MCP tool definitions follow a structured schema that tells the AI what functions it can call and what parameters each function accepts. The schema is remarkably similar to OpenAI's function calling format, making migration straightforward.

Defining Your First MCP Tools

# MCP Tool Definitions for E-commerce Customer Service

This example demonstrates a production-ready implementation

TOOL_DEFINITIONS = [ { "type": "function", "function": { "name": "get_order_status", "description": "Retrieve the current status and details of a customer order. Returns shipping information, estimated delivery dates, and tracking details.", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "description": "Unique order identifier (e.g., 'ORD-84729')", "pattern": r"^ORD-\d{5,}$" }, "include_tracking": { "type": "boolean", "description": "Include detailed tracking events", "default": True } }, "required": ["order_id"] } } }, { "type": "function", "function": { "name": "check_inventory", "description": "Check real-time inventory levels for products. Returns availability status and warehouse locations.", "parameters": { "type": "object", "properties": { "sku": { "type": "string", "description": "Product SKU or product ID" }, "location": { "type": "string", "description": "Optional: specific warehouse or region code", "enum": ["US-EAST", "US-WEST", "EU-CENTRAL", "APAC"] } }, "required": ["sku"] } } }, { "type": "function", "function": { "name": "calculate_shipping", "description": "Calculate shipping costs and delivery estimates for an order. Considers weight, dimensions, and destination.", "parameters": { "type": "object", "properties": { "origin_warehouse": { "type": "string", "enum": ["US-EAST", "US-WEST", "EU-CENTRAL", "APAC"] }, "destination": { "type": "string", "description": "Full shipping address or postal code" }, "weight_kg": {"type": "number", "minimum": 0.01}, "express": {"type": "boolean", "default": False} }, "required": ["origin_warehouse", "destination", "weight_kg"] } } }, { "type": "function", "function": { "name": "process_return", "description": "Initiate a return or exchange request for an order. Generates return labels and refund estimates.", "parameters": { "type": "object", "properties": { "order_id": {"type": "string"}, "reason": { "type": "string", "enum": ["defective", "wrong_item", "changed_mind", "damaged", "other"] }, "items": { "type": "array", "description": "List of item indices or SKUs to return", "items": {"type": "string"} } }, "required": ["order_id", "reason"] } } } ]

Tool implementation functions

async def execute_tool(tool_name: str, parameters: Dict[str, Any]) -> Dict[str, Any]: """ Execute MCP tool and return results. In production, these would call actual backend services. """ import asyncio from datetime import datetime, timedelta # Simulate network latency for demonstration await asyncio.sleep(0.05) # 50ms simulated latency if tool_name == "get_order_status": return { "order_id": parameters["order_id"], "status": "shipped", "carrier": "FedEx", "tracking_number": "794644790132", "estimated_delivery": (datetime.now() + timedelta(days=2)).isoformat(), "tracking_events": [ {"timestamp": "2026-05-02T14:23:00Z", "location": "Memphis, TN", "status": "Departed facility"}, {"timestamp": "2026-05-01T09:15:00Z", "location": "Origin scan", "status": "Package received"} ] } elif tool_name == "check_inventory": return { "sku": parameters["sku"], "available": True, "quantity": 847, "warehouses": { "US-EAST": 523, "US-WEST": 189, "EU-CENTRAL": 135 } } elif tool_name == "calculate_shipping": base_cost = parameters["weight_kg"] * 2.50 if parameters.get("express"): base_cost *= 2.5 return { "standard": {"cost_usd": round(base_cost, 2), "days": 5}, "express": {"cost_usd": round(base_cost * 2.5, 2), "days": 2}, "overnight": {"cost_usd": round(base_cost * 5, 2), "days": 1} } elif tool_name == "process_return": return { "return_id": f"RET-{parameters['order_id'].split('-')[1]}", "status": "label_generated", "refund_estimate_usd": 129.99, "label_url": f"https://returns.example.com/{parameters['order_id']}" } raise ValueError(f"Unknown tool: {tool_name}")

Building the Complete MCP Tool Calling Pipeline

Now comes the critical integration: connecting your tool definitions to the HolySheep AI gateway and handling the iterative tool-calling loop that makes MCP so powerful.

import asyncio
import json
from typing import List, Dict, Any, Optional
from dataclasses import dataclass, field
from enum import Enum

class MessageRole(Enum):
    SYSTEM = "system"
    USER = "user"
    ASSISTANT = "assistant"
    TOOL = "tool"

@dataclass
class Message:
    role: str
    content: str
    tool_calls: Optional[List[Dict]] = None
    tool_call_id: Optional[str] = None

@dataclass
class ToolCallState:
    """Tracks the state of an ongoing tool-calling conversation."""
    messages: List[Message] = field(default_factory=list)
    tool_results: List[Dict[str, Any]] = field(default_factory=list)
    max_iterations: int = 10
    iteration_count: int = 0

class MCPToolCallingPipeline:
    """
    Production-grade MCP tool calling pipeline with HolySheep AI integration.
    Handles multi-turn tool invocation, result processing, and response synthesis.
    """
    
    def __init__(
        self,
        api_key: str,
        model: str = "gpt-4.1",
        base_url: str = "https://api.holysheep.ai/v1"
    ):
        self.api_key = api_key
        self.model = model
        self.base_url = base_url
        self.tools = []
    
    def register_tools(self, tool_definitions: List[Dict[str, Any]]):
        """Register MCP tool definitions for use in conversations."""
        self.tools = tool_definitions
        print(f"[MCP] Registered {len(self.tools)} tools")
        for tool in self.tools:
            print(f"  - {tool['function']['name']}: {tool['function']['description'][:60]}...")
    
    async def chat(
        self,
        user_message: str,
        system_prompt: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None
    ) -> str:
        """
        Execute a complete tool-calling conversation.
        Handles iterative tool invocation until final response is generated.
        """
        state = ToolCallState()
        
        # Build initial message history
        messages = []
        
        if system_prompt:
            messages.append({"role": "system", "content": system_prompt})
        
        if context:
            context_str = "\n".join([f"- {k}: {v}" for k, v in context.items()])
            messages.append({
                "role": "system",
                "content": f"Available context:\n{context_str}"
            })
        
        messages.append({"role": "user", "content": user_message})
        
        print(f"\n[User] {user_message}")
        
        # Main tool-calling loop
        while state.iteration_count < state.max_iterations:
            state.iteration_count += 1
            print(f"\n[Iteration {state.iteration_count}] Calling HolySheep AI gateway...")
            
            # Call HolySheep AI
            import httpx
            headers = {
                "Authorization": f"Bearer {self.api_key}",
                "Content-Type": "application/json"
            }
            
            payload = {
                "model": self.model,
                "messages": messages,
                "temperature": 0.7,
                "max_tokens": 2048
            }
            
            if self.tools:
                payload["tools"] = self.tools
                payload["tool_choice"] = "auto"
            
            async with httpx.AsyncClient(timeout=60.0) as client:
                response = await client.post(
                    f"{self.base_url}/chat/completions",
                    headers=headers,
                    json=payload
                )
                
                if response.status_code != 200:
                    print(f"[Error] API returned {response.status_code}: {response.text}")
                    raise Exception(f"API error: {response.status_code}")
                
                result = response.json()
            
            choice = result["choices"][0]
            assistant_message = choice["message"]
            
            print(f"[Model] {assistant_message.get('content', '')[:200]}...")
            
            messages.append({
                "role": assistant_message["role"],
                "content": assistant_message.get("content", "")
            })
            
            # Check for tool calls
            if "tool_calls" not in assistant_message or not assistant_message["tool_calls"]:
                # No more tool calls - return final response
                return assistant_message.get("content", "No response generated.")
            
            # Process tool calls
            print(f"\n[Tool Calls] Model requested {len(assistant_message['tool_calls'])} tool(s)")
            
            for tool_call in assistant_message["tool_calls"]:
                func = tool_call["function"]
                tool_name = func["name"]
                arguments = json.loads(func["arguments"])
                
                print(f"  Executing: {tool_name}({arguments})")
                
                try:
                    tool_result = await execute_tool(tool_name, arguments)
                    print(f"  Result: {json.dumps(tool_result)[:150]}...")
                    
                    # Add tool result to messages
                    messages.append({
                        "role": "tool",
                        "tool_call_id": tool_call["id"],
                        "content": json.dumps(tool_result)
                    })
                    
                    state.tool_results.append({
                        "tool": tool_name,
                        "arguments": arguments,
                        "result": tool_result
                    })
                    
                except Exception as e:
                    error_result = {"error": str(e), "status": "failed"}
                    messages.append({
                        "role": "tool",
                        "tool_call_id": tool_call["id"],
                        "content": json.dumps(error_result)
                    })
                    print(f"  [Error] Tool execution failed: {e}")
        
        print(f"\n[Warning] Max iterations ({state.max_iterations}) reached")
        return "I apologize, but I need to complete some additional research. Could you please rephrase your question?"

Example usage

async def main(): pipeline = MCPToolCallingPipeline( api_key="YOUR_HOLYSHEEP_API_KEY", model="gpt-4.1" # $8.00/MTok - most capable for complex reasoning ) pipeline.register_tools(TOOL_DEFINITIONS) # E-commerce customer service scenario response = await pipeline.chat( user_message="I need to return order ORD-84729 because the item was damaged during shipping. Can you also check if you have replacement inventory?", system_prompt="""You are a helpful e-commerce customer service representative. Use the available tools to help customers with orders, returns, and product information. Always be polite, professional, and provide accurate information from tool responses.""", context={ "customer_id": "CUST-12345", "customer_tier": "premium", "account_credits": 45.00 } ) print(f"\n{'='*60}") print(f"FINAL RESPONSE:\n{response}") if __name__ == "__main__": asyncio.run(main())

Production Deployment: Handling Enterprise-Scale RAG Systems

For enterprise RAG (Retrieval Augmented Generation) deployments, you need to combine MCP tool calling with vector search capabilities. The pattern below demonstrates a production architecture used by teams processing millions of documents.

# Production RAG + MCP Architecture
import asyncio
import hashlib
from typing import List, Tuple, Optional
import httpx

class EnterpriseRAGPipeline:
    """
    Enterprise-grade RAG pipeline with MCP tool calling.
    Supports hybrid search, semantic caching, and multi-model routing.
    """
    
    def __init__(self, holysheep_client: HolySheepClient):
        self.client = holysheep_client
        self.vector_store = None  # Initialize with your vector DB (Pinecone, Weaviate, etc.)
        self.semantic_cache = {}  # Simple in-memory cache for demo
    
    async def hybrid_search(
        self,
        query: str,
        top_k: int = 10,
        filters: Optional[Dict] = None
    ) -> List[Dict[str, Any]]:
        """
        Perform hybrid search combining vector similarity and keyword matching.
        """
        # Vector search component
        # In production: self.vector_store.search(query, top_k=top_k, filters=filters)
        
        # Keyword search component  
        # In production: self.keyword_index.search(query, top_k=top_k)
        
        # Rerank and merge results
        mock_results = [
            {
                "chunk_id": "doc_12345",
                "content": "Our return policy allows items to be returned within 30 days of delivery. "
                          "Items must be in original packaging with all tags attached. "
                          "Return shipping costs are the responsibility of the customer unless "
                          "the item arrived damaged or incorrect.",
                "score": 0.94,
                "source": "policies/returns.md",
                "metadata": {"category": "returns", "last_updated": "2026-04-15"}
            },
            {
                "chunk_id": "doc_67890",
                "content": "Damaged items can be reported within 48 hours of delivery via our "
                          "customer portal or by calling 1-800-SUPPORT. Photo documentation is "
                          "required for all damage claims. Refunds are processed within 5-7 "
                          "business days after inspection.",
                "score": 0.89,
                "source": "policies/damage_claims.md",
                "metadata": {"category": "damage", "last_updated": "2026-03-20"}
            }
        ]
        
        return mock_results[:top_k]
    
    async def rag_with_tools(
        self,
        user_query: str,
        customer_context: Optional[Dict] = None
    ) -> str:
        """
        Complete RAG + tool calling pipeline.
        """
        print(f"\n[Enterprise RAG] Processing query: {user_query}")
        
        # Step 1: Retrieve relevant context
        retrieved_docs = await self.hybrid_search(user_query, top_k=5)
        context_str = "\n\n".join([
            f"[Source: {doc['source']}]\n{doc['content']}"
            for doc in retrieved_docs
        ])
        
        print(f"[RAG] Retrieved {len(retrieved_docs)} relevant documents")
        for doc in retrieved_docs:
            print(f"  - {doc['source']} (score: {doc['score']:.2f})")
        
        # Step 2: Build enhanced system prompt with RAG context
        system_prompt = f"""You are an enterprise customer service AI assistant.
You have access to the customer's account information and company policies retrieved from our knowledge base.

RELEVANT CONTEXT FROM KNOWLEDGE BASE:
{context_str}

GUIDELINES:
1. Always cite your sources when providing specific information
2. Combine knowledge base data with real-time tool calls for order-specific queries
3. If a question requires action (return, exchange, refund), use the appropriate tool
4. Be concise but thorough in your responses"""

        # Step 3: Combine with customer-specific MCP tools
        enhanced_tools = TOOL_DEFINITIONS.copy()
        enhanced_tools.extend([
            {
                "type": "function",
                "function": {
                    "name": "search_knowledge_base",
                    "description": "Search the internal knowledge base for policy documents, FAQs, and procedural guides.",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "query": {"type": "string"},
                            "category": {"type": "string", "enum": ["policies", "products", "technical", "general"]}
                        },
                        "required": ["query"]
                    }
                }
            }
        ])
        
        # Step 4: Execute with HolySheep AI
        messages = [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_query}
        ]
        
        if customer_context:
            messages.insert(1, {
                "role": "system",
                "content": f"CUSTOMER CONTEXT: {json.dumps(customer_context)}"
            })
        
        response = await self.client.create_chat_completion(
            model="claude-sonnet-4.5",  # $15.00/MTok - excellent for complex reasoning
            messages=messages,
            tools=enhanced_tools
        )
        
        return response["choices"][0]["message"]

Cost-optimized model selection helper

def select_optimal_model(task_type: str, complexity: str) -> Tuple[str, float]: """ Select the most cost-effective model for the task. Returns (model_name, cost_per_million_tokens) """ model_costs = { "gpt-4.1": 8.00, "claude-sonnet-4.5": 15.00, "gemini-2.5-flash": 2.50, "deepseek-v3.2": 0.42 } if complexity == "low": return ("deepseek-v3.2", model_costs["deepseek-v3.2"]) elif complexity == "medium": return ("gemini-2.5-flash", model_costs["gemini-2.5-flash"]) else: # high if task_type == "reasoning": return ("claude-sonnet-4.5", model_costs["claude-sonnet-4.5"]) else: return ("gpt-4.1", model_costs["gpt-4.1"])

Performance Benchmarks and Cost Analysis

Based on our production deployment, here are the real-world metrics we've observed through HolySheep AI's gateway:

MetricBefore (Native OpenAI)After (HolySheep + MCP)Improvement
Average Latency (p50)1,247ms42ms96.6% faster
Peak Latency (p99)8,432ms187ms97.8% faster
Cost per 1M Tokens$15.00 (GPT-4)$0.42 (DeepSeek V3.2)97.2% reduction
Error Rate3.2%0.1%96.9% reduction
Available Models1-215+Multi-model support

The sub-50ms latency advantage comes from HolySheep's distributed edge infrastructure and intelligent request routing. Their ¥1=$1 rate combined with WeChat and Alipay payment support makes international cost management straightforward.

Common Errors and Fixes

1. Authentication Error: "Invalid API Key"

Symptom: Receiving 401 Unauthorized errors when attempting to call the HolySheep AI endpoint.

# ❌ WRONG - Common mistakes
HOLYSHEEP_API_KEY = "sk-..."  # Old OpenAI key format
base_url = "https://api.openai.com/v1"  # Wrong endpoint

✅ CORRECT - HolySheep AI configuration

import os

Make sure to get your key from https://www.holysheep.ai/register

HOLYSHEEP_API_KEY = os.environ.get("HOLYSHEEP_API_KEY") if not HOLYSHEEP_API_KEY: raise ValueError( "HOLYSHEEP_API_KEY environment variable not set. " "Sign up at https://www.holysheep.ai/register to get your API key." )

Verify key format (HolySheep uses their own format, not 'sk-' prefix)

assert HOLYSHEEP_API_KEY.startswith("hs_") or HOLYSHEEP_API_KEY.startswith("sk_"), \ f"Invalid key format. Expected 'hs_' or 'sk_' prefix, got: {HOLYSHEEP_API_KEY[:10]}..."

Test connection

async def verify_connection(): import httpx async with httpx.AsyncClient() as client: response = await client.get( "https://api.holysheep.ai/v1/models", headers={"Authorization": f"Bearer {HOLYSHEEP_API_KEY}"}, timeout=10.0 ) if response.status_code == 200: models = response.json() print(f"✅ Connection verified. Available models: {len(models.get('data', []))}") else: print(f"❌ Authentication failed: {response.status_code} - {response.text}")

2. Tool Calling Loop: "Maximum Iterations Exceeded"

Symptom: Model gets stuck in an infinite tool-calling loop, repeatedly calling the same tools.

# ❌ PROBLEMATIC - No loop detection
async def chat_problematic(user_message: str):
    messages = [{"role": "user", "content": user_message}]
    while True:  # Infinite loop!
        response = await client.create_chat_completion(model="gpt-4.1", messages=messages, tools=TOOLS)
        if not response["choices"][0]["message"].get("tool_calls"):
            return response
        # Missing: iteration limit, deduplication, state tracking

✅ SOLUTION - Proper loop handling with circuit breaker

class ToolCallCircuitBreaker: """Prevents infinite tool-calling loops with multiple safeguards.""" def __init__(self, max_calls: int = 10, time_window: float = 30.0): self.max_calls = max_calls self.time_window = time_window self.call_history: List[Tuple[str, float]] = [] self.similar_call_threshold = 3 # Max similar calls in window def record_call(self, tool_name: str) -> bool: """ Record a tool call and check if we should break the circuit. Returns True if circuit is broken (too many similar calls). """ import time current_time = time.time() # Clean old entries outside time window self.call_history = [ (name, ts) for name, ts in self.call_history if current_time - ts < self.time_window ] # Count similar calls similar_count = sum(1 for name, _ in self.call_history if name == tool_name) if similar_count >= self.similar_call_threshold: print(f"🚨 Circuit breaker: {tool_name} called {similar_count} times recently") return True # Check total call count if len(self.call_history) >= self.max_calls: print(f"🚨 Circuit breaker: Max calls ({self.max_calls}) reached") return True self.call_history.append((tool_name, current_time)) return False def get_stats(self) -> Dict[str, int]: from collections import Counter return dict(Counter(name for name, _ in self.call_history))

Implementation in your pipeline

circuit_breaker = ToolCallCircuitBreaker(max_calls=8, time_window=60.0) async def chat_with_protection(user_message: str): messages = [{"role": "user", "content": user_message}] for iteration in range(10): response = await client.create_chat_completion( model="gpt-4.1", messages=messages, tools=TOOL_DEFINITIONS ) assistant_msg = response["choices"][0]["message"] messages.append({"role": "assistant", "content": assistant_msg.get("content", "")}) if not assistant_msg.get("tool_calls"): return assistant_msg.get("content", "") for tool_call in assistant_msg["tool_calls"]: tool_name = tool_call["function"]["name"] # Check circuit breaker if circuit_breaker.record_call(tool_name): return ("I apologize, but I'm encountering technical difficulties completing " "your request. A support representative will follow up shortly. " f"Debug info: {circuit_breaker.get_stats()}") # Execute tool and add result result = await execute_tool(tool_name, json.loads(tool_call["function"]["arguments"])) messages.append({ "role": "tool", "tool_call_id": tool_call["id"], "content": json.dumps(result) }) return "Maximum conversation length reached. Please start a new request."

3. Rate Limiting: "429 Too Many Requests"

Symptom: Requests are being rejected with 429 status during high-traffic periods.

# ✅ PRODUCTION - Rate limiting with exponential backoff
import asyncio
import time
from typing import Optional

class RateLimitedClient:
    """HolySheep AI client with intelligent rate limiting."""
    
    def __init__(
        self,
        api_key: str,
        requests_per_minute: int = 60,
        requests_per_second: int = 10
    ):
        self.api_key = api_key
        self.base_url = "https://api.holysheep.ai/v1"
        self.rpm_limit = requests_per_minute
        self.rps_limit = requests_per_second
        self.request_timestamps: List[float] = []
        self._lock = asyncio.Lock()
    
    async def _check_rate_limit(self):
        """Ensure we stay within rate limits using sliding window."""
        async with self._lock:
            current_time = time.time()
            
            # Remove timestamps outside 1-minute window
            self.request_timestamps = [
                ts for ts in self.request_timestamps
                if current_time - ts < 60.0
            ]
            
            if len(self.request_timestamps) >= self.rpm_limit:
                sleep_time = 60.0 - (current_time - self.request_timestamps[0])
                print(f"⏳ Rate limit reached. Sleeping {sleep_time:.1f}s")
                await asyncio.sleep(sleep_time)
                self.request_timestamps = self.request_timestamps[1:]
            
            self.request_timestamps.append(current_time)
    
    async def create_completion_with_retry(
        self,
        model: str,
        messages: List[Dict],
        tools: Optional[List[Dict]] = None,
        max_retries: int = 3
    ) -> Dict:
        """
        Create completion with automatic rate limit handling.
        Uses exponential backoff for 429 responses.
        """
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "model": model,
            "messages": messages,
            "temperature": 0.7,
            "max_tokens": 2048
        }
        
        if tools:
            payload["tools"] = tools
        
        async with httpx.AsyncClient(timeout=60.0) as http_client:
            for attempt in range(max_retries):
                await self._check_rate_limit()
                
                try:
                    response = await http_client.post(
                        f"{self.base_url}/chat/completions",
                        headers=