Skip to content

Commit 243d1ce

Browse files
committed
feat: add memobase mcp
1 parent 6d75b00 commit 243d1ce

File tree

10 files changed

+900
-0
lines changed

10 files changed

+900
-0
lines changed

src/mcp/.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.env

src/mcp/.env.example

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# The transport for the MCP server - either 'sse' or 'stdio' (defaults to SSE if left empty)
2+
TRANSPORT=
3+
4+
# Host to bind to if using sse as the transport (leave empty if using stdio)
5+
HOST=0.0.0.0
6+
7+
# Port to listen on if using sse as the transport (leave empty if using stdio)
8+
PORT=8050
9+
10+
# Memobase API Key
11+
MEMOBASE_API_KEY=
12+
13+
# Memobase Base URL
14+
MEMOBASE_BASE_URL=

src/mcp/.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

src/mcp/.gitignore

Whitespace-only changes.

src/mcp/Dockerfile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
FROM python:3.12-slim
2+
3+
ARG PORT=8050
4+
5+
WORKDIR /app
6+
7+
# Install uv
8+
RUN pip install uv
9+
10+
# Copy the MCP server files
11+
COPY . .
12+
13+
# Install packages
14+
RUN python -m venv .venv
15+
RUN uv pip install -e .
16+
17+
EXPOSE ${PORT}
18+
19+
# Command to run the MCP server
20+
CMD ["uv", "run", "src/main.py"]

