mem0 Memory System
"""
API endpoints for the mem0 MCP server
"""
from fastapi import FastAPI, HTTPException, Depends
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse
from typing import Dict, Any, Optional
from memory_provider import MemoryProvider
from auto_memory import AutoMemory
from models import (
MemoryConfig, MemoryContent, SearchQuery, ChatMessage,
MemoryID, MemoryResponse, SearchResponse, ChatResponse,
StatusResponse, MemoryData
)
# Create FastAPI app
app = FastAPI(
title="mem0 MCP Server",
description="Memory Capabilities Provider (MCP) server for mem0",
version="1.0.0",
)
# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Global memory provider instance
memory_provider = None
# Global auto memory instance
auto_memory = None
@app.post("/configure", response_model=StatusResponse)
async def configure_memory(config: MemoryConfig):
"""Configure the memory provider"""
global memory_provider, auto_memory
try:
# Initialize memory provider
memory_provider = MemoryProvider(
provider=config.provider,
embedding_provider=config.embedding_provider,
api_key=config.api_key,
model=config.model,
embedding_model=config.embedding_model,
data_dir=config.data_dir,
)
# Initialize auto memory
auto_memory = AutoMemory(memory_provider)
return StatusResponse(
success=True,
message=f"Memory provider configured with {config.provider}"
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/memory/add", response_model=MemoryResponse)
async def add_memory(memory: MemoryContent):
"""Add a memory"""
global memory_provider
if memory_provider is None:
raise HTTPException(status_code=500, detail="Memory provider not configured")
try:
# Add memory
memory_id = memory_provider.store(
content=memory.content,
metadata=memory.metadata
)
return MemoryResponse(memory_id=memory_id)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/memory/search", response_model=SearchResponse)
async def search_memories(query: SearchQuery):
"""Search for memories"""
global memory_provider
if memory_provider is None:
raise HTTPException(status_code=500, detail="Memory provider not configured")
try:
# Search memories
results = memory_provider.retrieve(
query=query.query,
limit=query.limit
)
# Format results
formatted_results = []
for result in results:
formatted_results.append({
"memory_id": result.get("id", "unknown"),
"content": result.get("content", ""),
"metadata": result.get("metadata", {}),
"score": result.get("score", 0.0)
})
return SearchResponse(
success=True,
results=formatted_results,
memory_id=None
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/memory/{memory_id}", response_model=MemoryData)
async def get_memory(
memory_id: str,
):
"""Get a memory by ID"""
global memory_provider
if memory_provider is None:
raise HTTPException(status_code=500, detail="Memory provider not configured")
try:
memory = memory_provider.get(memory_id)
if not memory:
raise HTTPException(status_code=404, detail=f"Memory {memory_id} not found")
# Ensure we have the required fields
if "content" not in memory:
memory["content"] = ""
if "metadata" not in memory:
memory["metadata"] = {}
return MemoryData(
id=memory_id,
content=memory.get("content", ""),
metadata=memory.get("metadata", {})
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.delete("/memory/{memory_id}", response_model=StatusResponse)
async def delete_memory(
memory_id: str,
):
"""Delete a memory by ID"""
global memory_provider
if memory_provider is None:
raise HTTPException(status_code=500, detail="Memory provider not configured")
try:
memory_provider.delete(memory_id)
return StatusResponse(
success=True,
message=f"Memory {memory_id} deleted"
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.delete("/memories", response_model=StatusResponse)
async def clear_memories():
"""Clear all memories"""
global memory_provider
if memory_provider is None:
raise HTTPException(status_code=500, detail="Memory provider not configured")
try:
memory_provider.clear()
return StatusResponse(
success=True,
message="All memories cleared"
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/health", response_model=StatusResponse)
async def health_check():
"""Health check endpoint"""
return StatusResponse(
success=True,
message="mem0 MCP server is running"
)
@app.get("/providers", response_model=Dict[str, Any])
async def list_providers():
"""List available providers"""
return {
"llm_providers": MemoryProvider.PROVIDERS,
"embedding_providers": MemoryProvider.EMBEDDING_PROVIDERS
}
HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
<title>mem0 MCP Server</title>
<style>
body {{
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
line-height: 1.6;
color: #333;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}}
h1 {{
color: #2563eb;
border-bottom: 2px solid #e5e7eb;
padding-bottom: 10px;
}}
h2 {{
color: #4b5563;
margin-top: 30px;
}}
.endpoint {{
background-color: #f9fafb;
border-left: 4px solid #2563eb;
padding: 15px;
margin: 15px 0;
border-radius: 0 5px 5px 0;
}}
.method {{
font-weight: bold;
color: #2563eb;
}}
.path {{
font-family: monospace;
background-color: #e5e7eb;
padding: 2px 5px;
border-radius: 3px;
}}
.description {{
margin-top: 10px;
}}
pre {{
background-color: #f3f4f6;
padding: 10px;
border-radius: 5px;
overflow-x: auto;
}}
code {{
font-family: monospace;
}}
.status {{
display: inline-block;
padding: 5px 10px;
border-radius: 15px;
font-size: 0.8em;
margin-top: 10px;
}}
.status.running {{
background-color: #dcfce7;
color: #166534;
}}
.status.not-configured {{
background-color: #fee2e2;
color: #991b1b;
}}
footer {{
margin-top: 50px;
text-align: center;
color: #6b7280;
font-size: 0.9em;
}}
</style>
</head>
<body>
<h1>✨ mem0 MCP Server</h1>
<div class="status {status_class}">
Status: {status}
</div>
<h2>API Endpoints</h2>
<div class="endpoint">
<div><span class="method">POST</span> <span class="path">/configure</span></div>
<div class="description">Configure the memory provider with specified settings.</div>
<pre><code>{{
"provider": "openai",
"embedding_provider": "openai",
"api_key": "your-api-key",
"model": "gpt-4o",
"embedding_model": "text-embedding-3-small",
"data_dir": "./memory_data"
}}</code></pre>
</div>
<div class="endpoint">
<div><span class="method">POST</span> <span class="path">/memory/add</span></div>
<div class="description">Store a memory with optional metadata.</div>
<pre><code>{{
"content": "This is a memory to be stored",
"metadata": {{
"source": "user",
"importance": "high"
}}
}}</code></pre>
</div>
<div class="endpoint">
<div><span class="method">POST</span> <span class="path">/memory/search</span></div>
<div class="description">Retrieve memories based on a query.</div>
<pre><code>{{
"query": "What do you remember about...",
"limit": 5
}}</code></pre>
</div>
<div class="endpoint">
<div><span class="method">GET</span> <span class="path">/memory/{{memory_id}}</span></div>
<div class="description">Get a memory by ID.</div>
</div>
<div class="endpoint">
<div><span class="method">DELETE</span> <span class="path">/memory/{{memory_id}}</span></div>
<div class="description">Delete a memory by ID.</div>
</div>
<div class="endpoint">
<div><span class="method">DELETE</span> <span class="path">/memories</span></div>
<div class="description">Clear all memories for a user or all users.</div>
</div>
<h2>Environment Configuration</h2>
<p>The server can be configured using environment variables:</p>
<ul>
<li><code>MEM0_PROVIDER</code> - Default LLM provider (openai, anthropic, google, ollama, etc.)</li>
<li><code>MEM0_EMBEDDING_PROVIDER</code> - Default embedding provider (openai, huggingface, ollama)</li>
<li><code>MEM0_DATA_DIR</code> - Directory to store memory data</li>
<li><code>OPENAI_API_KEY</code> - API key for OpenAI</li>
<li><code>ANTHROPIC_API_KEY</code> - API key for Anthropic</li>
<li><code>GOOGLE_API_KEY</code> - API key for Google</li>
<li><code>OLLAMA_BASE_URL</code> - Base URL for Ollama (default: http://localhost:11434)</li>
</ul>
<footer>
Made with ❤️ by Pink Pixel
</footer>
</body>
</html>
"""
@app.get("/", response_class=HTMLResponse)
async def root():
"""Root endpoint that displays API documentation"""
status = "Running" if memory_provider is not None else "Not Configured"
status_class = "running" if memory_provider is not None else "not-configured"
return HTML_TEMPLATE.format(
status=status,
status_class=status_class
)