[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6JDSV6AMD00R6Q0P2BEPYA1":3,"skill-same:01M6JDSV6AMD00R6Q0P2BEPYA1":78},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":25,"publishedAt":46,"linkOnly":47,"markdownContent":48,"markdownBody":49,"frontMatter":50,"refName":51,"commitSha":52,"skillDirectory":53,"forksCount":13,"repositoryHtmlUrl":54,"repositoryHomepageUrl":6,"ownerHtmlUrl":55,"ownerBlogUrl":6,"ownerDescription":56,"updatedAt":57,"install":58,"resources":71},"01M6JDSV6AMD00R6Q0P2BEPYA1","mcp-server",null,"Generic MCP (Model Context Protocol) server development patterns. Provides reusable architecture and best practices for building MCP servers that expose any domain-specific operations as tools for AI agents. Framework-agnostic implementation supporting async operations, error handling, and enterprise-grade features.","superhealth\u002Fskills-hub","superhealth","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6292112?v=4","01M6JA6E7F21BYK5W3E4P270TT","01M6JA6EC0W8MPHKDJVBZDSEZ0",0,"MIT","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fazeem-2\u002Fmcp-server\u002FSKILL.md",[17,22],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发",[26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],"mcp server","server","MCP","model","for","framework-agnostic","building mcp servers","error","as","domain-specific","domain","reusable","async","Enterprise","best practices","error handling","development","architecture","model context protocol","ai agents","2026-11-10 10:12:30",false,"---\nname: mcp-server\ndescription: Generic MCP (Model Context Protocol) server development patterns. Provides reusable architecture and best practices for building MCP servers that expose any domain-specific operations as tools for AI agents. Framework-agnostic implementation supporting async operations, error handling, and enterprise-grade features.\nlicense: MIT\n---\n\n# Generic MCP Server Development\n\nThis skill provides comprehensive patterns and reusable code for building MCP (Model Context Protocol) servers that can expose any domain operations as tools for AI agents. Follows 2025 best practices for performance, security, and maintainability.\n\n## When to Use This Skill\n\nUse this skill when you need to:\n- Build an MCP server for any domain (not just todos)\n- Expose database operations as MCP tools\n- Create AI-agent accessible APIs\n- Implement async MCP tool handlers\n- Add proper error handling and validation\n- Support rate limiting and caching\n- Build enterprise-grade MCP servers\n- Integrate with multiple storage backends\n\n## 1. Generic MCP Server Architecture\n\n```python\n# mcp_server\u002Fcore.py\n#!\u002Fusr\u002Fbin\u002Fenv python3\n\"\"\"\nGeneric MCP Server Base Architecture\nProvides reusable patterns for any MCP server implementation\n\"\"\"\n\nimport asyncio\nimport json\nimport logging\nfrom abc import ABC, abstractmethod\nfrom datetime import datetime, timedelta\nfrom typing import Any, Dict, List, Optional, Sequence, Union, Callable\nfrom contextlib import asynccontextmanager\nfrom dataclasses import dataclass, field\nfrom enum import Enum\n\nimport redis.asyncio as redis\nfrom mcp.server import Server, NotificationOptions, stdio\nfrom mcp.server.models import InitializationOptions\nfrom mcp.server.stdio import stdio_server\nfrom mcp.types import (\n    Resource, Tool, TextContent, ImageContent, EmbeddedResource,\n    LoggingLevel, CallToolRequest, EmptyResult,\n    ListResourcesRequest, ListToolsRequest, ReadResourceRequest,\n    GetPromptRequest, ListPromptsRequest\n)\nfrom pydantic import BaseModel, Field, validator\nimport aiofiles\nimport yaml\nfrom pathlib import Path\n\n# Configure logging\nlogging.basicConfig(\n    level=logging.INFO,\n    format=\"%(asctime)s - %(name)s - %(levelname)s - %(message)s\"\n)\nlogger = logging.getLogger(\"mcp_server\")\n\nclass ServerConfig(BaseModel):\n    \"\"\"MCP Server configuration\"\"\"\n    name: str\n    version: str = \"1.0.0\"\n    description: str\n    debug: bool = False\n    redis_url: Optional[str] = None\n    rate_limit_requests: int = 100\n    rate_limit_window: int = 60\n    cache_ttl: int = 300\n    max_retries: int = 3\n    timeout: int = 30\n\n    class Config:\n        extra = \"allow\"\n\n@dataclass\nclass RequestContext:\n    \"\"\"Request context for tool calls\"\"\"\n    user_id: str\n    session_id: Optional[str] = None\n    metadata: Dict[str, Any] = field(default_factory=dict)\n    timestamp: datetime = field(default_factory=datetime.utcnow)\n\nclass RateLimiter:\n    \"\"\"Redis-based rate limiter for MCP operations\"\"\"\n\n    def __init__(self, redis_url: str, requests: int, window: int):\n        self.redis_url = redis_url\n        self.requests = requests\n        self.window = window\n        self._redis = None\n\n    async def _get_redis(self):\n        if not self._redis:\n            self._redis = await redis.from_url(self.redis_url)\n        return self._redis\n\n    async def is_allowed(self, key: str) -> bool:\n        \"\"\"Check if request is allowed\"\"\"\n        r = await self._get_redis()\n        current = await r.incr(f\"rate_limit:{key}\")\n\n        if current == 1:\n            await r.expire(f\"rate_limit:{key}\", self.window)\n\n        return current \u003C= self.requests\n\n    async def get_remaining(self, key: str) -> int:\n        \"\"\"Get remaining requests\"\"\"\n        r = await self._get_redis()\n        current = await r.get(f\"rate_limit:{key}\")\n        return max(0, self.requests - int(current or 0))\n\nclass CacheManager:\n    \"\"\"Redis-based caching for MCP responses\"\"\"\n\n    def __init__(self, redis_url: str, ttl: int = 300):\n        self.redis_url = redis_url\n        self.ttl = ttl\n        self._redis = None\n\n    async def _get_redis(self):\n        if not self._redis:\n            self._redis = await redis.from_url(self.redis_url)\n        return self._redis\n\n    def _make_key(self, tool_name: str, args: Dict[str, Any]) -> str:\n        \"\"\"Generate cache key from tool name and arguments\"\"\"\n        import hashlib\n        args_str = json.dumps(args, sort_keys=True)\n        return f\"cache:{tool_name}:{hashlib.md5(args_str.encode()).hexdigest()}\"\n\n    async def get(self, tool_name: str, args: Dict[str, Any]) -> Optional[Any]:\n        \"\"\"Get cached result\"\"\"\n        r = await self._get_redis()\n        key = self._make_key(tool_name, args)\n        result = await r.get(key)\n        return json.loads(result) if result else None\n\n    async def set(self, tool_name: str, args: Dict[str, Any], value: Any):\n        \"\"\"Cache result\"\"\"\n        r = await self._get_redis()\n        key = self._make_key(tool_name, args)\n        await r.setex(key, self.ttl, json.dumps(value))\n\nclass BaseMCPServer:\n    \"\"\"Base MCP Server with common functionality\"\"\"\n\n    def __init__(self, config: ServerConfig):\n        self.config = config\n        self.server = Server(config.name)\n        self.tools: Dict[str, Callable] = {}\n        self.rate_limiter: Optional[RateLimiter] = None\n        self.cache: Optional[CacheManager] = None\n\n        # Setup optional components\n        if config.redis_url:\n            self.rate_limiter = RateLimiter(\n                config.redis_url,\n                config.rate_limit_requests,\n                config.rate_limit_window\n            )\n            self.cache = CacheManager(\n                config.redis_url,\n                config.cache_ttl\n            )\n\n        # Register handlers\n        self._register_handlers()\n\n        logger.info(f\"MCP Server '{config.name}' initialized\")\n\n    def _register_handlers(self):\n        \"\"\"Register MCP handlers\"\"\"\n        @self.server.list_tools()\n        async def handle_list_tools() -> List[Tool]:\n            \"\"\"Return list of available tools\"\"\"\n            return await self.list_tools()\n\n        @self.server.call_tool()\n        async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[TextContent]:\n            \"\"\"Handle tool call with rate limiting and caching\"\"\"\n            return await self.call_tool(name, arguments)\n\n    def register_tool(self, name: str, handler: Callable, schema: Dict[str, Any]):\n        \"\"\"Register a new tool\"\"\"\n        self.tools[name] = {\n            \"handler\": handler,\n            \"schema\": schema\n        }\n        logger.info(f\"Registered tool: {name}\")\n\n    async def list_tools(self) -> List[Tool]:\n        \"\"\"List all available tools\"\"\"\n        tools = []\n        for name, tool_info in self.tools.items():\n            tools.append(Tool(\n                name=name,\n                description=tool_info[\"schema\"].get(\"description\", \"\"),\n                inputSchema=tool_info[\"schema\"].get(\"inputSchema\", {})\n            ))\n        return tools\n\n    async def call_tool(self, name: str, arguments: Dict[str, Any]) -> List[TextContent]:\n        \"\"\"Execute a tool call with full middleware pipeline\"\"\"\n        start_time = datetime.utcnow()\n\n        try:\n            # Extract context from arguments\n            context = self._extract_context(arguments)\n\n            # Rate limiting check\n            if self.rate_limiter:\n                rate_key = f\"{context.user_id}:{name}\"\n                if not await self.rate_limiter.is_allowed(rate_key):\n                    return [TextContent(\n                        type=\"text\",\n                        text=json.dumps({\n                            \"status\": \"error\",\n                            \"error\": \"Rate limit exceeded\",\n                            \"remaining\": await self.rate_limiter.get_remaining(rate_key)\n                        })\n                    )]\n\n            # Check cache\n            if self.cache and self._is_cacheable(name):\n                cached_result = await self.cache.get(name, arguments)\n                if cached_result:\n                    logger.info(f\"Cache hit for tool: {name}\")\n                    return [TextContent(\n                        type=\"text\",\n                        text=json.dumps(cached_result)\n                    )]\n\n            # Validate tool exists\n            if name not in self.tools:\n                raise ValueError(f\"Unknown tool: {name}\")\n\n            # Validate arguments\n            schema = self.tools[name][\"schema\"]\n            self._validate_arguments(arguments, schema)\n\n            # Execute tool\n            handler = self.tools[name][\"handler\"]\n            result = await self._execute_tool(handler, arguments, context)\n\n            # Cache result if applicable\n            if self.cache and self._is_cacheable(name) and result.get(\"status\") != \"error\":\n                await self.cache.set(name, arguments, result)\n\n            # Log execution\n            duration = (datetime.utcnow() - start_time).total_seconds()\n            logger.info(f\"Tool {name} executed in {duration:.2f}s for user {context.user_id}\")\n\n            return [TextContent(\n                type=\"text\",\n                text=json.dumps(result, default=str)\n            )]\n\n        except Exception as e:\n            logger.error(f\"Error executing tool {name}: {str(e)}\", exc_info=True)\n            duration = (datetime.utcnow() - start_time).total_seconds()\n            logger.error(f\"Tool {name} failed after {duration:.2f}s\")\n\n            return [TextContent(\n                type=\"text\",\n                text=json.dumps({\n                    \"status\": \"error\",\n                    \"error\": str(e),\n                    \"tool\": name,\n                    \"timestamp\": datetime.utcnow().isoformat()\n                })\n            )]\n\n    def _extract_context(self, arguments: Dict[str, Any]) -> RequestContext:\n        \"\"\"Extract request context from arguments\"\"\"\n        user_id = arguments.pop(\"_user_id\", \"anonymous\")\n        session_id = arguments.pop(\"_session_id\", None)\n        metadata = arguments.pop(\"_metadata\", {})\n\n        return RequestContext(\n            user_id=user_id,\n            session_id=session_id,\n            metadata=metadata\n        )\n\n    def _validate_arguments(self, arguments: Dict[str, Any], schema: Dict[str, Any]):\n        \"\"\"Validate tool arguments against schema\"\"\"\n        # Basic validation - can be extended with pydantic\n        input_schema = schema.get(\"inputSchema\", {})\n        required = input_schema.get(\"required\", [])\n        properties = input_schema.get(\"properties\", {})\n\n        # Check required fields\n        for field in required:\n            if field not in arguments:\n                raise ValueError(f\"Missing required field: {field}\")\n\n        # Validate field types\n        for field, value in arguments.items():\n            if field in properties:\n                field_schema = properties[field]\n                expected_type = field_schema.get(\"type\")\n\n                if expected_type == \"string\" and not isinstance(value, str):\n                    raise ValueError(f\"Field {field} must be a string\")\n                elif expected_type == \"integer\" and not isinstance(value, int):\n                    raise ValueError(f\"Field {field} must be an integer\")\n                elif expected_type == \"array\" and not isinstance(value, list):\n                    raise ValueError(f\"Field {field} must be an array\")\n\n                # Check enum values\n                if \"enum\" in field_schema and value not in field_schema[\"enum\"]:\n                    raise ValueError(f\"Field {field} must be one of {field_schema['enum']}\")\n\n    def _is_cacheable(self, tool_name: str) -> bool:\n        \"\"\"Determine if tool result should be cached\"\"\"\n        # Non-mutating operations are cacheable\n        non_mutating = [\"get\", \"list\", \"search\", \"find\", \"read\"]\n        return any(op in tool_name.lower() for op in non_mutating)\n\n    async def _execute_tool(self, handler: Callable, arguments: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Execute tool handler with error handling\"\"\"\n        try:\n            # Pass context to handler if it accepts it\n            import inspect\n            sig = inspect.signature(handler)\n\n            if 'context' in sig.parameters:\n                result = await handler(arguments, context=context)\n            else:\n                result = await handler(arguments)\n\n            return result\n\n        except Exception as e:\n            logger.error(f\"Tool handler failed: {str(e)}\")\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n    async def run(self):\n        \"\"\"Start the MCP server\"\"\"\n        logger.info(f\"Starting MCP server: {self.config.name}\")\n        async with stdio_server() as (read_stream, write_stream):\n            await self.server.run(\n                read_stream,\n                write_stream,\n                InitializationOptions(\n                    server_name=self.config.name,\n                    server_version=self.config.version,\n                    capabilities=self.server.get_capabilities(\n                        notification_options=NotificationOptions(),\n                        experimental_capabilities={},\n                    )\n                )\n            )\n\ndef tool(\n    name: Optional[str] = None,\n    description: str = \"\",\n    input_schema: Optional[Dict[str, Any]] = None\n):\n    \"\"\"Decorator for registering MCP tools\"\"\"\n    def decorator(func):\n        tool_name = name or func.__name__\n        schema = {\n            \"description\": description or func.__doc__ or \"\",\n            \"inputSchema\": input_schema or {}\n        }\n\n        # Store schema on function for later registration\n        func._mcp_tool_schema = schema\n        func._mcp_tool_name = tool_name\n\n        return func\n    return decorator\n```\n\n## 2. Database Integration Patterns\n\n```python\n# mcp_server\u002Fdatabase.py\n\"\"\"\nGeneric Database Integration for MCP Servers\nSupports multiple ORMs and connection patterns\n\"\"\"\n\nimport asyncio\nfrom abc import ABC, abstractmethod\nfrom contextlib import asynccontextmanager\nfrom typing import Any, Dict, List, Optional, TypeVar, Generic, Union\nfrom datetime import datetime\nimport json\n\nfrom sqlalchemy import create_engine, MetaData, Table, Column, Integer, String, DateTime, Text, Boolean, select, update, delete, insert\nfrom sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker\nfrom sqlalchemy.orm import sessionmaker, declarative_base\nfrom sqlalchemy.pool import NullPool\nimport asyncpg\nimport motor.motor_asyncio\nfrom redis.asyncio import Redis\n\n# Type variables\nT = TypeVar('T')\n\nclass DatabaseBackend(ABC):\n    \"\"\"Abstract base for database backends\"\"\"\n\n    @abstractmethod\n    async def connect(self):\n        \"\"\"Establish connection\"\"\"\n        pass\n\n    @abstractmethod\n    async def disconnect(self):\n        \"\"\"Close connection\"\"\"\n        pass\n\n    @abstractmethod\n    async def execute_query(self, query: str, params: Dict[str, Any] = None) -> List[Dict[str, Any]]:\n        \"\"\"Execute a query and return results\"\"\"\n        pass\n\n    @abstractmethod\n    async def execute_command(self, command: str, params: Dict[str, Any] = None) -> Any:\n        \"\"\"Execute a command (INSERT, UPDATE, DELETE)\"\"\"\n        pass\n\nclass PostgresBackend(DatabaseBackend):\n    \"\"\"PostgreSQL backend using asyncpg\"\"\"\n\n    def __init__(self, connection_string: str):\n        self.connection_string = connection_string\n        self.pool: Optional[asyncpg.Pool] = None\n\n    async def connect(self):\n        self.pool = await asyncpg.create_pool(\n            self.connection_string,\n            min_size=5,\n            max_size=20,\n            command_timeout=60\n        )\n\n    async def disconnect(self):\n        if self.pool:\n            await self.pool.close()\n\n    async def execute_query(self, query: str, params: Dict[str, Any] = None) -> List[Dict[str, Any]]:\n        async with self.pool.acquire() as conn:\n            rows = await conn.fetch(query, *params.values() if params else [])\n            return [dict(row) for row in rows]\n\n    async def execute_command(self, command: str, params: Dict[str, Any] = None) -> Any:\n        async with self.pool.acquire() as conn:\n            return await conn.execute(command, *params.values() if params else [])\n\nclass SQLAlchemyBackend(DatabaseBackend):\n    \"\"\"SQLAlchemy backend for multiple databases\"\"\"\n\n    def __init__(self, database_url: str, async_mode: bool = True):\n        self.database_url = database_url\n        self.async_mode = async_mode\n        self.engine = None\n        self.session_factory = None\n\n    async def connect(self):\n        if self.async_mode:\n            self.engine = create_async_engine(\n                self.database_url,\n                pool_pre_ping=True,\n                pool_recycle=300,\n                echo=False\n            )\n            self.session_factory = async_sessionmaker(\n                self.engine,\n                class_=AsyncSession,\n                expire_on_commit=False\n            )\n        else:\n            self.engine = create_engine(\n                self.database_url,\n                pool_pre_ping=True,\n                pool_recycle=300,\n                echo=False\n            )\n            self.session_factory = sessionmaker(\n                bind=self.engine,\n                expire_on_commit=False\n            )\n\n    async def disconnect(self):\n        if self.engine:\n            await self.engine.dispose()\n\n    @asynccontextmanager\n    async def get_session(self):\n        \"\"\"Get database session\"\"\"\n        async with self.session_factory() as session:\n            try:\n                yield session\n                if self.async_mode:\n                    await session.commit()\n                else:\n                    session.commit()\n            except Exception:\n                if self.async_mode:\n                    await session.rollback()\n                else:\n                    session.rollback()\n                raise\n            finally:\n                if self.async_mode:\n                    await session.close()\n                else:\n                    session.close()\n\n    async def execute_query(self, query: Any, params: Dict[str, Any] = None) -> List[Dict[str, Any]]:\n        \"\"\"Execute SQLAlchemy query\"\"\"\n        async with self.get_session() as session:\n            if isinstance(query, str):\n                # Raw SQL query\n                result = await session.execute(query, params or {})\n                rows = result.fetchall()\n                return [dict(row._mapping) for row in rows]\n            else:\n                # SQLAlchemy ORM query\n                result = await session.execute(query)\n                rows = result.fetchall()\n                return [dict(row._mapping) for row in rows]\n\n    async def execute_command(self, command: Any, params: Dict[str, Any] = None) -> Any:\n        \"\"\"Execute SQLAlchemy command\"\"\"\n        async with self.get_session() as session:\n            if isinstance(command, str):\n                # Raw SQL command\n                result = await session.execute(command, params or {})\n                await session.commit()\n                return result\n            else:\n                # SQLAlchemy ORM command\n                await session.execute(command, params or {})\n                await session.commit()\n                return None\n\nclass MongoBackend(DatabaseBackend):\n    \"\"\"MongoDB backend using motor\"\"\"\n\n    def __init__(self, connection_string: str, database_name: str):\n        self.connection_string = connection_string\n        self.database_name = database_name\n        self.client = None\n        self.db = None\n\n    async def connect(self):\n        self.client = motor.motor_asyncio.AsyncIOMotorClient(self.connection_string)\n        self.db = self.client[self.database_name]\n\n    async def disconnect(self):\n        if self.client:\n            self.client.close()\n\n    async def execute_query(self, collection: str, query: Dict[str, Any] = None) -> List[Dict[str, Any]]:\n        \"\"\"Execute MongoDB find query\"\"\"\n        cursor = self.db[collection].find(query or {})\n        results = []\n        async for document in cursor:\n            # Convert ObjectId to string\n            if '_id' in document:\n                document['_id'] = str(document['_id'])\n            results.append(document)\n        return results\n\n    async def execute_command(self, operation: str, collection: str, data: Dict[str, Any]) -> Any:\n        \"\"\"Execute MongoDB command\"\"\"\n        if operation == \"insert\":\n            result = await self.db[collection].insert_one(data)\n            return str(result.inserted_id)\n        elif operation == \"update\":\n            filter_ = data.pop(\"_filter\")\n            update_data = {\"$set\": data}\n            result = await self.db[collection].update_one(filter_, update_data)\n            return result.modified_count\n        elif operation == \"delete\":\n            result = await self.db[collection].delete_one(data)\n            return result.deleted_count\n\nclass DatabaseManager(Generic[T]):\n    \"\"\"Generic database manager for MCP servers\"\"\"\n\n    def __init__(self, backend: DatabaseBackend):\n        self.backend = backend\n        self._connected = False\n\n    async def connect(self):\n        \"\"\"Connect to database\"\"\"\n        if not self._connected:\n            await self.backend.connect()\n            self._connected = True\n\n    async def disconnect(self):\n        \"\"\"Disconnect from database\"\"\"\n        if self._connected:\n            await self.backend.disconnect()\n            self._connected = False\n\n    @asynccontextmanager\n    async def transaction(self):\n        \"\"\"Database transaction context manager\"\"\"\n        if hasattr(self.backend, 'get_session'):\n            async with self.backend.get_session() as session:\n                yield session\n        else:\n            # For backends that don't support transactions\n            yield self.backend\n\n    async def find_one(self, table_or_collection: str, query: Dict[str, Any]) -> Optional[Dict[str, Any]]:\n        \"\"\"Find a single record\"\"\"\n        if isinstance(self.backend, MongoBackend):\n            results = await self.backend.execute_query(table_or_collection, query)\n            return results[0] if results else None\n        else:\n            # SQL implementation\n            where_clause = \" AND \".join([f\"{k} = :{k}\" for k in query.keys()])\n            sql = f\"SELECT * FROM {table_or_collection} WHERE {where_clause} LIMIT 1\"\n            results = await self.backend.execute_query(sql, query)\n            return results[0] if results else None\n\n    async def find_many(\n        self,\n        table_or_collection: str,\n        query: Dict[str, Any] = None,\n        limit: int = None,\n        offset: int = None,\n        order_by: str = None\n    ) -> List[Dict[str, Any]]:\n        \"\"\"Find multiple records\"\"\"\n        query = query or {}\n\n        if isinstance(self.backend, MongoBackend):\n            cursor = self.backend.db[table_or_collection].find(query)\n            if limit:\n                cursor = cursor.limit(limit)\n            if offset:\n                cursor = cursor.skip(offset)\n            if order_by:\n                # MongoDB sort format\n                sort_field, sort_dir = order_by.split()\n                cursor = cursor.sort([(sort_field, 1 if sort_dir == 'ASC' else -1)])\n\n            results = []\n            async for document in cursor:\n                if '_id' in document:\n                    document['_id'] = str(document['_id'])\n                results.append(document)\n            return results\n        else:\n            # SQL implementation\n            where_clause = \"\"\n            if query:\n                where_clause = \"WHERE \" + \" AND \".join([f\"{k} = :{k}\" for k in query.keys()])\n\n            sql = f\"SELECT * FROM {table_or_collection} {where_clause}\"\n\n            if order_by:\n                sql += f\" ORDER BY {order_by}\"\n\n            if limit:\n                sql += f\" LIMIT {limit}\"\n\n            if offset:\n                sql += f\" OFFSET {offset}\"\n\n            return await self.backend.execute_query(sql, query)\n\n    async def create(self, table_or_collection: str, data: Dict[str, Any]) -> Any:\n        \"\"\"Create a new record\"\"\"\n        data = data.copy()\n\n        # Add timestamps\n        data['created_at'] = datetime.utcnow()\n        data['updated_at'] = datetime.utcnow()\n\n        if isinstance(self.backend, MongoBackend):\n            return await self.backend.execute_command(\"insert\", table_or_collection, data)\n        else:\n            # SQL implementation\n            columns = list(data.keys())\n            placeholders = [f\":{col}\" for col in columns]\n            sql = f\"INSERT INTO {table_or_collection} ({', '.join(columns)}) VALUES ({', '.join(placeholders)})\"\n            return await self.backend.execute_command(sql, data)\n\n    async def update(self, table_or_collection: str, query: Dict[str, Any], data: Dict[str, Any]) -> int:\n        \"\"\"Update records\"\"\"\n        data = data.copy()\n        data['updated_at'] = datetime.utcnow()\n\n        if isinstance(self.backend, MongoBackend):\n            data['_filter'] = query\n            return await self.backend.execute_command(\"update\", table_or_collection, data)\n        else:\n            # SQL implementation\n            where_clause = \" AND \".join([f\"{k} = :{k}\" for k in query.keys()])\n            set_clause = \", \".join([f\"{k} = :update_{k}\" for k in data.keys()])\n\n            # Prefix update params to avoid conflicts\n            update_params = {f\"update_{k}\": v for k, v in data.items()}\n            params = {**query, **update_params}\n\n            sql = f\"UPDATE {table_or_collection} SET {set_clause} WHERE {where_clause}\"\n            result = await self.backend.execute_command(sql, params)\n            return result.rowcount if hasattr(result, 'rowcount') else 0\n\n    async def delete(self, table_or_collection: str, query: Dict[str, Any]) -> int:\n        \"\"\"Delete records\"\"\"\n        if isinstance(self.backend, MongoBackend):\n            return await self.backend.execute_command(\"delete\", table_or_collection, query)\n        else:\n            # SQL implementation\n            where_clause = \" AND \".join([f\"{k} = :{k}\" for k in query.keys()])\n            sql = f\"DELETE FROM {table_or_collection} WHERE {where_clause}\"\n            result = await self.backend.execute_command(sql, query)\n            return result.rowcount if hasattr(result, 'rowcount') else 0\n\n    async def count(self, table_or_collection: str, query: Dict[str, Any] = None) -> int:\n        \"\"\"Count records\"\"\"\n        query = query or {}\n\n        if isinstance(self.backend, MongoBackend):\n            return await self.backend.db[table_or_collection].count_documents(query)\n        else:\n            # SQL implementation\n            where_clause = \"\"\n            if query:\n                where_clause = \"WHERE \" + \" AND \".join([f\"{k} = :{k}\" for k in query.keys()])\n\n            sql = f\"SELECT COUNT(*) as count FROM {table_or_collection} {where_clause}\"\n            results = await self.backend.execute_query(sql, query)\n            return results[0]['count'] if results else 0\n\n# Factory function for creating database managers\ndef create_database_manager(database_url: str, backend_type: str = \"auto\") -> DatabaseManager:\n    \"\"\"Create database manager based on URL or backend type\"\"\"\n\n    if backend_type == \"auto\":\n        if database_url.startswith(\"postgresql+asyncpg:\u002F\u002F\"):\n            backend = SQLAlchemyBackend(database_url, async_mode=True)\n        elif database_url.startswith(\"mongodb:\u002F\u002F\"):\n            import re\n            match = re.match(r'mongodb:\u002F\u002F[^\u002F]+\u002F([^?]*)', database_url)\n            db_name = match.group(1) if match else \"default\"\n            backend = MongoBackend(database_url, db_name)\n        elif database_url.startswith(\"postgresql:\u002F\u002F\"):\n            backend = PostgresBackend(database_url)\n        else:\n            backend = SQLAlchemyBackend(database_url, async_mode=True)\n    else:\n        if backend_type == \"postgres\":\n            backend = PostgresBackend(database_url)\n        elif backend_type == \"mongodb\":\n            db_name = database_url.split(\"\u002F\")[-1].split(\"?\")[0]\n            backend = MongoBackend(database_url, db_name)\n        elif backend_type == \"sqlalchemy\":\n            backend = SQLAlchemyBackend(database_url)\n        else:\n            raise ValueError(f\"Unknown backend type: {backend_type}\")\n\n    return DatabaseManager(backend)\n```\n\n## 3. Tool Implementation Patterns\n\n```python\n# mcp_server\u002Ftools.py\n\"\"\"\nGeneric MCP Tool Implementation Patterns\n\"\"\"\n\nfrom typing import Any, Dict, List, Optional, Union, Callable\nfrom datetime import datetime, timedelta\nimport json\nimport uuid\nfrom dataclasses import dataclass, field\n\nfrom .core import BaseMCPServer, tool, RequestContext\nfrom .database import DatabaseManager\n\nclass BaseTool:\n    \"\"\"Base class for MCP tools\"\"\"\n\n    def __init__(self, db_manager: DatabaseManager, cache=None):\n        self.db_manager = db_manager\n        self.cache = cache\n\n    async def execute(self, args: Dict[str, Any], context: RequestContext = None) -> Dict[str, Any]:\n        \"\"\"Execute the tool logic\"\"\"\n        raise NotImplementedError\n\n    def _validate_permissions(self, context: RequestContext, required_permission: str = None) -> bool:\n        \"\"\"Validate user permissions\"\"\"\n        # Implement permission checking logic\n        return True\n\nclass CRUDBaseTool(BaseTool):\n    \"\"\"Base CRUD tool for any entity\"\"\"\n\n    def __init__(self, table_name: str, db_manager: DatabaseManager, schema: Dict[str, Any]):\n        super().__init__(db_manager)\n        self.table_name = table_name\n        self.schema = schema\n        self.entity_name = table_name.rstrip('s')  # Remove plural 's'\n\n    async def create(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Create entity\"\"\"\n        try:\n            # Validate against schema\n            validated_data = self._validate_data(args, for_create=True)\n\n            # Add user context\n            if context:\n                validated_data['user_id'] = context.user_id\n                if context.session_id:\n                    validated_data['session_id'] = context.session_id\n\n            # Insert into database\n            result = await self.db_manager.create(self.table_name, validated_data)\n\n            return {\n                \"status\": \"created\",\n                \"id\": result,\n                \"entity\": self.entity_name,\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"create\"\n            }\n\n    async def get(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Get entity by ID\"\"\"\n        try:\n            entity_id = args.get(\"id\")\n            if not entity_id:\n                raise ValueError(\"Missing required field: id\")\n\n            # Add user filter for security\n            query = {\"id\": entity_id}\n            if context and not self._validate_permissions(context, \"read_all\"):\n                query[\"user_id\"] = context.user_id\n\n            result = await self.db_manager.find_one(self.table_name, query)\n\n            if not result:\n                return {\n                    \"status\": \"not_found\",\n                    \"entity\": self.entity_name,\n                    \"id\": entity_id\n                }\n\n            return {\n                \"status\": \"success\",\n                \"entity\": self.entity_name,\n                \"data\": self._serialize_data(result)\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"get\"\n            }\n\n    async def list(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"List entities with filtering\"\"\"\n        try:\n            # Build query from args\n            query = {}\n            filters = args.get(\"filters\", {})\n            limit = args.get(\"limit\", 20)\n            offset = args.get(\"offset\", 0)\n            order_by = args.get(\"order_by\", \"created_at DESC\")\n\n            # Add user filter for security\n            if context and not self._validate_permissions(context, \"read_all\"):\n                query[\"user_id\"] = context.user_id\n\n            # Apply additional filters\n            query.update(filters)\n\n            # Fetch from database\n            results = await self.db_manager.find_many(\n                self.table_name,\n                query=query,\n                limit=limit,\n                offset=offset,\n                order_by=order_by\n            )\n\n            # Get total count\n            total = await self.db_manager.count(self.table_name, query)\n\n            return {\n                \"status\": \"success\",\n                \"entity\": self.entity_name,\n                \"data\": [self._serialize_data(r) for r in results],\n                \"pagination\": {\n                    \"total\": total,\n                    \"limit\": limit,\n                    \"offset\": offset,\n                    \"has_more\": offset + limit \u003C total\n                }\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"list\"\n            }\n\n    async def update(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Update entity\"\"\"\n        try:\n            entity_id = args.pop(\"id\", None)\n            if not entity_id:\n                raise ValueError(\"Missing required field: id\")\n\n            # Validate update data\n            update_data = self._validate_data(args, for_create=False)\n\n            # Build query filter\n            query = {\"id\": entity_id}\n            if context and not self._validate_permissions(context, \"update_all\"):\n                query[\"user_id\"] = context.user_id\n\n            # Update in database\n            affected = await self.db_manager.update(self.table_name, query, update_data)\n\n            if affected == 0:\n                return {\n                    \"status\": \"not_found\",\n                    \"entity\": self.entity_name,\n                    \"id\": entity_id\n                }\n\n            return {\n                \"status\": \"updated\",\n                \"entity\": self.entity_name,\n                \"id\": entity_id,\n                \"affected_rows\": affected,\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"update\"\n            }\n\n    async def delete(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Delete entity\"\"\"\n        try:\n            entity_id = args.get(\"id\")\n            if not entity_id:\n                raise ValueError(\"Missing required field: id\")\n\n            # Build query filter\n            query = {\"id\": entity_id}\n            if context and not self._validate_permissions(context, \"delete_all\"):\n                query[\"user_id\"] = context.user_id\n\n            # Delete from database\n            affected = await self.db_manager.delete(self.table_name, query)\n\n            if affected == 0:\n                return {\n                    \"status\": \"not_found\",\n                    \"entity\": self.entity_name,\n                    \"id\": entity_id\n                }\n\n            return {\n                \"status\": \"deleted\",\n                \"entity\": self.entity_name,\n                \"id\": entity_id,\n                \"affected_rows\": affected,\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"delete\"\n            }\n\n    def _validate_data(self, data: Dict[str, Any], for_create: bool = False) -> Dict[str, Any]:\n        \"\"\"Validate data against schema\"\"\"\n        validated = {}\n        schema_fields = self.schema.get(\"properties\", {})\n        required_fields = self.schema.get(\"required\", [])\n\n        # Check required fields for create\n        if for_create:\n            for field in required_fields:\n                if field not in data:\n                    raise ValueError(f\"Missing required field: {field}\")\n\n        # Validate each field\n        for field, value in data.items():\n            if field not in schema_fields:\n                continue  # Skip unknown fields or raise error based on strictness\n\n            field_schema = schema_fields[field]\n            field_type = field_schema.get(\"type\")\n\n            # Type validation\n            if field_type == \"string\":\n                if not isinstance(value, str):\n                    raise ValueError(f\"Field {field} must be a string\")\n                # Check min\u002Fmax length\n                if \"minLength\" in field_schema and len(value) \u003C field_schema[\"minLength\"]:\n                    raise ValueError(f\"Field {field} is too short\")\n                if \"maxLength\" in field_schema and len(value) > field_schema[\"maxLength\"]:\n                    raise ValueError(f\"Field {field} is too long\")\n            elif field_type == \"integer\":\n                if not isinstance(value, int):\n                    raise ValueError(f\"Field {field} must be an integer\")\n                # Check min\u002Fmax value\n                if \"minimum\" in field_schema and value \u003C field_schema[\"minimum\"]:\n                    raise ValueError(f\"Field {field} is too small\")\n                if \"maximum\" in field_schema and value > field_schema[\"maximum\"]:\n                    raise ValueError(f\"Field {field} is too large\")\n            elif field_type == \"array\":\n                if not isinstance(value, list):\n                    raise ValueError(f\"Field {field} must be an array\")\n\n            # Check enum values\n            if \"enum\" in field_schema and value not in field_schema[\"enum\"]:\n                raise ValueError(f\"Field {field} must be one of {field_schema['enum']}\")\n\n            validated[field] = value\n\n        return validated\n\n    def _serialize_data(self, data: Dict[str, Any]) -> Dict[str, Any]:\n        \"\"\"Serialize data for output\"\"\"\n        serialized = data.copy()\n\n        # Handle datetime serialization\n        for key, value in serialized.items():\n            if isinstance(value, datetime):\n                serialized[key] = value.isoformat()\n            elif isinstance(value, dict):\n                # Convert complex types to JSON string\n                try:\n                    json.dumps(value)\n                except TypeError:\n                    serialized[key] = str(value)\n\n        return serialized\n\nclass BulkOperationTool(BaseTool):\n    \"\"\"Tool for bulk operations on entities\"\"\"\n\n    def __init__(self, table_name: str, db_manager: DatabaseManager, schema: Dict[str, Any]):\n        super().__init__(db_manager)\n        self.table_name = table_name\n        self.schema = schema\n        self.entity_name = table_name.rstrip('s')\n\n    async def bulk_create(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Bulk create entities\"\"\"\n        try:\n            items = args.get(\"items\", [])\n            if not items:\n                raise ValueError(\"No items provided for bulk create\")\n\n            # Validate all items\n            validated_items = []\n            for item in items:\n                validated = self._validate_item(item)\n                if context:\n                    validated[\"user_id\"] = context.user_id\n                validated_items.append(validated)\n\n            # Insert all items\n            results = []\n            for item in validated_items:\n                result = await self.db_manager.create(self.table_name, item)\n                results.append(result)\n\n            return {\n                \"status\": \"created\",\n                \"entity\": self.entity_name,\n                \"count\": len(results),\n                \"ids\": results,\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"bulk_create\"\n            }\n\n    async def bulk_update(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Bulk update entities\"\"\"\n        try:\n            updates = args.get(\"updates\", [])\n            if not updates:\n                raise ValueError(\"No updates provided\")\n\n            total_affected = 0\n            for update in updates:\n                entity_id = update.get(\"id\")\n                update_data = update.get(\"data\", {})\n\n                if not entity_id:\n                    continue\n\n                # Build query\n                query = {\"id\": entity_id}\n                if context:\n                    query[\"user_id\"] = context.user_id\n\n                # Update\n                affected = await self.db_manager.update(self.table_name, query, update_data)\n                total_affected += affected\n\n            return {\n                \"status\": \"updated\",\n                \"entity\": self.entity_name,\n                \"affected_rows\": total_affected,\n                \"updates_processed\": len(updates),\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"bulk_update\"\n            }\n\n    async def bulk_delete(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Bulk delete entities\"\"\"\n        try:\n            ids = args.get(\"ids\", [])\n            if not ids:\n                raise ValueError(\"No IDs provided for bulk delete\")\n\n            total_affected = 0\n            for entity_id in ids:\n                # Build query\n                query = {\"id\": entity_id}\n                if context:\n                    query[\"user_id\"] = context.user_id\n\n                # Delete\n                affected = await self.db_manager.delete(self.table_name, query)\n                total_affected += affected\n\n            return {\n                \"status\": \"deleted\",\n                \"entity\": self.entity_name,\n                \"affected_rows\": total_affected,\n                \"ids_processed\": len(ids),\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"bulk_delete\"\n            }\n\n    def _validate_item(self, item: Dict[str, Any]) -> Dict[str, Any]:\n        \"\"\"Validate a single item\"\"\"\n        # Use CRUD base tool validation\n        crud_tool = CRUDBaseTool(self.table_name, self.db_manager, self.schema)\n        return crud_tool._validate_data(item, for_create=True)\n```\n\n## 4. Example: Building a Generic Task Management MCP Server\n\n```python\n# examples\u002Ftask_mcp_server.py\n\"\"\"\nExample: Task Management MCP Server using generic patterns\n\"\"\"\n\nimport os\nfrom typing import Dict, Any\n\nfrom mcp_server.core import BaseMCPServer, ServerConfig, tool\nfrom mcp_server.database import create_database_manager\nfrom mcp_server.tools import CRUDBaseTool, BulkOperationTool\n\n# Server configuration\nconfig = ServerConfig(\n    name=\"task-manager\",\n    version=\"1.0.0\",\n    description=\"Generic task management MCP server\",\n    redis_url=os.getenv(\"REDIS_URL\", \"redis:\u002F\u002Flocalhost:6379\"),\n    database_url=os.getenv(\"DATABASE_URL\", \"postgresql+asyncpg:\u002F\u002Fuser:pass@localhost\u002Ftasks\")\n)\n\n# Task entity schema\nTASK_SCHEMA = {\n    \"type\": \"object\",\n    \"properties\": {\n        \"title\": {\n            \"type\": \"string\",\n            \"minLength\": 1,\n            \"maxLength\": 200,\n            \"description\": \"Task title\"\n        },\n        \"description\": {\n            \"type\": \"string\",\n            \"maxLength\": 1000,\n            \"description\": \"Task description\"\n        },\n        \"priority\": {\n            \"type\": \"string\",\n            \"enum\": [\"low\", \"medium\", \"high\"],\n            \"default\": \"medium\",\n            \"description\": \"Task priority\"\n        },\n        \"status\": {\n            \"type\": \"string\",\n            \"enum\": [\"todo\", \"in_progress\", \"completed\"],\n            \"default\": \"todo\",\n            \"description\": \"Task status\"\n        },\n        \"due_date\": {\n            \"type\": \"string\",\n            \"format\": \"date-time\",\n            \"description\": \"Optional due date\"\n        },\n        \"tags\": {\n            \"type\": \"array\",\n            \"items\": {\"type\": \"string\"},\n            \"description\": \"Task tags\"\n        }\n    },\n    \"required\": [\"title\"]\n}\n\nclass TaskMCPServer(BaseMCPServer):\n    \"\"\"Task Management MCP Server\"\"\"\n\n    def __init__(self, config: ServerConfig):\n        super().__init__(config)\n\n        # Initialize database\n        self.db_manager = create_database_manager(config.database_url)\n\n        # Initialize tools\n        self.task_tool = CRUDBaseTool(\"tasks\", self.db_manager, TASK_SCHEMA)\n        self.bulk_tool = BulkOperationTool(\"tasks\", self.db_manager, TASK_SCHEMA)\n\n        # Register tools\n        self._register_task_tools()\n\n    def _register_task_tools(self):\n        \"\"\"Register all task-related tools\"\"\"\n\n        # Create task\n        self.register_tool(\n            \"create_task\",\n            self.task_tool.create,\n            {\n                \"description\": \"Create a new task\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"title\": {\"type\": \"string\", \"description\": \"Task title\"},\n                        \"description\": {\"type\": \"string\", \"description\": \"Optional description\"},\n                        \"priority\": {\"type\": \"string\", \"enum\": [\"low\", \"medium\", \"high\"]},\n                        \"due_date\": {\"type\": \"string\", \"format\": \"date-time\"},\n                        \"tags\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}}\n                    },\n                    \"required\": [\"title\"]\n                }\n            }\n        )\n\n        # Get task\n        self.register_tool(\n            \"get_task\",\n            self.task_tool.get,\n            {\n                \"description\": \"Get a task by ID\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"id\": {\"type\": \"integer\", \"description\": \"Task ID\"}\n                    },\n                    \"required\": [\"id\"]\n                }\n            }\n        )\n\n        # List tasks\n        self.register_tool(\n            \"list_tasks\",\n            self.task_tool.list,\n            {\n                \"description\": \"List tasks with optional filtering\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"filters\": {\"type\": \"object\", \"description\": \"Filter criteria\"},\n                        \"limit\": {\"type\": \"integer\", \"minimum\": 1, \"maximum\": 100, \"default\": 20},\n                        \"offset\": {\"type\": \"integer\", \"minimum\": 0, \"default\": 0},\n                        \"order_by\": {\"type\": \"string\", \"description\": \"Order by field (e.g., 'created_at DESC')\"}\n                    }\n                }\n            }\n        )\n\n        # Update task\n        self.register_tool(\n            \"update_task\",\n            self.task_tool.update,\n            {\n                \"description\": \"Update a task\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"id\": {\"type\": \"integer\", \"description\": \"Task ID\"},\n                        \"title\": {\"type\": \"string\", \"description\": \"New title\"},\n                        \"description\": {\"type\": \"string\", \"description\": \"New description\"},\n                        \"priority\": {\"type\": \"string\", \"enum\": [\"low\", \"medium\", \"high\"]},\n                        \"status\": {\"type\": \"string\", \"enum\": [\"todo\", \"in_progress\", \"completed\"]},\n                        \"due_date\": {\"type\": \"string\", \"format\": \"date-time\"},\n                        \"tags\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}}\n                    },\n                    \"required\": [\"id\"]\n                }\n            }\n        )\n\n        # Delete task\n        self.register_tool(\n            \"delete_task\",\n            self.task_tool.delete,\n            {\n                \"description\": \"Delete a task\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"id\": {\"type\": \"integer\", \"description\": \"Task ID\"}\n                    },\n                    \"required\": [\"id\"]\n                }\n            }\n        )\n\n        # Bulk create\n        self.register_tool(\n            \"bulk_create_tasks\",\n            self.bulk_tool.bulk_create,\n            {\n                \"description\": \"Create multiple tasks at once\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"items\": {\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"object\",\n                                \"properties\": {\n                                    \"title\": {\"type\": \"string\"},\n                                    \"description\": {\"type\": \"string\"},\n                                    \"priority\": {\"type\": \"string\", \"enum\": [\"low\", \"medium\", \"high\"]},\n                                    \"tags\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}}\n                                },\n                                \"required\": [\"title\"]\n                            }\n                        }\n                    },\n                    \"required\": [\"items\"]\n                }\n            }\n        )\n\n        # Search tasks\n        self.register_tool(\n            \"search_tasks\",\n            self._search_tasks,\n            {\n                \"description\": \"Search tasks by text query\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"query\": {\"type\": \"string\", \"description\": \"Search query\"},\n                        \"limit\": {\"type\": \"integer\", \"minimum\": 1, \"maximum\": 50, \"default\": 20}\n                    },\n                    \"required\": [\"query\"]\n                }\n            }\n        )\n\n    async def _search_tasks(self, args: Dict[str, Any], context) -> Dict[str, Any]:\n        \"\"\"Search tasks by text\"\"\"\n        try:\n            query = args.get(\"query\", \"\")\n            limit = args.get(\"limit\", 20)\n\n            # Build search query\n            if isinstance(self.db_manager.backend, MongoBackend):\n                # MongoDB text search\n                search_query = {\n                    \"$text\": {\"$search\": query}\n                }\n                if context and not self.task_tool._validate_permissions(context, \"read_all\"):\n                    search_query[\"user_id\"] = context.user_id\n\n                results = await self.db_manager.find_many(\"tasks\", search_query, limit=limit)\n            else:\n                # PostgreSQL full-text search\n                sql = \"\"\"\n                SELECT * FROM tasks\n                WHERE to_tsvector('english', title || ' ' || COALESCE(description, '')) @@ plainto_tsquery('english', :query)\n                \"\"\"\n                params = {\"query\": query}\n\n                if context and not self.task_tool._validate_permissions(context, \"read_all\"):\n                    sql += \" AND user_id = :user_id\"\n                    params[\"user_id\"] = context.user_id\n\n                sql += f\" LIMIT {limit}\"\n\n                results = await self.db_manager.execute_query(sql, params)\n\n            return {\n                \"status\": \"success\",\n                \"entity\": \"task\",\n                \"data\": [self.task_tool._serialize_data(r) for r in results],\n                \"query\": query,\n                \"count\": len(results)\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"operation\": \"search_tasks\"\n            }\n\n# Main execution\nasync def main():\n    \"\"\"Start the Task MCP Server\"\"\"\n    server = TaskMCPServer(config)\n    await server.run()\n\nif __name__ == \"__main__\":\n    import asyncio\n    asyncio.run(main())\n```\n\n## 5. Testing Patterns\n\n```python\n# tests\u002Ftest_mcp_server.py\n\"\"\"\nGeneric MCP Server Testing Patterns\n\"\"\"\n\nimport pytest\nimport asyncio\nfrom typing import Dict, Any, List\nfrom unittest.mock import Mock, AsyncMock\n\nfrom mcp_server.core import BaseMCPServer, ServerConfig, RequestContext\nfrom mcp_server.database import DatabaseManager, create_database_manager\nfrom mcp_server.tools import CRUDBaseTool\n\nclass MockDatabaseManager:\n    \"\"\"Mock database manager for testing\"\"\"\n\n    def __init__(self):\n        self.data = {}\n        self.next_id = 1\n\n    async def create(self, table: str, data: Dict[str, Any]) -> int:\n        \"\"\"Mock create\"\"\"\n        entity_id = self.next_id\n        data['id'] = entity_id\n        self.data[f\"{table}:{entity_id}\"] = data\n        self.next_id += 1\n        return entity_id\n\n    async def find_one(self, table: str, query: Dict[str, Any]) -> Dict[str, Any]:\n        \"\"\"Mock find one\"\"\"\n        for key, value in self.data.items():\n            table_name, entity_id = key.split(\":\")\n            if table_name == table:\n                match = True\n                for k, v in query.items():\n                    if value.get(k) != v:\n                        match = False\n                        break\n                if match:\n                    return value\n        return None\n\n    async def find_many(self, table: str, query: Dict[str, Any], limit: int = None) -> List[Dict[str, Any]]:\n        \"\"\"Mock find many\"\"\"\n        results = []\n        for key, value in self.data.items():\n            table_name, entity_id = key.split(\":\")\n            if table_name == table:\n                match = True\n                for k, v in query.items():\n                    if value.get(k) != v:\n                        match = False\n                        break\n                if match:\n                    results.append(value)\n                    if limit and len(results) >= limit:\n                        break\n        return results\n\n    async def update(self, table: str, query: Dict[str, Any], data: Dict[str, Any]) -> int:\n        \"\"\"Mock update\"\"\"\n        count = 0\n        for key, value in self.data.items():\n            table_name, entity_id = key.split(\":\")\n            if table_name == table:\n                match = True\n                for k, v in query.items():\n                    if value.get(k) != v:\n                        match = False\n                        break\n                if match:\n                    value.update(data)\n                    count += 1\n        return count\n\n    async def delete(self, table: str, query: Dict[str, Any]) -> int:\n        \"\"\"Mock delete\"\"\"\n        to_delete = []\n        for key, value in self.data.items():\n            table_name, entity_id = key.split(\":\")\n            if table_name == table:\n                match = True\n                for k, v in query.items():\n                    if value.get(k) != v:\n                        match = False\n                        break\n                if match:\n                    to_delete.append(key)\n\n        for key in to_delete:\n            del self.data[key]\n\n        return len(to_delete)\n\n@pytest.fixture\nasync def mock_db():\n    \"\"\"Mock database manager fixture\"\"\"\n    return MockDatabaseManager()\n\n@pytest.fixture\ndef test_schema():\n    \"\"\"Test entity schema\"\"\"\n    return {\n        \"type\": \"object\",\n        \"properties\": {\n            \"name\": {\"type\": \"string\", \"minLength\": 1},\n            \"value\": {\"type\": \"integer\", \"minimum\": 0},\n            \"status\": {\"type\": \"string\", \"enum\": [\"active\", \"inactive\"]},\n            \"tags\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}}\n        },\n        \"required\": [\"name\"]\n    }\n\n@pytest.fixture\ndef crud_tool(mock_db, test_schema):\n    \"\"\"CRUD tool fixture\"\"\"\n    return CRUDBaseTool(\"test_entities\", mock_db, test_schema)\n\n@pytest.fixture\ndef user_context():\n    \"\"\"User context fixture\"\"\"\n    return RequestContext(user_id=\"test_user\", session_id=\"test_session\")\n\nclass TestCRUDTool:\n    \"\"\"Test CRUD tool operations\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_create_entity(self, crud_tool, user_context):\n        \"\"\"Test entity creation\"\"\"\n        args = {\n            \"name\": \"Test Entity\",\n            \"value\": 100,\n            \"status\": \"active\",\n            \"tags\": [\"test\", \"example\"]\n        }\n\n        result = await crud_tool.create(args, user_context)\n\n        assert result[\"status\"] == \"created\"\n        assert \"id\" in result\n        assert result[\"entity\"] == \"test_entity\"\n        assert \"timestamp\" in result\n\n    @pytest.mark.asyncio\n    async def test_create_missing_required(self, crud_tool, user_context):\n        \"\"\"Test creation with missing required field\"\"\"\n        args = {\"value\": 100}  # Missing 'name'\n\n        result = await crud_tool.create(args, user_context)\n\n        assert result[\"status\"] == \"error\"\n        assert \"Missing required field\" in result[\"error\"]\n\n    @pytest.mark.asyncio\n    async def test_get_entity(self, crud_tool, user_context):\n        \"\"\"Test getting an entity\"\"\"\n        # First create an entity\n        create_args = {\"name\": \"Test Get\"}\n        create_result = await crud_tool.create(create_args, user_context)\n        entity_id = create_result[\"id\"]\n\n        # Get the entity\n        get_args = {\"id\": entity_id}\n        result = await crud_tool.get(get_args, user_context)\n\n        assert result[\"status\"] == \"success\"\n        assert result[\"data\"][\"name\"] == \"Test Get\"\n        assert result[\"data\"][\"id\"] == entity_id\n\n    @pytest.mark.asyncio\n    async def test_get_not_found(self, crud_tool, user_context):\n        \"\"\"Test getting non-existent entity\"\"\"\n        args = {\"id\": 99999}\n        result = await crud_tool.get(args, user_context)\n\n        assert result[\"status\"] == \"not_found\"\n\n    @pytest.mark.asyncio\n    async def test_list_entities(self, crud_tool, user_context):\n        \"\"\"Test listing entities\"\"\"\n        # Create a few entities\n        for i in range(3):\n            args = {\"name\": f\"Entity {i}\"}\n            await crud_tool.create(args, user_context)\n\n        # List entities\n        result = await crud_tool.list({}, user_context)\n\n        assert result[\"status\"] == \"success\"\n        assert len(result[\"data\"]) == 3\n        assert \"pagination\" in result\n        assert result[\"pagination\"][\"total\"] == 3\n\n    @pytest.mark.asyncio\n    async def test_list_with_filters(self, crud_tool, user_context):\n        \"\"\"Test listing with filters\"\"\"\n        # Create entities with different statuses\n        await crud_tool.create({\"name\": \"Active 1\", \"status\": \"active\"}, user_context)\n        await crud_tool.create({\"name\": \"Inactive 1\", \"status\": \"inactive\"}, user_context)\n        await crud_tool.create({\"name\": \"Active 2\", \"status\": \"active\"}, user_context)\n\n        # Filter by status\n        result = await crud_tool.list(\n            {\"filters\": {\"status\": \"active\"}},\n            user_context\n        )\n\n        assert result[\"status\"] == \"success\"\n        assert all(entity[\"status\"] == \"active\" for entity in result[\"data\"])\n\n    @pytest.mark.asyncio\n    async def test_update_entity(self, crud_tool, user_context):\n        \"\"\"Test updating an entity\"\"\"\n        # Create entity\n        create_result = await crud_tool.create({\"name\": \"Original\"}, user_context)\n        entity_id = create_result[\"id\"]\n\n        # Update entity\n        update_args = {\n            \"id\": entity_id,\n            \"name\": \"Updated\",\n            \"value\": 200\n        }\n        result = await crud_tool.update(update_args, user_context)\n\n        assert result[\"status\"] == \"updated\"\n        assert result[\"affected_rows\"] == 1\n\n    @pytest.mark.asyncio\n    async def test_delete_entity(self, crud_tool, user_context):\n        \"\"\"Test deleting an entity\"\"\"\n        # Create entity\n        create_result = await crud_tool.create({\"name\": \"To Delete\"}, user_context)\n        entity_id = create_result[\"id\"]\n\n        # Delete entity\n        delete_args = {\"id\": entity_id}\n        result = await crud_tool.delete(delete_args, user_context)\n\n        assert result[\"status\"] == \"deleted\"\n        assert result[\"affected_rows\"] == 1\n\n        # Verify deletion\n        get_result = await crud_tool.get({\"id\": entity_id}, user_context)\n        assert get_result[\"status\"] == \"not_found\"\n\nclass TestMCPServer:\n    \"\"\"Test MCP Server functionality\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_server_initialization(self):\n        \"\"\"Test server initialization\"\"\"\n        config = ServerConfig(\n            name=\"test-server\",\n            description=\"Test MCP Server\"\n        )\n\n        server = BaseMCPServer(config)\n\n        assert server.config.name == \"test-server\"\n        assert server.server.name == \"test-server\"\n        assert len(server.tools) == 0\n\n    @pytest.mark.asyncio\n    async def test_tool_registration(self):\n        \"\"\"Test tool registration\"\"\"\n        config = ServerConfig(name=\"test-server\", description=\"Test\")\n        server = BaseMCPServer(config)\n\n        # Register a test tool\n        async def test_tool(args: Dict[str, Any]) -> Dict[str, Any]:\n            return {\"status\": \"success\", \"data\": args}\n\n        schema = {\n            \"description\": \"Test tool\",\n            \"inputSchema\": {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\"type\": \"string\"}\n                }\n            }\n        }\n\n        server.register_tool(\"test_tool\", test_tool, schema)\n\n        assert \"test_tool\" in server.tools\n        assert server.tools[\"test_tool\"][\"schema\"] == schema\n\n    @pytest.mark.asyncio\n    async def test_rate_limiting(self):\n        \"\"\"Test rate limiting functionality\"\"\"\n        # This would require mocking Redis or using a test instance\n        # Implementation would depend on your rate limiting strategy\n        pass\n\n    @pytest.mark.asyncio\n    async def test_caching(self):\n        \"\"\"Test caching functionality\"\"\"\n        # This would require mocking Redis or using a test instance\n        # Implementation would depend on your caching strategy\n        pass\n\n# Integration test example\nclass TestMCPServerIntegration:\n    \"\"\"Integration tests for MCP Server\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_full_crud_workflow(self):\n        \"\"\"Test full CRUD workflow through MCP interface\"\"\"\n        # Create mock server\n        config = ServerConfig(\n            name=\"test-integration\",\n            description=\"Integration test server\"\n        )\n\n        # Use in-memory database\n        mock_db = MockDatabaseManager()\n\n        # Create CRUD tool\n        test_schema = {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\"type\": \"string\"},\n                \"value\": {\"type\": \"integer\"}\n            },\n            \"required\": [\"name\"]\n        }\n\n        crud_tool = CRUDBaseTool(\"items\", mock_db, test_schema)\n\n        # Register tools\n        server = BaseMCPServer(config)\n        server.register_tool(\n            \"create_item\",\n            crud_tool.create,\n            {\n                \"description\": \"Create item\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"name\": {\"type\": \"string\"},\n                        \"value\": {\"type\": \"integer\"}\n                    },\n                    \"required\": [\"name\"]\n                }\n            }\n        )\n\n        # Test create\n        result = await server.call_tool(\n            \"create_item\",\n            {\"name\": \"Test Item\", \"value\": 123}\n        )\n\n        response = json.loads(result[0].text)\n        assert response[\"status\"] == \"created\"\n\n        # Test get (would need get_item tool)\n        # Test list\n        # Test update\n        # Test delete\n```\n\nThis generic MCP server skill provides a reusable foundation for building any MCP server, not just for todos. It includes:\n\n1. **Core Server Architecture** - Base class with rate limiting, caching, and error handling\n2. **Database Integration** - Support for PostgreSQL, MongoDB, and SQLAlchemy with async operations\n3. **Tool Patterns** - Generic CRUD and bulk operation patterns that work with any entity\n4. **Example Implementation** - Shows how to build a task management server using the generic patterns\n5. **Testing Framework** - Comprehensive testing patterns and mocks\n\n`★ Insight ─────────────────────────────────────`\nThe key architectural pattern here is the separation of concerns between:\n- The MCP protocol handling (BaseMCPServer)\n- The data access layer (DatabaseManager with multiple backends)\n- The business logic layer (CRUDBaseTool and BulkOperationTool)\n- The specific implementation (TaskMCPServer combining the components)\n\nThis makes the system highly reusable and maintainable. Any developer can quickly build a new MCP server by defining their entity schema and combining the generic tools.\n`─────────────────────────────────────────────────`","# Generic MCP Server Development\n\nThis skill provides comprehensive patterns and reusable code for building MCP (Model Context Protocol) servers that can expose any domain operations as tools for AI agents. Follows 2025 best practices for performance, security, and maintainability.\n\n## When to Use This Skill\n\nUse this skill when you need to:\n- Build an MCP server for any domain (not just todos)\n- Expose database operations as MCP tools\n- Create AI-agent accessible APIs\n- Implement async MCP tool handlers\n- Add proper error handling and validation\n- Support rate limiting and caching\n- Build enterprise-grade MCP servers\n- Integrate with multiple storage backends\n\n## 1. Generic MCP Server Architecture\n\n```python\n# mcp_server\u002Fcore.py\n#!\u002Fusr\u002Fbin\u002Fenv python3\n\"\"\"\nGeneric MCP Server Base Architecture\nProvides reusable patterns for any MCP server implementation\n\"\"\"\n\nimport asyncio\nimport json\nimport logging\nfrom abc import ABC, abstractmethod\nfrom datetime import datetime, timedelta\nfrom typing import Any, Dict, List, Optional, Sequence, Union, Callable\nfrom contextlib import asynccontextmanager\nfrom dataclasses import dataclass, field\nfrom enum import Enum\n\nimport redis.asyncio as redis\nfrom mcp.server import Server, NotificationOptions, stdio\nfrom mcp.server.models import InitializationOptions\nfrom mcp.server.stdio import stdio_server\nfrom mcp.types import (\n    Resource, Tool, TextContent, ImageContent, EmbeddedResource,\n    LoggingLevel, CallToolRequest, EmptyResult,\n    ListResourcesRequest, ListToolsRequest, ReadResourceRequest,\n    GetPromptRequest, ListPromptsRequest\n)\nfrom pydantic import BaseModel, Field, validator\nimport aiofiles\nimport yaml\nfrom pathlib import Path\n\n# Configure logging\nlogging.basicConfig(\n    level=logging.INFO,\n    format=\"%(asctime)s - %(name)s - %(levelname)s - %(message)s\"\n)\nlogger = logging.getLogger(\"mcp_server\")\n\nclass ServerConfig(BaseModel):\n    \"\"\"MCP Server configuration\"\"\"\n    name: str\n    version: str = \"1.0.0\"\n    description: str\n    debug: bool = False\n    redis_url: Optional[str] = None\n    rate_limit_requests: int = 100\n    rate_limit_window: int = 60\n    cache_ttl: int = 300\n    max_retries: int = 3\n    timeout: int = 30\n\n    class Config:\n        extra = \"allow\"\n\n@dataclass\nclass RequestContext:\n    \"\"\"Request context for tool calls\"\"\"\n    user_id: str\n    session_id: Optional[str] = None\n    metadata: Dict[str, Any] = field(default_factory=dict)\n    timestamp: datetime = field(default_factory=datetime.utcnow)\n\nclass RateLimiter:\n    \"\"\"Redis-based rate limiter for MCP operations\"\"\"\n\n    def __init__(self, redis_url: str, requests: int, window: int):\n        self.redis_url = redis_url\n        self.requests = requests\n        self.window = window\n        self._redis = None\n\n    async def _get_redis(self):\n        if not self._redis:\n            self._redis = await redis.from_url(self.redis_url)\n        return self._redis\n\n    async def is_allowed(self, key: str) -> bool:\n        \"\"\"Check if request is allowed\"\"\"\n        r = await self._get_redis()\n        current = await r.incr(f\"rate_limit:{key}\")\n\n        if current == 1:\n            await r.expire(f\"rate_limit:{key}\", self.window)\n\n        return current \u003C= self.requests\n\n    async def get_remaining(self, key: str) -> int:\n        \"\"\"Get remaining requests\"\"\"\n        r = await self._get_redis()\n        current = await r.get(f\"rate_limit:{key}\")\n        return max(0, self.requests - int(current or 0))\n\nclass CacheManager:\n    \"\"\"Redis-based caching for MCP responses\"\"\"\n\n    def __init__(self, redis_url: str, ttl: int = 300):\n        self.redis_url = redis_url\n        self.ttl = ttl\n        self._redis = None\n\n    async def _get_redis(self):\n        if not self._redis:\n            self._redis = await redis.from_url(self.redis_url)\n        return self._redis\n\n    def _make_key(self, tool_name: str, args: Dict[str, Any]) -> str:\n        \"\"\"Generate cache key from tool name and arguments\"\"\"\n        import hashlib\n        args_str = json.dumps(args, sort_keys=True)\n        return f\"cache:{tool_name}:{hashlib.md5(args_str.encode()).hexdigest()}\"\n\n    async def get(self, tool_name: str, args: Dict[str, Any]) -> Optional[Any]:\n        \"\"\"Get cached result\"\"\"\n        r = await self._get_redis()\n        key = self._make_key(tool_name, args)\n        result = await r.get(key)\n        return json.loads(result) if result else None\n\n    async def set(self, tool_name: str, args: Dict[str, Any], value: Any):\n        \"\"\"Cache result\"\"\"\n        r = await self._get_redis()\n        key = self._make_key(tool_name, args)\n        await r.setex(key, self.ttl, json.dumps(value))\n\nclass BaseMCPServer:\n    \"\"\"Base MCP Server with common functionality\"\"\"\n\n    def __init__(self, config: ServerConfig):\n        self.config = config\n        self.server = Server(config.name)\n        self.tools: Dict[str, Callable] = {}\n        self.rate_limiter: Optional[RateLimiter] = None\n        self.cache: Optional[CacheManager] = None\n\n        # Setup optional components\n        if config.redis_url:\n            self.rate_limiter = RateLimiter(\n                config.redis_url,\n                config.rate_limit_requests,\n                config.rate_limit_window\n            )\n            self.cache = CacheManager(\n                config.redis_url,\n                config.cache_ttl\n            )\n\n        # Register handlers\n        self._register_handlers()\n\n        logger.info(f\"MCP Server '{config.name}' initialized\")\n\n    def _register_handlers(self):\n        \"\"\"Register MCP handlers\"\"\"\n        @self.server.list_tools()\n        async def handle_list_tools() -> List[Tool]:\n            \"\"\"Return list of available tools\"\"\"\n            return await self.list_tools()\n\n        @self.server.call_tool()\n        async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[TextContent]:\n            \"\"\"Handle tool call with rate limiting and caching\"\"\"\n            return await self.call_tool(name, arguments)\n\n    def register_tool(self, name: str, handler: Callable, schema: Dict[str, Any]):\n        \"\"\"Register a new tool\"\"\"\n        self.tools[name] = {\n            \"handler\": handler,\n            \"schema\": schema\n        }\n        logger.info(f\"Registered tool: {name}\")\n\n    async def list_tools(self) -> List[Tool]:\n        \"\"\"List all available tools\"\"\"\n        tools = []\n        for name, tool_info in self.tools.items():\n            tools.append(Tool(\n                name=name,\n                description=tool_info[\"schema\"].get(\"description\", \"\"),\n                inputSchema=tool_info[\"schema\"].get(\"inputSchema\", {})\n            ))\n        return tools\n\n    async def call_tool(self, name: str, arguments: Dict[str, Any]) -> List[TextContent]:\n        \"\"\"Execute a tool call with full middleware pipeline\"\"\"\n        start_time = datetime.utcnow()\n\n        try:\n            # Extract context from arguments\n            context = self._extract_context(arguments)\n\n            # Rate limiting check\n            if self.rate_limiter:\n                rate_key = f\"{context.user_id}:{name}\"\n                if not await self.rate_limiter.is_allowed(rate_key):\n                    return [TextContent(\n                        type=\"text\",\n                        text=json.dumps({\n                            \"status\": \"error\",\n                            \"error\": \"Rate limit exceeded\",\n                            \"remaining\": await self.rate_limiter.get_remaining(rate_key)\n                        })\n                    )]\n\n            # Check cache\n            if self.cache and self._is_cacheable(name):\n                cached_result = await self.cache.get(name, arguments)\n                if cached_result:\n                    logger.info(f\"Cache hit for tool: {name}\")\n                    return [TextContent(\n                        type=\"text\",\n                        text=json.dumps(cached_result)\n                    )]\n\n            # Validate tool exists\n            if name not in self.tools:\n                raise ValueError(f\"Unknown tool: {name}\")\n\n            # Validate arguments\n            schema = self.tools[name][\"schema\"]\n            self._validate_arguments(arguments, schema)\n\n            # Execute tool\n            handler = self.tools[name][\"handler\"]\n            result = await self._execute_tool(handler, arguments, context)\n\n            # Cache result if applicable\n            if self.cache and self._is_cacheable(name) and result.get(\"status\") != \"error\":\n                await self.cache.set(name, arguments, result)\n\n            # Log execution\n            duration = (datetime.utcnow() - start_time).total_seconds()\n            logger.info(f\"Tool {name} executed in {duration:.2f}s for user {context.user_id}\")\n\n            return [TextContent(\n                type=\"text\",\n                text=json.dumps(result, default=str)\n            )]\n\n        except Exception as e:\n            logger.error(f\"Error executing tool {name}: {str(e)}\", exc_info=True)\n            duration = (datetime.utcnow() - start_time).total_seconds()\n            logger.error(f\"Tool {name} failed after {duration:.2f}s\")\n\n            return [TextContent(\n                type=\"text\",\n                text=json.dumps({\n                    \"status\": \"error\",\n                    \"error\": str(e),\n                    \"tool\": name,\n                    \"timestamp\": datetime.utcnow().isoformat()\n                })\n            )]\n\n    def _extract_context(self, arguments: Dict[str, Any]) -> RequestContext:\n        \"\"\"Extract request context from arguments\"\"\"\n        user_id = arguments.pop(\"_user_id\", \"anonymous\")\n        session_id = arguments.pop(\"_session_id\", None)\n        metadata = arguments.pop(\"_metadata\", {})\n\n        return RequestContext(\n            user_id=user_id,\n            session_id=session_id,\n            metadata=metadata\n        )\n\n    def _validate_arguments(self, arguments: Dict[str, Any], schema: Dict[str, Any]):\n        \"\"\"Validate tool arguments against schema\"\"\"\n        # Basic validation - can be extended with pydantic\n        input_schema = schema.get(\"inputSchema\", {})\n        required = input_schema.get(\"required\", [])\n        properties = input_schema.get(\"properties\", {})\n\n        # Check required fields\n        for field in required:\n            if field not in arguments:\n                raise ValueError(f\"Missing required field: {field}\")\n\n        # Validate field types\n        for field, value in arguments.items():\n            if field in properties:\n                field_schema = properties[field]\n                expected_type = field_schema.get(\"type\")\n\n                if expected_type == \"string\" and not isinstance(value, str):\n                    raise ValueError(f\"Field {field} must be a string\")\n                elif expected_type == \"integer\" and not isinstance(value, int):\n                    raise ValueError(f\"Field {field} must be an integer\")\n                elif expected_type == \"array\" and not isinstance(value, list):\n                    raise ValueError(f\"Field {field} must be an array\")\n\n                # Check enum values\n                if \"enum\" in field_schema and value not in field_schema[\"enum\"]:\n                    raise ValueError(f\"Field {field} must be one of {field_schema['enum']}\")\n\n    def _is_cacheable(self, tool_name: str) -> bool:\n        \"\"\"Determine if tool result should be cached\"\"\"\n        # Non-mutating operations are cacheable\n        non_mutating = [\"get\", \"list\", \"search\", \"find\", \"read\"]\n        return any(op in tool_name.lower() for op in non_mutating)\n\n    async def _execute_tool(self, handler: Callable, arguments: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Execute tool handler with error handling\"\"\"\n        try:\n            # Pass context to handler if it accepts it\n            import inspect\n            sig = inspect.signature(handler)\n\n            if 'context' in sig.parameters:\n                result = await handler(arguments, context=context)\n            else:\n                result = await handler(arguments)\n\n            return result\n\n        except Exception as e:\n            logger.error(f\"Tool handler failed: {str(e)}\")\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n    async def run(self):\n        \"\"\"Start the MCP server\"\"\"\n        logger.info(f\"Starting MCP server: {self.config.name}\")\n        async with stdio_server() as (read_stream, write_stream):\n            await self.server.run(\n                read_stream,\n                write_stream,\n                InitializationOptions(\n                    server_name=self.config.name,\n                    server_version=self.config.version,\n                    capabilities=self.server.get_capabilities(\n                        notification_options=NotificationOptions(),\n                        experimental_capabilities={},\n                    )\n                )\n            )\n\ndef tool(\n    name: Optional[str] = None,\n    description: str = \"\",\n    input_schema: Optional[Dict[str, Any]] = None\n):\n    \"\"\"Decorator for registering MCP tools\"\"\"\n    def decorator(func):\n        tool_name = name or func.__name__\n        schema = {\n            \"description\": description or func.__doc__ or \"\",\n            \"inputSchema\": input_schema or {}\n        }\n\n        # Store schema on function for later registration\n        func._mcp_tool_schema = schema\n        func._mcp_tool_name = tool_name\n\n        return func\n    return decorator\n```\n\n## 2. Database Integration Patterns\n\n```python\n# mcp_server\u002Fdatabase.py\n\"\"\"\nGeneric Database Integration for MCP Servers\nSupports multiple ORMs and connection patterns\n\"\"\"\n\nimport asyncio\nfrom abc import ABC, abstractmethod\nfrom contextlib import asynccontextmanager\nfrom typing import Any, Dict, List, Optional, TypeVar, Generic, Union\nfrom datetime import datetime\nimport json\n\nfrom sqlalchemy import create_engine, MetaData, Table, Column, Integer, String, DateTime, Text, Boolean, select, update, delete, insert\nfrom sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker\nfrom sqlalchemy.orm import sessionmaker, declarative_base\nfrom sqlalchemy.pool import NullPool\nimport asyncpg\nimport motor.motor_asyncio\nfrom redis.asyncio import Redis\n\n# Type variables\nT = TypeVar('T')\n\nclass DatabaseBackend(ABC):\n    \"\"\"Abstract base for database backends\"\"\"\n\n    @abstractmethod\n    async def connect(self):\n        \"\"\"Establish connection\"\"\"\n        pass\n\n    @abstractmethod\n    async def disconnect(self):\n        \"\"\"Close connection\"\"\"\n        pass\n\n    @abstractmethod\n    async def execute_query(self, query: str, params: Dict[str, Any] = None) -> List[Dict[str, Any]]:\n        \"\"\"Execute a query and return results\"\"\"\n        pass\n\n    @abstractmethod\n    async def execute_command(self, command: str, params: Dict[str, Any] = None) -> Any:\n        \"\"\"Execute a command (INSERT, UPDATE, DELETE)\"\"\"\n        pass\n\nclass PostgresBackend(DatabaseBackend):\n    \"\"\"PostgreSQL backend using asyncpg\"\"\"\n\n    def __init__(self, connection_string: str):\n        self.connection_string = connection_string\n        self.pool: Optional[asyncpg.Pool] = None\n\n    async def connect(self):\n        self.pool = await asyncpg.create_pool(\n            self.connection_string,\n            min_size=5,\n            max_size=20,\n            command_timeout=60\n        )\n\n    async def disconnect(self):\n        if self.pool:\n            await self.pool.close()\n\n    async def execute_query(self, query: str, params: Dict[str, Any] = None) -> List[Dict[str, Any]]:\n        async with self.pool.acquire() as conn:\n            rows = await conn.fetch(query, *params.values() if params else [])\n            return [dict(row) for row in rows]\n\n    async def execute_command(self, command: str, params: Dict[str, Any] = None) -> Any:\n        async with self.pool.acquire() as conn:\n            return await conn.execute(command, *params.values() if params else [])\n\nclass SQLAlchemyBackend(DatabaseBackend):\n    \"\"\"SQLAlchemy backend for multiple databases\"\"\"\n\n    def __init__(self, database_url: str, async_mode: bool = True):\n        self.database_url = database_url\n        self.async_mode = async_mode\n        self.engine = None\n        self.session_factory = None\n\n    async def connect(self):\n        if self.async_mode:\n            self.engine = create_async_engine(\n                self.database_url,\n                pool_pre_ping=True,\n                pool_recycle=300,\n                echo=False\n            )\n            self.session_factory = async_sessionmaker(\n                self.engine,\n                class_=AsyncSession,\n                expire_on_commit=False\n            )\n        else:\n            self.engine = create_engine(\n                self.database_url,\n                pool_pre_ping=True,\n                pool_recycle=300,\n                echo=False\n            )\n            self.session_factory = sessionmaker(\n                bind=self.engine,\n                expire_on_commit=False\n            )\n\n    async def disconnect(self):\n        if self.engine:\n            await self.engine.dispose()\n\n    @asynccontextmanager\n    async def get_session(self):\n        \"\"\"Get database session\"\"\"\n        async with self.session_factory() as session:\n            try:\n                yield session\n                if self.async_mode:\n                    await session.commit()\n                else:\n                    session.commit()\n            except Exception:\n                if self.async_mode:\n                    await session.rollback()\n                else:\n                    session.rollback()\n                raise\n            finally:\n                if self.async_mode:\n                    await session.close()\n                else:\n                    session.close()\n\n    async def execute_query(self, query: Any, params: Dict[str, Any] = None) -> List[Dict[str, Any]]:\n        \"\"\"Execute SQLAlchemy query\"\"\"\n        async with self.get_session() as session:\n            if isinstance(query, str):\n                # Raw SQL query\n                result = await session.execute(query, params or {})\n                rows = result.fetchall()\n                return [dict(row._mapping) for row in rows]\n            else:\n                # SQLAlchemy ORM query\n                result = await session.execute(query)\n                rows = result.fetchall()\n                return [dict(row._mapping) for row in rows]\n\n    async def execute_command(self, command: Any, params: Dict[str, Any] = None) -> Any:\n        \"\"\"Execute SQLAlchemy command\"\"\"\n        async with self.get_session() as session:\n            if isinstance(command, str):\n                # Raw SQL command\n                result = await session.execute(command, params or {})\n                await session.commit()\n                return result\n            else:\n                # SQLAlchemy ORM command\n                await session.execute(command, params or {})\n                await session.commit()\n                return None\n\nclass MongoBackend(DatabaseBackend):\n    \"\"\"MongoDB backend using motor\"\"\"\n\n    def __init__(self, connection_string: str, database_name: str):\n        self.connection_string = connection_string\n        self.database_name = database_name\n        self.client = None\n        self.db = None\n\n    async def connect(self):\n        self.client = motor.motor_asyncio.AsyncIOMotorClient(self.connection_string)\n        self.db = self.client[self.database_name]\n\n    async def disconnect(self):\n        if self.client:\n            self.client.close()\n\n    async def execute_query(self, collection: str, query: Dict[str, Any] = None) -> List[Dict[str, Any]]:\n        \"\"\"Execute MongoDB find query\"\"\"\n        cursor = self.db[collection].find(query or {})\n        results = []\n        async for document in cursor:\n            # Convert ObjectId to string\n            if '_id' in document:\n                document['_id'] = str(document['_id'])\n            results.append(document)\n        return results\n\n    async def execute_command(self, operation: str, collection: str, data: Dict[str, Any]) -> Any:\n        \"\"\"Execute MongoDB command\"\"\"\n        if operation == \"insert\":\n            result = await self.db[collection].insert_one(data)\n            return str(result.inserted_id)\n        elif operation == \"update\":\n            filter_ = data.pop(\"_filter\")\n            update_data = {\"$set\": data}\n            result = await self.db[collection].update_one(filter_, update_data)\n            return result.modified_count\n        elif operation == \"delete\":\n            result = await self.db[collection].delete_one(data)\n            return result.deleted_count\n\nclass DatabaseManager(Generic[T]):\n    \"\"\"Generic database manager for MCP servers\"\"\"\n\n    def __init__(self, backend: DatabaseBackend):\n        self.backend = backend\n        self._connected = False\n\n    async def connect(self):\n        \"\"\"Connect to database\"\"\"\n        if not self._connected:\n            await self.backend.connect()\n            self._connected = True\n\n    async def disconnect(self):\n        \"\"\"Disconnect from database\"\"\"\n        if self._connected:\n            await self.backend.disconnect()\n            self._connected = False\n\n    @asynccontextmanager\n    async def transaction(self):\n        \"\"\"Database transaction context manager\"\"\"\n        if hasattr(self.backend, 'get_session'):\n            async with self.backend.get_session() as session:\n                yield session\n        else:\n            # For backends that don't support transactions\n            yield self.backend\n\n    async def find_one(self, table_or_collection: str, query: Dict[str, Any]) -> Optional[Dict[str, Any]]:\n        \"\"\"Find a single record\"\"\"\n        if isinstance(self.backend, MongoBackend):\n            results = await self.backend.execute_query(table_or_collection, query)\n            return results[0] if results else None\n        else:\n            # SQL implementation\n            where_clause = \" AND \".join([f\"{k} = :{k}\" for k in query.keys()])\n            sql = f\"SELECT * FROM {table_or_collection} WHERE {where_clause} LIMIT 1\"\n            results = await self.backend.execute_query(sql, query)\n            return results[0] if results else None\n\n    async def find_many(\n        self,\n        table_or_collection: str,\n        query: Dict[str, Any] = None,\n        limit: int = None,\n        offset: int = None,\n        order_by: str = None\n    ) -> List[Dict[str, Any]]:\n        \"\"\"Find multiple records\"\"\"\n        query = query or {}\n\n        if isinstance(self.backend, MongoBackend):\n            cursor = self.backend.db[table_or_collection].find(query)\n            if limit:\n                cursor = cursor.limit(limit)\n            if offset:\n                cursor = cursor.skip(offset)\n            if order_by:\n                # MongoDB sort format\n                sort_field, sort_dir = order_by.split()\n                cursor = cursor.sort([(sort_field, 1 if sort_dir == 'ASC' else -1)])\n\n            results = []\n            async for document in cursor:\n                if '_id' in document:\n                    document['_id'] = str(document['_id'])\n                results.append(document)\n            return results\n        else:\n            # SQL implementation\n            where_clause = \"\"\n            if query:\n                where_clause = \"WHERE \" + \" AND \".join([f\"{k} = :{k}\" for k in query.keys()])\n\n            sql = f\"SELECT * FROM {table_or_collection} {where_clause}\"\n\n            if order_by:\n                sql += f\" ORDER BY {order_by}\"\n\n            if limit:\n                sql += f\" LIMIT {limit}\"\n\n            if offset:\n                sql += f\" OFFSET {offset}\"\n\n            return await self.backend.execute_query(sql, query)\n\n    async def create(self, table_or_collection: str, data: Dict[str, Any]) -> Any:\n        \"\"\"Create a new record\"\"\"\n        data = data.copy()\n\n        # Add timestamps\n        data['created_at'] = datetime.utcnow()\n        data['updated_at'] = datetime.utcnow()\n\n        if isinstance(self.backend, MongoBackend):\n            return await self.backend.execute_command(\"insert\", table_or_collection, data)\n        else:\n            # SQL implementation\n            columns = list(data.keys())\n            placeholders = [f\":{col}\" for col in columns]\n            sql = f\"INSERT INTO {table_or_collection} ({', '.join(columns)}) VALUES ({', '.join(placeholders)})\"\n            return await self.backend.execute_command(sql, data)\n\n    async def update(self, table_or_collection: str, query: Dict[str, Any], data: Dict[str, Any]) -> int:\n        \"\"\"Update records\"\"\"\n        data = data.copy()\n        data['updated_at'] = datetime.utcnow()\n\n        if isinstance(self.backend, MongoBackend):\n            data['_filter'] = query\n            return await self.backend.execute_command(\"update\", table_or_collection, data)\n        else:\n            # SQL implementation\n            where_clause = \" AND \".join([f\"{k} = :{k}\" for k in query.keys()])\n            set_clause = \", \".join([f\"{k} = :update_{k}\" for k in data.keys()])\n\n            # Prefix update params to avoid conflicts\n            update_params = {f\"update_{k}\": v for k, v in data.items()}\n            params = {**query, **update_params}\n\n            sql = f\"UPDATE {table_or_collection} SET {set_clause} WHERE {where_clause}\"\n            result = await self.backend.execute_command(sql, params)\n            return result.rowcount if hasattr(result, 'rowcount') else 0\n\n    async def delete(self, table_or_collection: str, query: Dict[str, Any]) -> int:\n        \"\"\"Delete records\"\"\"\n        if isinstance(self.backend, MongoBackend):\n            return await self.backend.execute_command(\"delete\", table_or_collection, query)\n        else:\n            # SQL implementation\n            where_clause = \" AND \".join([f\"{k} = :{k}\" for k in query.keys()])\n            sql = f\"DELETE FROM {table_or_collection} WHERE {where_clause}\"\n            result = await self.backend.execute_command(sql, query)\n            return result.rowcount if hasattr(result, 'rowcount') else 0\n\n    async def count(self, table_or_collection: str, query: Dict[str, Any] = None) -> int:\n        \"\"\"Count records\"\"\"\n        query = query or {}\n\n        if isinstance(self.backend, MongoBackend):\n            return await self.backend.db[table_or_collection].count_documents(query)\n        else:\n            # SQL implementation\n            where_clause = \"\"\n            if query:\n                where_clause = \"WHERE \" + \" AND \".join([f\"{k} = :{k}\" for k in query.keys()])\n\n            sql = f\"SELECT COUNT(*) as count FROM {table_or_collection} {where_clause}\"\n            results = await self.backend.execute_query(sql, query)\n            return results[0]['count'] if results else 0\n\n# Factory function for creating database managers\ndef create_database_manager(database_url: str, backend_type: str = \"auto\") -> DatabaseManager:\n    \"\"\"Create database manager based on URL or backend type\"\"\"\n\n    if backend_type == \"auto\":\n        if database_url.startswith(\"postgresql+asyncpg:\u002F\u002F\"):\n            backend = SQLAlchemyBackend(database_url, async_mode=True)\n        elif database_url.startswith(\"mongodb:\u002F\u002F\"):\n            import re\n            match = re.match(r'mongodb:\u002F\u002F[^\u002F]+\u002F([^?]*)', database_url)\n            db_name = match.group(1) if match else \"default\"\n            backend = MongoBackend(database_url, db_name)\n        elif database_url.startswith(\"postgresql:\u002F\u002F\"):\n            backend = PostgresBackend(database_url)\n        else:\n            backend = SQLAlchemyBackend(database_url, async_mode=True)\n    else:\n        if backend_type == \"postgres\":\n            backend = PostgresBackend(database_url)\n        elif backend_type == \"mongodb\":\n            db_name = database_url.split(\"\u002F\")[-1].split(\"?\")[0]\n            backend = MongoBackend(database_url, db_name)\n        elif backend_type == \"sqlalchemy\":\n            backend = SQLAlchemyBackend(database_url)\n        else:\n            raise ValueError(f\"Unknown backend type: {backend_type}\")\n\n    return DatabaseManager(backend)\n```\n\n## 3. Tool Implementation Patterns\n\n```python\n# mcp_server\u002Ftools.py\n\"\"\"\nGeneric MCP Tool Implementation Patterns\n\"\"\"\n\nfrom typing import Any, Dict, List, Optional, Union, Callable\nfrom datetime import datetime, timedelta\nimport json\nimport uuid\nfrom dataclasses import dataclass, field\n\nfrom .core import BaseMCPServer, tool, RequestContext\nfrom .database import DatabaseManager\n\nclass BaseTool:\n    \"\"\"Base class for MCP tools\"\"\"\n\n    def __init__(self, db_manager: DatabaseManager, cache=None):\n        self.db_manager = db_manager\n        self.cache = cache\n\n    async def execute(self, args: Dict[str, Any], context: RequestContext = None) -> Dict[str, Any]:\n        \"\"\"Execute the tool logic\"\"\"\n        raise NotImplementedError\n\n    def _validate_permissions(self, context: RequestContext, required_permission: str = None) -> bool:\n        \"\"\"Validate user permissions\"\"\"\n        # Implement permission checking logic\n        return True\n\nclass CRUDBaseTool(BaseTool):\n    \"\"\"Base CRUD tool for any entity\"\"\"\n\n    def __init__(self, table_name: str, db_manager: DatabaseManager, schema: Dict[str, Any]):\n        super().__init__(db_manager)\n        self.table_name = table_name\n        self.schema = schema\n        self.entity_name = table_name.rstrip('s')  # Remove plural 's'\n\n    async def create(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Create entity\"\"\"\n        try:\n            # Validate against schema\n            validated_data = self._validate_data(args, for_create=True)\n\n            # Add user context\n            if context:\n                validated_data['user_id'] = context.user_id\n                if context.session_id:\n                    validated_data['session_id'] = context.session_id\n\n            # Insert into database\n            result = await self.db_manager.create(self.table_name, validated_data)\n\n            return {\n                \"status\": \"created\",\n                \"id\": result,\n                \"entity\": self.entity_name,\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"create\"\n            }\n\n    async def get(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Get entity by ID\"\"\"\n        try:\n            entity_id = args.get(\"id\")\n            if not entity_id:\n                raise ValueError(\"Missing required field: id\")\n\n            # Add user filter for security\n            query = {\"id\": entity_id}\n            if context and not self._validate_permissions(context, \"read_all\"):\n                query[\"user_id\"] = context.user_id\n\n            result = await self.db_manager.find_one(self.table_name, query)\n\n            if not result:\n                return {\n                    \"status\": \"not_found\",\n                    \"entity\": self.entity_name,\n                    \"id\": entity_id\n                }\n\n            return {\n                \"status\": \"success\",\n                \"entity\": self.entity_name,\n                \"data\": self._serialize_data(result)\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"get\"\n            }\n\n    async def list(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"List entities with filtering\"\"\"\n        try:\n            # Build query from args\n            query = {}\n            filters = args.get(\"filters\", {})\n            limit = args.get(\"limit\", 20)\n            offset = args.get(\"offset\", 0)\n            order_by = args.get(\"order_by\", \"created_at DESC\")\n\n            # Add user filter for security\n            if context and not self._validate_permissions(context, \"read_all\"):\n                query[\"user_id\"] = context.user_id\n\n            # Apply additional filters\n            query.update(filters)\n\n            # Fetch from database\n            results = await self.db_manager.find_many(\n                self.table_name,\n                query=query,\n                limit=limit,\n                offset=offset,\n                order_by=order_by\n            )\n\n            # Get total count\n            total = await self.db_manager.count(self.table_name, query)\n\n            return {\n                \"status\": \"success\",\n                \"entity\": self.entity_name,\n                \"data\": [self._serialize_data(r) for r in results],\n                \"pagination\": {\n                    \"total\": total,\n                    \"limit\": limit,\n                    \"offset\": offset,\n                    \"has_more\": offset + limit \u003C total\n                }\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"list\"\n            }\n\n    async def update(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Update entity\"\"\"\n        try:\n            entity_id = args.pop(\"id\", None)\n            if not entity_id:\n                raise ValueError(\"Missing required field: id\")\n\n            # Validate update data\n            update_data = self._validate_data(args, for_create=False)\n\n            # Build query filter\n            query = {\"id\": entity_id}\n            if context and not self._validate_permissions(context, \"update_all\"):\n                query[\"user_id\"] = context.user_id\n\n            # Update in database\n            affected = await self.db_manager.update(self.table_name, query, update_data)\n\n            if affected == 0:\n                return {\n                    \"status\": \"not_found\",\n                    \"entity\": self.entity_name,\n                    \"id\": entity_id\n                }\n\n            return {\n                \"status\": \"updated\",\n                \"entity\": self.entity_name,\n                \"id\": entity_id,\n                \"affected_rows\": affected,\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"update\"\n            }\n\n    async def delete(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Delete entity\"\"\"\n        try:\n            entity_id = args.get(\"id\")\n            if not entity_id:\n                raise ValueError(\"Missing required field: id\")\n\n            # Build query filter\n            query = {\"id\": entity_id}\n            if context and not self._validate_permissions(context, \"delete_all\"):\n                query[\"user_id\"] = context.user_id\n\n            # Delete from database\n            affected = await self.db_manager.delete(self.table_name, query)\n\n            if affected == 0:\n                return {\n                    \"status\": \"not_found\",\n                    \"entity\": self.entity_name,\n                    \"id\": entity_id\n                }\n\n            return {\n                \"status\": \"deleted\",\n                \"entity\": self.entity_name,\n                \"id\": entity_id,\n                \"affected_rows\": affected,\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"delete\"\n            }\n\n    def _validate_data(self, data: Dict[str, Any], for_create: bool = False) -> Dict[str, Any]:\n        \"\"\"Validate data against schema\"\"\"\n        validated = {}\n        schema_fields = self.schema.get(\"properties\", {})\n        required_fields = self.schema.get(\"required\", [])\n\n        # Check required fields for create\n        if for_create:\n            for field in required_fields:\n                if field not in data:\n                    raise ValueError(f\"Missing required field: {field}\")\n\n        # Validate each field\n        for field, value in data.items():\n            if field not in schema_fields:\n                continue  # Skip unknown fields or raise error based on strictness\n\n            field_schema = schema_fields[field]\n            field_type = field_schema.get(\"type\")\n\n            # Type validation\n            if field_type == \"string\":\n                if not isinstance(value, str):\n                    raise ValueError(f\"Field {field} must be a string\")\n                # Check min\u002Fmax length\n                if \"minLength\" in field_schema and len(value) \u003C field_schema[\"minLength\"]:\n                    raise ValueError(f\"Field {field} is too short\")\n                if \"maxLength\" in field_schema and len(value) > field_schema[\"maxLength\"]:\n                    raise ValueError(f\"Field {field} is too long\")\n            elif field_type == \"integer\":\n                if not isinstance(value, int):\n                    raise ValueError(f\"Field {field} must be an integer\")\n                # Check min\u002Fmax value\n                if \"minimum\" in field_schema and value \u003C field_schema[\"minimum\"]:\n                    raise ValueError(f\"Field {field} is too small\")\n                if \"maximum\" in field_schema and value > field_schema[\"maximum\"]:\n                    raise ValueError(f\"Field {field} is too large\")\n            elif field_type == \"array\":\n                if not isinstance(value, list):\n                    raise ValueError(f\"Field {field} must be an array\")\n\n            # Check enum values\n            if \"enum\" in field_schema and value not in field_schema[\"enum\"]:\n                raise ValueError(f\"Field {field} must be one of {field_schema['enum']}\")\n\n            validated[field] = value\n\n        return validated\n\n    def _serialize_data(self, data: Dict[str, Any]) -> Dict[str, Any]:\n        \"\"\"Serialize data for output\"\"\"\n        serialized = data.copy()\n\n        # Handle datetime serialization\n        for key, value in serialized.items():\n            if isinstance(value, datetime):\n                serialized[key] = value.isoformat()\n            elif isinstance(value, dict):\n                # Convert complex types to JSON string\n                try:\n                    json.dumps(value)\n                except TypeError:\n                    serialized[key] = str(value)\n\n        return serialized\n\nclass BulkOperationTool(BaseTool):\n    \"\"\"Tool for bulk operations on entities\"\"\"\n\n    def __init__(self, table_name: str, db_manager: DatabaseManager, schema: Dict[str, Any]):\n        super().__init__(db_manager)\n        self.table_name = table_name\n        self.schema = schema\n        self.entity_name = table_name.rstrip('s')\n\n    async def bulk_create(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Bulk create entities\"\"\"\n        try:\n            items = args.get(\"items\", [])\n            if not items:\n                raise ValueError(\"No items provided for bulk create\")\n\n            # Validate all items\n            validated_items = []\n            for item in items:\n                validated = self._validate_item(item)\n                if context:\n                    validated[\"user_id\"] = context.user_id\n                validated_items.append(validated)\n\n            # Insert all items\n            results = []\n            for item in validated_items:\n                result = await self.db_manager.create(self.table_name, item)\n                results.append(result)\n\n            return {\n                \"status\": \"created\",\n                \"entity\": self.entity_name,\n                \"count\": len(results),\n                \"ids\": results,\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"bulk_create\"\n            }\n\n    async def bulk_update(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Bulk update entities\"\"\"\n        try:\n            updates = args.get(\"updates\", [])\n            if not updates:\n                raise ValueError(\"No updates provided\")\n\n            total_affected = 0\n            for update in updates:\n                entity_id = update.get(\"id\")\n                update_data = update.get(\"data\", {})\n\n                if not entity_id:\n                    continue\n\n                # Build query\n                query = {\"id\": entity_id}\n                if context:\n                    query[\"user_id\"] = context.user_id\n\n                # Update\n                affected = await self.db_manager.update(self.table_name, query, update_data)\n                total_affected += affected\n\n            return {\n                \"status\": \"updated\",\n                \"entity\": self.entity_name,\n                \"affected_rows\": total_affected,\n                \"updates_processed\": len(updates),\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"bulk_update\"\n            }\n\n    async def bulk_delete(self, args: Dict[str, Any], context: RequestContext) -> Dict[str, Any]:\n        \"\"\"Bulk delete entities\"\"\"\n        try:\n            ids = args.get(\"ids\", [])\n            if not ids:\n                raise ValueError(\"No IDs provided for bulk delete\")\n\n            total_affected = 0\n            for entity_id in ids:\n                # Build query\n                query = {\"id\": entity_id}\n                if context:\n                    query[\"user_id\"] = context.user_id\n\n                # Delete\n                affected = await self.db_manager.delete(self.table_name, query)\n                total_affected += affected\n\n            return {\n                \"status\": \"deleted\",\n                \"entity\": self.entity_name,\n                \"affected_rows\": total_affected,\n                \"ids_processed\": len(ids),\n                \"timestamp\": datetime.utcnow().isoformat()\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"entity\": self.entity_name,\n                \"operation\": \"bulk_delete\"\n            }\n\n    def _validate_item(self, item: Dict[str, Any]) -> Dict[str, Any]:\n        \"\"\"Validate a single item\"\"\"\n        # Use CRUD base tool validation\n        crud_tool = CRUDBaseTool(self.table_name, self.db_manager, self.schema)\n        return crud_tool._validate_data(item, for_create=True)\n```\n\n## 4. Example: Building a Generic Task Management MCP Server\n\n```python\n# examples\u002Ftask_mcp_server.py\n\"\"\"\nExample: Task Management MCP Server using generic patterns\n\"\"\"\n\nimport os\nfrom typing import Dict, Any\n\nfrom mcp_server.core import BaseMCPServer, ServerConfig, tool\nfrom mcp_server.database import create_database_manager\nfrom mcp_server.tools import CRUDBaseTool, BulkOperationTool\n\n# Server configuration\nconfig = ServerConfig(\n    name=\"task-manager\",\n    version=\"1.0.0\",\n    description=\"Generic task management MCP server\",\n    redis_url=os.getenv(\"REDIS_URL\", \"redis:\u002F\u002Flocalhost:6379\"),\n    database_url=os.getenv(\"DATABASE_URL\", \"postgresql+asyncpg:\u002F\u002Fuser:pass@localhost\u002Ftasks\")\n)\n\n# Task entity schema\nTASK_SCHEMA = {\n    \"type\": \"object\",\n    \"properties\": {\n        \"title\": {\n            \"type\": \"string\",\n            \"minLength\": 1,\n            \"maxLength\": 200,\n            \"description\": \"Task title\"\n        },\n        \"description\": {\n            \"type\": \"string\",\n            \"maxLength\": 1000,\n            \"description\": \"Task description\"\n        },\n        \"priority\": {\n            \"type\": \"string\",\n            \"enum\": [\"low\", \"medium\", \"high\"],\n            \"default\": \"medium\",\n            \"description\": \"Task priority\"\n        },\n        \"status\": {\n            \"type\": \"string\",\n            \"enum\": [\"todo\", \"in_progress\", \"completed\"],\n            \"default\": \"todo\",\n            \"description\": \"Task status\"\n        },\n        \"due_date\": {\n            \"type\": \"string\",\n            \"format\": \"date-time\",\n            \"description\": \"Optional due date\"\n        },\n        \"tags\": {\n            \"type\": \"array\",\n            \"items\": {\"type\": \"string\"},\n            \"description\": \"Task tags\"\n        }\n    },\n    \"required\": [\"title\"]\n}\n\nclass TaskMCPServer(BaseMCPServer):\n    \"\"\"Task Management MCP Server\"\"\"\n\n    def __init__(self, config: ServerConfig):\n        super().__init__(config)\n\n        # Initialize database\n        self.db_manager = create_database_manager(config.database_url)\n\n        # Initialize tools\n        self.task_tool = CRUDBaseTool(\"tasks\", self.db_manager, TASK_SCHEMA)\n        self.bulk_tool = BulkOperationTool(\"tasks\", self.db_manager, TASK_SCHEMA)\n\n        # Register tools\n        self._register_task_tools()\n\n    def _register_task_tools(self):\n        \"\"\"Register all task-related tools\"\"\"\n\n        # Create task\n        self.register_tool(\n            \"create_task\",\n            self.task_tool.create,\n            {\n                \"description\": \"Create a new task\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"title\": {\"type\": \"string\", \"description\": \"Task title\"},\n                        \"description\": {\"type\": \"string\", \"description\": \"Optional description\"},\n                        \"priority\": {\"type\": \"string\", \"enum\": [\"low\", \"medium\", \"high\"]},\n                        \"due_date\": {\"type\": \"string\", \"format\": \"date-time\"},\n                        \"tags\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}}\n                    },\n                    \"required\": [\"title\"]\n                }\n            }\n        )\n\n        # Get task\n        self.register_tool(\n            \"get_task\",\n            self.task_tool.get,\n            {\n                \"description\": \"Get a task by ID\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"id\": {\"type\": \"integer\", \"description\": \"Task ID\"}\n                    },\n                    \"required\": [\"id\"]\n                }\n            }\n        )\n\n        # List tasks\n        self.register_tool(\n            \"list_tasks\",\n            self.task_tool.list,\n            {\n                \"description\": \"List tasks with optional filtering\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"filters\": {\"type\": \"object\", \"description\": \"Filter criteria\"},\n                        \"limit\": {\"type\": \"integer\", \"minimum\": 1, \"maximum\": 100, \"default\": 20},\n                        \"offset\": {\"type\": \"integer\", \"minimum\": 0, \"default\": 0},\n                        \"order_by\": {\"type\": \"string\", \"description\": \"Order by field (e.g., 'created_at DESC')\"}\n                    }\n                }\n            }\n        )\n\n        # Update task\n        self.register_tool(\n            \"update_task\",\n            self.task_tool.update,\n            {\n                \"description\": \"Update a task\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"id\": {\"type\": \"integer\", \"description\": \"Task ID\"},\n                        \"title\": {\"type\": \"string\", \"description\": \"New title\"},\n                        \"description\": {\"type\": \"string\", \"description\": \"New description\"},\n                        \"priority\": {\"type\": \"string\", \"enum\": [\"low\", \"medium\", \"high\"]},\n                        \"status\": {\"type\": \"string\", \"enum\": [\"todo\", \"in_progress\", \"completed\"]},\n                        \"due_date\": {\"type\": \"string\", \"format\": \"date-time\"},\n                        \"tags\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}}\n                    },\n                    \"required\": [\"id\"]\n                }\n            }\n        )\n\n        # Delete task\n        self.register_tool(\n            \"delete_task\",\n            self.task_tool.delete,\n            {\n                \"description\": \"Delete a task\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"id\": {\"type\": \"integer\", \"description\": \"Task ID\"}\n                    },\n                    \"required\": [\"id\"]\n                }\n            }\n        )\n\n        # Bulk create\n        self.register_tool(\n            \"bulk_create_tasks\",\n            self.bulk_tool.bulk_create,\n            {\n                \"description\": \"Create multiple tasks at once\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"items\": {\n                            \"type\": \"array\",\n                            \"items\": {\n                                \"type\": \"object\",\n                                \"properties\": {\n                                    \"title\": {\"type\": \"string\"},\n                                    \"description\": {\"type\": \"string\"},\n                                    \"priority\": {\"type\": \"string\", \"enum\": [\"low\", \"medium\", \"high\"]},\n                                    \"tags\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}}\n                                },\n                                \"required\": [\"title\"]\n                            }\n                        }\n                    },\n                    \"required\": [\"items\"]\n                }\n            }\n        )\n\n        # Search tasks\n        self.register_tool(\n            \"search_tasks\",\n            self._search_tasks,\n            {\n                \"description\": \"Search tasks by text query\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"query\": {\"type\": \"string\", \"description\": \"Search query\"},\n                        \"limit\": {\"type\": \"integer\", \"minimum\": 1, \"maximum\": 50, \"default\": 20}\n                    },\n                    \"required\": [\"query\"]\n                }\n            }\n        )\n\n    async def _search_tasks(self, args: Dict[str, Any], context) -> Dict[str, Any]:\n        \"\"\"Search tasks by text\"\"\"\n        try:\n            query = args.get(\"query\", \"\")\n            limit = args.get(\"limit\", 20)\n\n            # Build search query\n            if isinstance(self.db_manager.backend, MongoBackend):\n                # MongoDB text search\n                search_query = {\n                    \"$text\": {\"$search\": query}\n                }\n                if context and not self.task_tool._validate_permissions(context, \"read_all\"):\n                    search_query[\"user_id\"] = context.user_id\n\n                results = await self.db_manager.find_many(\"tasks\", search_query, limit=limit)\n            else:\n                # PostgreSQL full-text search\n                sql = \"\"\"\n                SELECT * FROM tasks\n                WHERE to_tsvector('english', title || ' ' || COALESCE(description, '')) @@ plainto_tsquery('english', :query)\n                \"\"\"\n                params = {\"query\": query}\n\n                if context and not self.task_tool._validate_permissions(context, \"read_all\"):\n                    sql += \" AND user_id = :user_id\"\n                    params[\"user_id\"] = context.user_id\n\n                sql += f\" LIMIT {limit}\"\n\n                results = await self.db_manager.execute_query(sql, params)\n\n            return {\n                \"status\": \"success\",\n                \"entity\": \"task\",\n                \"data\": [self.task_tool._serialize_data(r) for r in results],\n                \"query\": query,\n                \"count\": len(results)\n            }\n\n        except Exception as e:\n            return {\n                \"status\": \"error\",\n                \"error\": str(e),\n                \"operation\": \"search_tasks\"\n            }\n\n# Main execution\nasync def main():\n    \"\"\"Start the Task MCP Server\"\"\"\n    server = TaskMCPServer(config)\n    await server.run()\n\nif __name__ == \"__main__\":\n    import asyncio\n    asyncio.run(main())\n```\n\n## 5. Testing Patterns\n\n```python\n# tests\u002Ftest_mcp_server.py\n\"\"\"\nGeneric MCP Server Testing Patterns\n\"\"\"\n\nimport pytest\nimport asyncio\nfrom typing import Dict, Any, List\nfrom unittest.mock import Mock, AsyncMock\n\nfrom mcp_server.core import BaseMCPServer, ServerConfig, RequestContext\nfrom mcp_server.database import DatabaseManager, create_database_manager\nfrom mcp_server.tools import CRUDBaseTool\n\nclass MockDatabaseManager:\n    \"\"\"Mock database manager for testing\"\"\"\n\n    def __init__(self):\n        self.data = {}\n        self.next_id = 1\n\n    async def create(self, table: str, data: Dict[str, Any]) -> int:\n        \"\"\"Mock create\"\"\"\n        entity_id = self.next_id\n        data['id'] = entity_id\n        self.data[f\"{table}:{entity_id}\"] = data\n        self.next_id += 1\n        return entity_id\n\n    async def find_one(self, table: str, query: Dict[str, Any]) -> Dict[str, Any]:\n        \"\"\"Mock find one\"\"\"\n        for key, value in self.data.items():\n            table_name, entity_id = key.split(\":\")\n            if table_name == table:\n                match = True\n                for k, v in query.items():\n                    if value.get(k) != v:\n                        match = False\n                        break\n                if match:\n                    return value\n        return None\n\n    async def find_many(self, table: str, query: Dict[str, Any], limit: int = None) -> List[Dict[str, Any]]:\n        \"\"\"Mock find many\"\"\"\n        results = []\n        for key, value in self.data.items():\n            table_name, entity_id = key.split(\":\")\n            if table_name == table:\n                match = True\n                for k, v in query.items():\n                    if value.get(k) != v:\n                        match = False\n                        break\n                if match:\n                    results.append(value)\n                    if limit and len(results) >= limit:\n                        break\n        return results\n\n    async def update(self, table: str, query: Dict[str, Any], data: Dict[str, Any]) -> int:\n        \"\"\"Mock update\"\"\"\n        count = 0\n        for key, value in self.data.items():\n            table_name, entity_id = key.split(\":\")\n            if table_name == table:\n                match = True\n                for k, v in query.items():\n                    if value.get(k) != v:\n                        match = False\n                        break\n                if match:\n                    value.update(data)\n                    count += 1\n        return count\n\n    async def delete(self, table: str, query: Dict[str, Any]) -> int:\n        \"\"\"Mock delete\"\"\"\n        to_delete = []\n        for key, value in self.data.items():\n            table_name, entity_id = key.split(\":\")\n            if table_name == table:\n                match = True\n                for k, v in query.items():\n                    if value.get(k) != v:\n                        match = False\n                        break\n                if match:\n                    to_delete.append(key)\n\n        for key in to_delete:\n            del self.data[key]\n\n        return len(to_delete)\n\n@pytest.fixture\nasync def mock_db():\n    \"\"\"Mock database manager fixture\"\"\"\n    return MockDatabaseManager()\n\n@pytest.fixture\ndef test_schema():\n    \"\"\"Test entity schema\"\"\"\n    return {\n        \"type\": \"object\",\n        \"properties\": {\n            \"name\": {\"type\": \"string\", \"minLength\": 1},\n            \"value\": {\"type\": \"integer\", \"minimum\": 0},\n            \"status\": {\"type\": \"string\", \"enum\": [\"active\", \"inactive\"]},\n            \"tags\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}}\n        },\n        \"required\": [\"name\"]\n    }\n\n@pytest.fixture\ndef crud_tool(mock_db, test_schema):\n    \"\"\"CRUD tool fixture\"\"\"\n    return CRUDBaseTool(\"test_entities\", mock_db, test_schema)\n\n@pytest.fixture\ndef user_context():\n    \"\"\"User context fixture\"\"\"\n    return RequestContext(user_id=\"test_user\", session_id=\"test_session\")\n\nclass TestCRUDTool:\n    \"\"\"Test CRUD tool operations\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_create_entity(self, crud_tool, user_context):\n        \"\"\"Test entity creation\"\"\"\n        args = {\n            \"name\": \"Test Entity\",\n            \"value\": 100,\n            \"status\": \"active\",\n            \"tags\": [\"test\", \"example\"]\n        }\n\n        result = await crud_tool.create(args, user_context)\n\n        assert result[\"status\"] == \"created\"\n        assert \"id\" in result\n        assert result[\"entity\"] == \"test_entity\"\n        assert \"timestamp\" in result\n\n    @pytest.mark.asyncio\n    async def test_create_missing_required(self, crud_tool, user_context):\n        \"\"\"Test creation with missing required field\"\"\"\n        args = {\"value\": 100}  # Missing 'name'\n\n        result = await crud_tool.create(args, user_context)\n\n        assert result[\"status\"] == \"error\"\n        assert \"Missing required field\" in result[\"error\"]\n\n    @pytest.mark.asyncio\n    async def test_get_entity(self, crud_tool, user_context):\n        \"\"\"Test getting an entity\"\"\"\n        # First create an entity\n        create_args = {\"name\": \"Test Get\"}\n        create_result = await crud_tool.create(create_args, user_context)\n        entity_id = create_result[\"id\"]\n\n        # Get the entity\n        get_args = {\"id\": entity_id}\n        result = await crud_tool.get(get_args, user_context)\n\n        assert result[\"status\"] == \"success\"\n        assert result[\"data\"][\"name\"] == \"Test Get\"\n        assert result[\"data\"][\"id\"] == entity_id\n\n    @pytest.mark.asyncio\n    async def test_get_not_found(self, crud_tool, user_context):\n        \"\"\"Test getting non-existent entity\"\"\"\n        args = {\"id\": 99999}\n        result = await crud_tool.get(args, user_context)\n\n        assert result[\"status\"] == \"not_found\"\n\n    @pytest.mark.asyncio\n    async def test_list_entities(self, crud_tool, user_context):\n        \"\"\"Test listing entities\"\"\"\n        # Create a few entities\n        for i in range(3):\n            args = {\"name\": f\"Entity {i}\"}\n            await crud_tool.create(args, user_context)\n\n        # List entities\n        result = await crud_tool.list({}, user_context)\n\n        assert result[\"status\"] == \"success\"\n        assert len(result[\"data\"]) == 3\n        assert \"pagination\" in result\n        assert result[\"pagination\"][\"total\"] == 3\n\n    @pytest.mark.asyncio\n    async def test_list_with_filters(self, crud_tool, user_context):\n        \"\"\"Test listing with filters\"\"\"\n        # Create entities with different statuses\n        await crud_tool.create({\"name\": \"Active 1\", \"status\": \"active\"}, user_context)\n        await crud_tool.create({\"name\": \"Inactive 1\", \"status\": \"inactive\"}, user_context)\n        await crud_tool.create({\"name\": \"Active 2\", \"status\": \"active\"}, user_context)\n\n        # Filter by status\n        result = await crud_tool.list(\n            {\"filters\": {\"status\": \"active\"}},\n            user_context\n        )\n\n        assert result[\"status\"] == \"success\"\n        assert all(entity[\"status\"] == \"active\" for entity in result[\"data\"])\n\n    @pytest.mark.asyncio\n    async def test_update_entity(self, crud_tool, user_context):\n        \"\"\"Test updating an entity\"\"\"\n        # Create entity\n        create_result = await crud_tool.create({\"name\": \"Original\"}, user_context)\n        entity_id = create_result[\"id\"]\n\n        # Update entity\n        update_args = {\n            \"id\": entity_id,\n            \"name\": \"Updated\",\n            \"value\": 200\n        }\n        result = await crud_tool.update(update_args, user_context)\n\n        assert result[\"status\"] == \"updated\"\n        assert result[\"affected_rows\"] == 1\n\n    @pytest.mark.asyncio\n    async def test_delete_entity(self, crud_tool, user_context):\n        \"\"\"Test deleting an entity\"\"\"\n        # Create entity\n        create_result = await crud_tool.create({\"name\": \"To Delete\"}, user_context)\n        entity_id = create_result[\"id\"]\n\n        # Delete entity\n        delete_args = {\"id\": entity_id}\n        result = await crud_tool.delete(delete_args, user_context)\n\n        assert result[\"status\"] == \"deleted\"\n        assert result[\"affected_rows\"] == 1\n\n        # Verify deletion\n        get_result = await crud_tool.get({\"id\": entity_id}, user_context)\n        assert get_result[\"status\"] == \"not_found\"\n\nclass TestMCPServer:\n    \"\"\"Test MCP Server functionality\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_server_initialization(self):\n        \"\"\"Test server initialization\"\"\"\n        config = ServerConfig(\n            name=\"test-server\",\n            description=\"Test MCP Server\"\n        )\n\n        server = BaseMCPServer(config)\n\n        assert server.config.name == \"test-server\"\n        assert server.server.name == \"test-server\"\n        assert len(server.tools) == 0\n\n    @pytest.mark.asyncio\n    async def test_tool_registration(self):\n        \"\"\"Test tool registration\"\"\"\n        config = ServerConfig(name=\"test-server\", description=\"Test\")\n        server = BaseMCPServer(config)\n\n        # Register a test tool\n        async def test_tool(args: Dict[str, Any]) -> Dict[str, Any]:\n            return {\"status\": \"success\", \"data\": args}\n\n        schema = {\n            \"description\": \"Test tool\",\n            \"inputSchema\": {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\"type\": \"string\"}\n                }\n            }\n        }\n\n        server.register_tool(\"test_tool\", test_tool, schema)\n\n        assert \"test_tool\" in server.tools\n        assert server.tools[\"test_tool\"][\"schema\"] == schema\n\n    @pytest.mark.asyncio\n    async def test_rate_limiting(self):\n        \"\"\"Test rate limiting functionality\"\"\"\n        # This would require mocking Redis or using a test instance\n        # Implementation would depend on your rate limiting strategy\n        pass\n\n    @pytest.mark.asyncio\n    async def test_caching(self):\n        \"\"\"Test caching functionality\"\"\"\n        # This would require mocking Redis or using a test instance\n        # Implementation would depend on your caching strategy\n        pass\n\n# Integration test example\nclass TestMCPServerIntegration:\n    \"\"\"Integration tests for MCP Server\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_full_crud_workflow(self):\n        \"\"\"Test full CRUD workflow through MCP interface\"\"\"\n        # Create mock server\n        config = ServerConfig(\n            name=\"test-integration\",\n            description=\"Integration test server\"\n        )\n\n        # Use in-memory database\n        mock_db = MockDatabaseManager()\n\n        # Create CRUD tool\n        test_schema = {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\"type\": \"string\"},\n                \"value\": {\"type\": \"integer\"}\n            },\n            \"required\": [\"name\"]\n        }\n\n        crud_tool = CRUDBaseTool(\"items\", mock_db, test_schema)\n\n        # Register tools\n        server = BaseMCPServer(config)\n        server.register_tool(\n            \"create_item\",\n            crud_tool.create,\n            {\n                \"description\": \"Create item\",\n                \"inputSchema\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"name\": {\"type\": \"string\"},\n                        \"value\": {\"type\": \"integer\"}\n                    },\n                    \"required\": [\"name\"]\n                }\n            }\n        )\n\n        # Test create\n        result = await server.call_tool(\n            \"create_item\",\n            {\"name\": \"Test Item\", \"value\": 123}\n        )\n\n        response = json.loads(result[0].text)\n        assert response[\"status\"] == \"created\"\n\n        # Test get (would need get_item tool)\n        # Test list\n        # Test update\n        # Test delete\n```\n\nThis generic MCP server skill provides a reusable foundation for building any MCP server, not just for todos. It includes:\n\n1. **Core Server Architecture** - Base class with rate limiting, caching, and error handling\n2. **Database Integration** - Support for PostgreSQL, MongoDB, and SQLAlchemy with async operations\n3. **Tool Patterns** - Generic CRUD and bulk operation patterns that work with any entity\n4. **Example Implementation** - Shows how to build a task management server using the generic patterns\n5. **Testing Framework** - Comprehensive testing patterns and mocks\n\n`★ Insight ─────────────────────────────────────`\nThe key architectural pattern here is the separation of concerns between:\n- The MCP protocol handling (BaseMCPServer)\n- The data access layer (DatabaseManager with multiple backends)\n- The business logic layer (CRUDBaseTool and BulkOperationTool)\n- The specific implementation (TaskMCPServer combining the components)\n\nThis makes the system highly reusable and maintainable. Any developer can quickly build a new MCP server by defining their entity schema and combining the generic tools.\n`─────────────────────────────────────────────────`",{"name":5,"license":14,"description":7},"master","08cc2532077058aa50e6e18f54695bc256c88152","skills\u002Fazeem-2\u002Fmcp-server","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub","https:\u002F\u002Fgithub.com\u002Fsuperhealth","java engineer","2026-04-06 22:07:23",{"source":8,"skillName":5,"commands":59,"prompt":69,"zipAvailable":70},[60,63,66],{"tool":61,"command":62},"npx","npx skills add superhealth\u002Fskills-hub --skill mcp-server",{"tool":64,"command":65},"bunx","bunx skills add superhealth\u002Fskills-hub --skill mcp-server",{"tool":67,"command":68},"pnpm","pnpm dlx skills add superhealth\u002Fskills-hub --skill mcp-server","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fazeem-2\u002Fmcp-server\u002FSKILL.md",true,[72],{"path":73,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":76,"sourceHtmlUrl":77},"skill-report.json","REFERENCE","参考文档",15707,"https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fazeem-2\u002Fmcp-server\u002Fskill-report.json",[79,108,135,148,164,186],{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":88,"publishedAt":46},"01M6MC9F3WHV8S8FZ2W4TRB0FE","vercel-react-best-practices","React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React\u002FNext.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fzhanlincui\u002Fvercel-react-best-practices\u002FSKILL.md",[85],{"categoryNo":86,"categoryName":87,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000009","前端开发",[89,90,40,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107],"react","vercel react best practices","vercel","react best practices","data fetching","code","triggers","pages","next","patterns","refactoring","data","Optimization","tasks","guidelines","react components","components","performance","writing",{"skillNo":109,"name":110,"nameZh":6,"description":111,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":118,"publishedAt":46},"01M6MB8KWE1Q5A5KERR7RFTQWP","vue-testing-best-practices","Use for Vue.js testing. Covers Vitest, Vue Test Utils, component testing, mocking, testing patterns, and Playwright for E2E testing.","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fvuejs-ai\u002Fvue-testing-best-practices\u002FSKILL.md",[114,117],{"categoryNo":115,"categoryName":116,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":86,"categoryName":87,"taxonomyType":20,"taxonomyTypeDesc":21},[119,120,121,40,122,123,124,125,126,127,128,98,129,130,30,131,132,133,134],"vue testing best practices","testing best practices","vue","testing","testing patterns","js","e2e","vitest","use","component","test","mocking","utils","e2e testing","github","playwright",{"skillNo":136,"name":137,"nameZh":6,"description":138,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":139,"categories":140,"keywords":142,"publishedAt":46},"01M6MB8GK06M6GA4KVYNDV1BZP","vue-router-best-practices","Vue Router 4 patterns, navigation guards, route params, and route-component lifecycle interactions.","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fvuejs-ai\u002Fvue-router-best-practices\u002FSKILL.md",[141],{"categoryNo":86,"categoryName":87,"taxonomyType":20,"taxonomyTypeDesc":21},[40,121,143,144,145,98,146,147,128,133],"router","vue router best practices","route","navigation","lifecycle",{"skillNo":149,"name":150,"nameZh":6,"description":151,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":152,"categories":153,"keywords":155,"publishedAt":46},"01M6MB8DQF21TZMQ9XC3745ERW","vue-pinia-best-practices","Pinia stores, state management patterns, store setup, and reactivity with stores.","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fvuejs-ai\u002Fvue-pinia-best-practices\u002FSKILL.md",[154],{"categoryNo":86,"categoryName":87,"taxonomyType":20,"taxonomyTypeDesc":21},[156,157,121,40,158,159,98,160,161,162,163,133],"vue pinia best practices","pinia","with","store","management","state","state management","setup",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":168,"categories":169,"keywords":177,"publishedAt":46},"01M6MB8A7MC08747J9TV4GWQ9A","vue-options-api-best-practices","Vue 3 Options API style (data(), methods, this context). Each reference shows Options API solution only.","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fvuejs-ai\u002Fvue-options-api-best-practices\u002FSKILL.md",[170,171,172],{"categoryNo":86,"categoryName":87,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":173,"categoryName":174,"taxonomyType":175,"taxonomyTypeDesc":176},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[121,178,179,180,40,181,182,183,184,100,133,185],"options","vue options api best practices","api","methods","reference","only","context","style",{"skillNo":187,"name":188,"nameZh":6,"description":189,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":190,"categories":191,"keywords":193,"publishedAt":46},"01M6MB85ZTQC24Q04X49MM4YXN","vue-development-guides","A collection of best practices and tips for developing applications using Vue.js. This skill MUST be apply when developing, refactoring or reviewing Vue.js or Nuxt projects.","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fvuejs-ai\u002Fvue-development-guides\u002FSKILL.md",[192],{"categoryNo":86,"categoryName":87,"taxonomyType":20,"taxonomyTypeDesc":21},[42,121,194,195,133,196,197,30,198,199,200,124,99,201,202,40],"guides","vue development guides","tips","apply","project","nuxt","projects","collection","applications"]