src/mcp/README.md

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
<h1 align="center">Memobase-MCP: Long-Term Memory for AI Agents</h1>
2+
3+
> This project is forked from [coleam00/mcp-mem0](https://github.com/coleam00/mcp-mem0)
4+
5+
A template implementation of the [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server integrated with [Memobase](https://memobase.io) for providing AI agents with persistent memory capabilities.
6+
7+
Use this as a reference point to build your MCP servers yourself, or give this as an example to an AI coding assistant and tell it to follow this example for structure and code correctness!
8+
9+
To run this mcp, you need to have your own Memobase backend:
10+
11+
- You can [deploy](../server/readme.md) a local one
12+
- Or use [free credits](https://www.memobase.io/en) of Memobase Cloud
13+
14+
You should have:
15+
16+
- A project url. (local: `http://localhost:8019` , cloud `https://api.memobase.dev`)
17+
- A project token. (local: `secret` , cloud `sk-proj-xxxxxx`)
18+
19+
## Overview
20+
21+
This project demonstrates how to build an MCP server that enables AI agents to store, retrieve, and search memories using semantic search. It serves as a practical template for creating your own MCP servers, simply using Memobase and a practical example.
22+
23+
The implementation follows the best practices laid out by Anthropic for building MCP servers, allowing seamless integration with any MCP-compatible client.
24+
25+
## Features
26+
27+
The server provides three essential memory management tools:
28+
29+
1. **`save_memory`**: Store any information in long-term memory with semantic indexing
30+
2. **`get_user_profiles`**: Retrieve complete user profiles
31+
3. **`search_memories`**: Find relevant context for a given query
32+
33+
## Prerequisites
34+
- Python 3.11+
35+
36+
## Installation
37+
38+
### Using uv
39+
40+
1. Install uv if you don't have it:
41+
```bash
42+
pip install uv
43+
```
44+
45+
2. Clone the repository:
46+
```bash
47+
git clone https://github.com/memodb-io/memobase
48+
```
49+
50+
3. Navigate to the project directory:
51+
```bash
52+
cd memobase/src/mcp
53+
```
54+
55+
3. Install dependencies:
56+
```bash
57+
uv pip install -e .
58+
```
59+
60+
4. Create a `.env` file based on `.env.example`:
61+
```bash
62+
cp .env.example .env
63+
```
64+
65+
5. Configure your environment variables in the `.env` file (see Configuration section)
66+
67+
### Using Docker (Recommended)
68+
69+
1. Build the Docker image:
70+
```bash
71+
docker build -t memobase-mcp --build-arg PORT=8050 .
72+
```
73+
74+
2. Create a `.env` file based on `.env.example` and configure your environment variables
75+
76+
## Configuration
77+
78+
The following environment variables can be configured in your `.env` file:
79+
80+
| Variable | Description | Example |
81+
|----------|-------------|----------|
82+
| `TRANSPORT` | Transport protocol (sse or stdio) | `sse` |
83+
| `HOST` | Host to bind to when using SSE transport | `0.0.0.0` |
84+
| `PORT` | Port to listen on when using SSE transport | `8050` |
85+
| `MEMOBASE_API_KEY` | Memobase API key | `secret` |
86+
| `MEMOBASE_BASE_URL` | Memobase base URL | `http://localhost:8019` |
87+
88+
## Running the Server
89+
90+
### Using uv
91+
92+
#### SSE Transport
93+
94+
```bash
95+
# Set TRANSPORT=sse in .env then:
96+
uv run src/main.py
97+
```
98+
99+
The MCP server will essentially be run as an API endpoint that you can then connect to with config shown below.
100+
101+
#### Stdio Transport
102+
103+
With stdio, the MCP client iself can spin up the MCP server, so nothing to run at this point.
104+
105+
### Using Docker
106+
107+
#### SSE Transport
108+
109+
```bash
110+
docker run --env-file .env -p:8050:8050 memobase-mcp
111+
```
112+
113+
The MCP server will essentially be run as an API endpoint within the container that you can then connect to with config shown below.
114+
115+
#### Stdio Transport
116+
117+
With stdio, the MCP client iself can spin up the MCP server container, so nothing to run at this point.
118+
119+
## Integration with MCP Clients
120+
121+
### SSE Configuration
122+
123+
Once you have the server running with SSE transport, you can connect to it using this configuration:
124+
125+
```json
126+
{
127+
"mcpServers": {
128+
"memobase": {
129+
"transport": "sse",
130+
"url": "http://localhost:8050/sse"
131+
}
132+
}
133+
}
134+
```
135+
136+
> **Note for Windsurf users**: Use `serverUrl` instead of `url` in your configuration:
137+
> ```json
138+
> {
139+
> "mcpServers": {
140+
> "memobase": {
141+
> "transport": "sse",
142+
> "serverUrl": "http://localhost:8050/sse"
143+
> }
144+
> }
145+
> }
146+
> ```
147+
148+
> **Note for n8n users**: Use host.docker.internal instead of localhost since n8n has to reach outside of it's own container to the host machine:
149+
>
150+
> So the full URL in the MCP node would be: http://host.docker.internal:8050/sse
151+
152+
Make sure to update the port if you are using a value other than the default 8050.
153+
154+
### Python with Stdio Configuration
155+
156+
Add this server to your MCP configuration for Claude Desktop, Windsurf, or any other MCP client:
157+
158+
```json
159+
{
160+
"mcpServers": {
161+
"memobase": {
162+
"command": "your/path/to/mcp/.venv/Scripts/python.exe",
163+
"args": ["your/path/to/mcp/src/main.py"],
164+
"env": {
165+
"TRANSPORT": "stdio",
166+
"MEMOBASE_API_KEY": "YOUR-API-KEY",
167+
"MEMOBASE_BASE_URL": "YOUR-MEMOBASE-URL",
168+
}
169+
}
170+
}
171+
}
172+
```
173+
174+
### Docker with Stdio Configuration
175+
176+
```json
177+
{
178+
"mcpServers": {
179+
"memobase": {
180+
"command": "docker",
181+
"args": ["run", "--rm", "-i",
182+
"-e", "TRANSPORT",
183+
"-e", "MEMOBASE_API_KEY",
184+
"-e", "MEMOBASE_BASE_URL",
185+
"memobase-mcp"],
186+
"env": {
187+
"TRANSPORT": "stdio",
188+
"MEMOBASE_API_KEY": "YOUR-API-KEY",
189+
"MEMOBASE_BASE_URL": "https://api.memobase.io",
190+
}
191+
}
192+
}
193+
}
194+
```
195+
196+
## Building Your Own Server
197+
198+
This template provides a foundation for building more complex MCP servers. To build your own:
199+
200+
1. Add your own tools by creating methods with the `@mcp.tool()` decorator
201+
2. Create your own lifespan function to add your own dependencies (clients, database connections, etc.)
202+
3. Modify the `utils.py` file for any helper functions you need for your MCP server
203+
4. Feel free to add prompts and resources as well with `@mcp.resource()` and `@mcp.prompt()`

src/mcp/pyproject.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[project]
2+
name = "memobase-mcp"
3+
version = "0.1.0"
4+
description = "MCP server for integrating long term memory into AI agents with Memobase"
5+
readme = "README.md"
6+
requires-python = ">=3.11"
7+
dependencies = ["httpx>=0.28.1", "mcp[cli]>=1.3.0", "memobase"]

src/mcp/src/main.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
from mcp.server.fastmcp import FastMCP, Context
2+
from contextlib import asynccontextmanager
3+
from collections.abc import AsyncIterator
4+
from dataclasses import dataclass
5+
from dotenv import load_dotenv
6+
from memobase import AsyncMemoBaseClient, ChatBlob
7+
from memobase.utils import string_to_uuid
8+
import asyncio
9+
import json
10+
import os
11+
12+
from utils import get_memobase_client
13+
14+
load_dotenv()
15+
16+
# Default user ID for memory operations
17+
DEFAULT_USER_ID = string_to_uuid("user")
18+
19+
20+
# Create a dataclass for our application context
21+
@dataclass
22+
class MemobaseContext:
23+
"""Context for the Memobase MCP server."""
24+
25+
memobase_client: AsyncMemoBaseClient
26+
27+
28+
@asynccontextmanager
29+
async def memobase_lifespan(server: FastMCP) -> AsyncIterator[MemobaseContext]:
30+
"""
31+
Manages the Memobase client lifecycle.
32+
33+
Args:
34+
server: The FastMCP server instance
35+
36+
Yields:
37+
MemobaseContext: The context containing the Memobase client
38+
"""
39+
# Create and return the Memory client with the helper function in utils.py
40+
memobase_client = get_memobase_client()
41+
assert await memobase_client.ping(), "Failed to connect to Memobase"
42+
print("Memobase client connected")
43+
try:
44+
yield MemobaseContext(memobase_client=memobase_client)
45+
finally:
46+
# No explicit cleanup needed for the Memobase client
47+
pass
48+
49+
50+
# Initialize FastMCP server with the Memobase client as context
51+
mcp = FastMCP(
52+
"memobase-mcp",
53+
description="MCP server for long term memory storage and retrieval with Memobase",
54+
lifespan=memobase_lifespan,
55+
host=os.getenv("HOST", "0.0.0.0"),
56+
port=os.getenv("PORT", 8050),
57+
)
58+
59+
60+
@mcp.tool()
61+
async def save_memory(ctx: Context, text: str) -> str:
62+
"""Save information to your long-term memory.
63+
64+
This tool is designed to store any type of information that might be useful in the future.
65+
The content will be processed and indexed for later retrieval through semantic search.
66+
67+
Args:
68+
ctx: The MCP server provided context which includes the Memobase client
69+
text: The content to store in memory, including any relevant details and context
70+
"""
71+
try:
72+
memobase_client: AsyncMemoBaseClient = (
73+
ctx.request_context.lifespan_context.memobase_client
74+
)
75+
messages = [{"role": "user", "content": text}]
76+
u = await memobase_client.get_or_create_user(DEFAULT_USER_ID)
77+
await u.insert(ChatBlob(messages=messages))
78+
await u.flush()
79+
return f"Successfully saved memory: {text[:100]}..."
80+
except Exception as e:
81+
return f"Error saving memory: {str(e)}"
82+
83+
84+
@mcp.tool()
85+
async def get_user_profiles(ctx: Context) -> str:
86+
"""Get full user profiles.
87+
88+
Call this tool when user asks for a summary of complete image of itself.
89+
90+
Args:
91+
ctx: The MCP server provided context which includes the Memobase client
92+
93+
Returns:
94+
A list of user profiles with topic, subtopic and content.
95+
"""
96+
try:
97+
memobase_client: AsyncMemoBaseClient = (
98+
ctx.request_context.lifespan_context.memobase_client
99+
)
100+
u = await memobase_client.get_or_create_user(DEFAULT_USER_ID)
101+
ps = await u.profile()
102+
return "\n".join([f"- {p.describe}" for p in ps])
103+
except Exception as e:
104+
return f"Error retrieving memories: {str(e)}"
105+
106+
107+
@mcp.tool()
108+
async def search_memories(ctx: Context, query: str, max_length: int = 1000) -> str:
109+
"""Search user memories
110+
111+
Call this tool when user ask for recall some personal information.
112+
113+
Args:
114+
ctx: The MCP server provided context which includes the Memobase client
115+
query: Search query string describing what you're looking for. Can be natural language.
116+
max_length: Maximum content length of the returned context.
117+
"""
118+
try:
119+
memobase_client: AsyncMemoBaseClient = (
120+
ctx.request_context.lifespan_context.memobase_client
121+
)
122+
u = await memobase_client.get_or_create_user(DEFAULT_USER_ID)
123+
ps = await u.context(
124+
chats=[{"role": "user", "content": query}], max_token_size=max_length
125+
)
126+
return ps
127+
except Exception as e:
128+
return f"Error searching memories: {str(e)}"
129+
130+
131+
async def main():
132+
transport = os.getenv("TRANSPORT", "sse")
133+
if transport == "sse":
134+
# Run the MCP server with sse transport
135+
await mcp.run_sse_async()
136+
else:
137+
# Run the MCP server with stdio transport
138+
await mcp.run_stdio_async()
139+
140+
141+
if __name__ == "__main__":
142+
asyncio.run(main())

0 commit comments

Comments
 (0)