Implementation Summary:
- REST API with FastAPI (complete CRUD operations)
- MCP Server with Python MCP SDK (7 tools)
- Supabase migrations (pgvector setup)
- Docker Compose orchestration
- Mintlify documentation site
- Environment configuration
- Shared config module
REST API Features:
- POST /v1/memories/ - Add memory
- GET /v1/memories/search - Semantic search
- GET /v1/memories/{id} - Get memory
- GET /v1/memories/user/{user_id} - User memories
- PATCH /v1/memories/{id} - Update memory
- DELETE /v1/memories/{id} - Delete memory
- GET /v1/health - Health check
- GET /v1/stats - Statistics
- Bearer token authentication
- OpenAPI documentation
MCP Server Tools:
- add_memory - Add from messages
- search_memories - Semantic search
- get_memory - Retrieve by ID
- get_all_memories - List all
- update_memory - Update content
- delete_memory - Delete by ID
- delete_all_memories - Bulk delete
Infrastructure:
- Neo4j 5.26 with APOC/GDS
- Supabase pgvector integration
- Docker network: localai
- Health checks and monitoring
- Structured logging
Documentation:
- Introduction page
- Quickstart guide
- Architecture deep dive
- Mintlify configuration
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
166 lines
5.0 KiB
Python
166 lines
5.0 KiB
Python
"""
|
|
T6 Mem0 v2 MCP Server
|
|
Model Context Protocol server for memory operations
|
|
"""
|
|
|
|
import logging
|
|
import sys
|
|
import asyncio
|
|
from mcp.server import Server
|
|
from mcp.server.stdio import stdio_server
|
|
from mcp.types import (
|
|
Resource,
|
|
Tool,
|
|
TextContent,
|
|
ImageContent,
|
|
EmbeddedResource
|
|
)
|
|
from mem0 import Memory
|
|
|
|
from config import mem0_config, settings
|
|
from mcp_server.tools import MemoryTools
|
|
|
|
# Configure logging
|
|
logging.basicConfig(
|
|
level=getattr(logging, settings.log_level.upper()),
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
handlers=[logging.StreamHandler(sys.stderr)] # MCP uses stderr for logs
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class T6Mem0Server:
|
|
"""T6 Mem0 v2 MCP Server"""
|
|
|
|
def __init__(self):
|
|
"""Initialize MCP server"""
|
|
self.server = Server("t6-mem0-v2")
|
|
self.memory: Memory | None = None
|
|
self.tools: MemoryTools | None = None
|
|
|
|
# Setup handlers
|
|
self.setup_handlers()
|
|
|
|
def setup_handlers(self):
|
|
"""Setup MCP server handlers"""
|
|
|
|
@self.server.list_resources()
|
|
async def list_resources() -> list[Resource]:
|
|
"""
|
|
List available resources (for future extension)
|
|
"""
|
|
return []
|
|
|
|
@self.server.read_resource()
|
|
async def read_resource(uri: str) -> str:
|
|
"""
|
|
Read resource by URI (for future extension)
|
|
"""
|
|
logger.warning(f"Resource read not implemented: {uri}")
|
|
return ""
|
|
|
|
@self.server.list_tools()
|
|
async def list_tools() -> list[Tool]:
|
|
"""List available memory tools"""
|
|
logger.info("Listing tools")
|
|
if not self.tools:
|
|
raise RuntimeError("Tools not initialized")
|
|
return self.tools.get_tool_definitions()
|
|
|
|
@self.server.call_tool()
|
|
async def call_tool(name: str, arguments: dict) -> list[TextContent | ImageContent | EmbeddedResource]:
|
|
"""
|
|
Handle tool calls
|
|
|
|
Args:
|
|
name: Tool name
|
|
arguments: Tool arguments
|
|
|
|
Returns:
|
|
Tool response
|
|
"""
|
|
logger.info(f"Tool called: {name}")
|
|
logger.debug(f"Arguments: {arguments}")
|
|
|
|
if not self.tools:
|
|
raise RuntimeError("Tools not initialized")
|
|
|
|
# Route to appropriate handler
|
|
handlers = {
|
|
"add_memory": self.tools.handle_add_memory,
|
|
"search_memories": self.tools.handle_search_memories,
|
|
"get_memory": self.tools.handle_get_memory,
|
|
"get_all_memories": self.tools.handle_get_all_memories,
|
|
"update_memory": self.tools.handle_update_memory,
|
|
"delete_memory": self.tools.handle_delete_memory,
|
|
"delete_all_memories": self.tools.handle_delete_all_memories,
|
|
}
|
|
|
|
handler = handlers.get(name)
|
|
if not handler:
|
|
logger.error(f"Unknown tool: {name}")
|
|
return [TextContent(type="text", text=f"Error: Unknown tool '{name}'")]
|
|
|
|
try:
|
|
return await handler(arguments)
|
|
except Exception as e:
|
|
logger.error(f"Tool execution failed: {e}", exc_info=True)
|
|
return [TextContent(type="text", text=f"Error executing tool: {str(e)}")]
|
|
|
|
async def initialize(self):
|
|
"""Initialize memory service"""
|
|
logger.info("Initializing T6 Mem0 v2 MCP Server")
|
|
logger.info(f"Environment: {settings.environment}")
|
|
|
|
try:
|
|
# Initialize Mem0
|
|
logger.info("Initializing Mem0...")
|
|
self.memory = Memory.from_config(config_dict=mem0_config)
|
|
logger.info("Mem0 initialized successfully")
|
|
|
|
# Initialize tools
|
|
self.tools = MemoryTools(self.memory)
|
|
logger.info("Tools initialized successfully")
|
|
|
|
logger.info("T6 Mem0 v2 MCP Server ready")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to initialize server: {e}", exc_info=True)
|
|
raise
|
|
|
|
async def run(self):
|
|
"""Run the MCP server"""
|
|
try:
|
|
# Initialize before running
|
|
await self.initialize()
|
|
|
|
# Run server with stdio transport
|
|
logger.info("Starting MCP server with stdio transport")
|
|
async with stdio_server() as (read_stream, write_stream):
|
|
await self.server.run(
|
|
read_stream,
|
|
write_stream,
|
|
self.server.create_initialization_options()
|
|
)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Server error: {e}", exc_info=True)
|
|
raise
|
|
|
|
|
|
async def main():
|
|
"""Main entry point"""
|
|
try:
|
|
server = T6Mem0Server()
|
|
await server.run()
|
|
except KeyboardInterrupt:
|
|
logger.info("Server stopped by user")
|
|
except Exception as e:
|
|
logger.error(f"Fatal error: {e}", exc_info=True)
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|