{ "cells": [ { "cell_type": "raw", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "# 🛡️ Error Handling in MCP Tools\n", "\n", "Learn how to implement robust error handling in your MCP tools. This notebook covers error types, handling strategies, and best practices for creating reliable tools.\n", "\n", "## 🎯 Learning Objectives\n", "\n", "By the end of this notebook, you will:\n", "- Understand MCP error types\n", "- Implement error handling strategies\n", "- Create custom error types\n", "- Build error recovery mechanisms\n", "- Design fault-tolerant tools\n", "\n", "## 📋 Prerequisites\n", "\n", "- Completed notebooks 01-09\n", "- Basic exception handling knowledge\n", "- Python virtual environment with required packages\n", "\n", "## 🔑 Key Concepts\n", "\n", "1. **Error Types**\n", " - Validation errors\n", " - Runtime errors\n", " - System errors\n", " - User errors\n", "\n", "2. **Handling Strategies**\n", " - Try-except patterns\n", " - Error recovery\n", " - Graceful degradation\n", " - Fault tolerance\n", "\n", "3. **Error Communication**\n", " - Error messages\n", " - Status codes\n", " - Error context\n", " - Recovery hints\n", "\n", "## 📚 Table of Contents\n", "\n", "1. [Understanding MCP Errors](#understanding)\n", "2. [Error Handling Patterns](#patterns)\n", "3. [Custom Error Types](#custom)\n", "4. [Recovery Strategies](#recovery)\n", "5. [Best Practices](#practices)\n", "\n", "---\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from typing import Optional, Dict, Any\n", "from enum import Enum\n", "import modelcontextprotocol as mcp\n", "from pydantic import BaseModel, Field\n", "\n", "# Custom error types\n", "class MCPErrorType(Enum):\n", " VALIDATION = \"validation\"\n", " RUNTIME = \"runtime\"\n", " SYSTEM = \"system\"\n", " USER = \"user\"\n", " \n", "class MCPError(Exception):\n", " \"\"\"Base class for MCP errors.\"\"\"\n", " def __init__(self, message: str, error_type: MCPErrorType, details: Optional[Dict[str, Any]] = None):\n", " self.message = message\n", " self.error_type = error_type\n", " self.details = details or {}\n", " super().__init__(self.message)\n", " \n", "class ValidationError(MCPError):\n", " \"\"\"Raised when input validation fails.\"\"\"\n", " def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):\n", " super().__init__(message, MCPErrorType.VALIDATION, details)\n", " \n", "class RuntimeError(MCPError):\n", " \"\"\"Raised when an error occurs during tool execution.\"\"\"\n", " def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):\n", " super().__init__(message, MCPErrorType.RUNTIME, details)\n", " \n", "class SystemError(MCPError):\n", " \"\"\"Raised when a system-level error occurs.\"\"\"\n", " def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):\n", " super().__init__(message, MCPErrorType.SYSTEM, details)\n", " \n", "class UserError(MCPError):\n", " \"\"\"Raised when user input or action causes an error.\"\"\"\n", " def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):\n", " super().__init__(message, MCPErrorType.USER, details)\n", " \n", "# Input/Output models\n", "class ErrorResponse(BaseModel):\n", " error_type: MCPErrorType\n", " message: str\n", " details: Optional[Dict[str, Any]] = None\n", " \n", "class CalculatorInput(BaseModel):\n", " operation: str = Field(..., description=\"Mathematical operation to perform\")\n", " x: float = Field(..., description=\"First number\")\n", " y: float = Field(..., description=\"Second number\")\n", " \n", "class CalculatorOutput(BaseModel):\n", " result: float\n", " operation: str\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Calculator:\n", " \"\"\"A calculator tool that demonstrates error handling.\"\"\"\n", " \n", " VALID_OPERATIONS = {\n", " '+': lambda x, y: x + y,\n", " '-': lambda x, y: x - y,\n", " '*': lambda x, y: x * y,\n", " '/': lambda x, y: x / y,\n", " '**': lambda x, y: x ** y\n", " }\n", " \n", " def validate_input(self, input_data: CalculatorInput):\n", " \"\"\"Validate calculator input.\"\"\"\n", " if input_data.operation not in self.VALID_OPERATIONS:\n", " raise ValidationError(\n", " f\"Invalid operation: {input_data.operation}\",\n", " details={\n", " \"valid_operations\": list(self.VALID_OPERATIONS.keys()),\n", " \"provided\": input_data.operation\n", " }\n", " )\n", " \n", " if input_data.operation == '/' and input_data.y == 0:\n", " raise UserError(\n", " \"Division by zero\",\n", " details={\n", " \"x\": input_data.x,\n", " \"y\": input_data.y,\n", " \"operation\": input_data.operation\n", " }\n", " )\n", " \n", " if input_data.operation == '**' and input_data.y > 100:\n", " raise ValidationError(\n", " \"Exponent too large\",\n", " details={\n", " \"max_exponent\": 100,\n", " \"provided\": input_data.y\n", " }\n", " )\n", " \n", " async def calculate(self, input_data: CalculatorInput) -> CalculatorOutput:\n", " \"\"\"Perform calculation with error handling.\"\"\"\n", " try:\n", " # Validate input\n", " self.validate_input(input_data)\n", " \n", " # Perform calculation\n", " operation_func = self.VALID_OPERATIONS[input_data.operation]\n", " result = operation_func(input_data.x, input_data.y)\n", " \n", " # Check for overflow\n", " if abs(result) > 1e308: # Max float value\n", " raise RuntimeError(\n", " \"Result too large\",\n", " details={\n", " \"result\": \"overflow\",\n", " \"operation\": input_data.operation\n", " }\n", " )\n", " \n", " return CalculatorOutput(\n", " result=result,\n", " operation=input_data.operation\n", " )\n", " \n", " except MCPError:\n", " # Re-raise MCP errors\n", " raise\n", " except Exception as e:\n", " # Convert other exceptions to MCPError\n", " raise SystemError(\n", " f\"Unexpected error: {str(e)}\",\n", " details={\n", " \"error_type\": type(e).__name__,\n", " \"operation\": input_data.operation\n", " }\n", " )\n", "\n", "# Create calculator tool\n", "calculator = Calculator()\n", "\n", "# Create MCP server\n", "server = mcp.Server()\n", "server.add_tool(\"calculator\", calculator.calculate, CalculatorInput, CalculatorOutput)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import asyncio\n", "\n", "async def test_calculator():\n", " # Test valid operations\n", " print(\"Testing valid operations:\")\n", " try:\n", " result = await calculator.calculate(CalculatorInput(operation=\"+\", x=5, y=3))\n", " print(f\"5 + 3 = {result.result}\")\n", " except MCPError as e:\n", " print(f\"Error: {e.message}\")\n", " \n", " # Test invalid operation\n", " print(\"\\nTesting invalid operation:\")\n", " try:\n", " result = await calculator.calculate(CalculatorInput(operation=\"%\", x=10, y=2))\n", " print(result)\n", " except MCPError as e:\n", " print(f\"Error type: {e.error_type}\")\n", " print(f\"Message: {e.message}\")\n", " print(f\"Details: {e.details}\")\n", " \n", " # Test division by zero\n", " print(\"\\nTesting division by zero:\")\n", " try:\n", " result = await calculator.calculate(CalculatorInput(operation=\"/\", x=1, y=0))\n", " print(result)\n", " except MCPError as e:\n", " print(f\"Error type: {e.error_type}\")\n", " print(f\"Message: {e.message}\")\n", " print(f\"Details: {e.details}\")\n", " \n", " # Test exponent too large\n", " print(\"\\nTesting large exponent:\")\n", " try:\n", " result = await calculator.calculate(CalculatorInput(operation=\"**\", x=2, y=1000))\n", " print(result)\n", " except MCPError as e:\n", " print(f\"Error type: {e.error_type}\")\n", " print(f\"Message: {e.message}\")\n", " print(f\"Details: {e.details}\")\n", "\n", "# Run the tests\n", "await test_calculator()\n" ] }, { "cell_type": "raw", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "# Error Handling Best Practices\n", "\n", "When implementing error handling in MCP tools, follow these best practices:\n", "\n", "## 1. Error Classification\n", "\n", "Properly categorize errors into types:\n", "- **Validation Errors**: Input validation failures\n", "- **Runtime Errors**: Errors during execution\n", "- **System Errors**: Infrastructure/environment issues\n", "- **User Errors**: Invalid user actions/input\n", "\n", "## 2. Error Context\n", "\n", "Include helpful information in error messages:\n", "- Clear error descriptions\n", "- Relevant context\n", "- Possible solutions\n", "- Recovery steps\n", "\n", "## 3. Error Recovery\n", "\n", "Implement recovery mechanisms:\n", "- Retry logic for transient errors\n", "- Fallback options\n", "- Graceful degradation\n", "- State recovery\n", "\n", "## 4. Error Logging\n", "\n", "Maintain comprehensive error logs:\n", "- Error type and message\n", "- Stack traces\n", "- Context data\n", "- Timestamp and environment\n", "\n", "## 5. User Communication\n", "\n", "Provide user-friendly error messages:\n", "- Clear explanations\n", "- Action items\n", "- Alternative solutions\n", "- Support resources\n", "\n", "## Exercise\n", "\n", "Improve our calculator tool with:\n", "\n", "1. Retry logic for transient errors\n", "2. Fallback operations\n", "3. Error logging\n", "4. User-friendly messages\n" ] }, { "cell_type": "raw", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "# 🛡️ Error Handling & Validation\n", "\n", "Build robust, production-ready MCP servers! Master comprehensive error handling, input validation, logging, and monitoring to create reliable AI tool integrations.\n", "\n", "## 🎯 Learning Objectives\n", "\n", "By the end of this notebook, you will:\n", "- Implement comprehensive error handling strategies\n", "- Build robust input validation systems\n", "- Create proper logging and monitoring\n", "- Handle edge cases and failure modes\n", "- Design graceful degradation patterns\n", "\n", "## 🔧 Error Types & Handling\n", "\n", "- **🚨 Validation Errors**: Invalid inputs and parameters\n", "- **🌐 Network Errors**: API failures and timeouts \n", "- **💾 Storage Errors**: Database and file system issues\n", "- **🔒 Security Errors**: Authentication and authorization failures\n", "- **⚡ System Errors**: Resource exhaustion and crashes\n", "\n", "## 📚 Table of Contents\n", "\n", "1. [Error Classification & Strategy](#classification)\n", "2. [Input Validation Patterns](#validation)\n", "3. [Logging & Monitoring](#logging)\n", "4. [Retry & Circuit Breaker Patterns](#resilience)\n", "5. [Testing Error Scenarios](#testing)\n", "\n", "---\n" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 2 }