agent-memory
Standalone memory microservice that converts completed agent sessions into long-term memory and exposes retrieval through an MCP tool interface, enabling agents to search their past interactions.
README
agent-memory
Standalone memory microservice for agent memory management. Converts completed agent sessions into long-term memory and exposes retrieval through an MCP tool interface.
All runnable code must remain inside sandbox/agent-memory/.
Requirements
- Python 3.12+
- Qdrant (local Docker container)
- Ollama (local, with models pulled)
- Docker (for Qdrant)
Quick Install
pip install -e ".[dev]"
Copy and configure the environment file:
copy .env.example .env
Dependencies At A Glance
| Dependency | Default Port | Purpose |
|---|---|---|
| Qdrant | 7333 |
Vector database (via Docker) |
| Ollama | 11434 |
LLM extraction + embedding |
| Service | 8000 |
agent_memory_service FastAPI |
| MCP Server | stdio | agent_memory_mcp (no TCP port) |
| Sleep CLI | n/a | One-shot operator tool |
Architecture Boundaries
The system has four separate package roots with clear ownership:
| Package | Entrypoint | Responsibility |
|---|---|---|
agent_memory_service |
python -m agent_memory_service |
HTTP API, persistence, retrieval |
agent_memory_mcp |
python -m agent_memory_mcp |
MCP tool server (long-lived) |
agent_memory_sleep |
python -m agent_memory_sleep |
Interactive operator CLI (one-shot) |
| Config layer | src/agent_memory_service/ |
Typed YAML loading, shared by all |
Hard boundary rule: neither agent_memory_mcp nor agent_memory_sleep
talk to Qdrant or Mem0 directly. All memory operations go through
agent_memory_service HTTP endpoints.
Startup Order
Start the stack in this exact order. Each step depends on the previous one.
1. Start Qdrant (Docker)
docker run --name agent-memory-qdrant -p 7333:6333 -p 7334:6334 -d qdrant/qdrant
Verify:
curl http://localhost:7333/
Windows note: host port 6333 is reserved (TCP range 6315-6414),
so config/memory.yaml maps host 7333 to container 6333.
If the container already exists but is stopped:
docker start agent-memory-qdrant
2. Verify Ollama models
ollama list
Required models (pull if missing):
ollama pull qwen2.5:3b
ollama pull qwen2.5:7b
ollama pull nomic-embed-text
3. Start agent_memory_service
python -m agent_memory_service
Verify:
curl http://localhost:8000/health
curl http://localhost:8000/up-status
/up-status reports component-by-component status for config loading,
Qdrant, Mem0 OSS, and the provider layer. All four must be ok before
proceeding.
4. Start agent_memory_mcp (separate terminal)
set AGENT_MEMORY_AGENT_ID=default
python -m agent_memory_mcp
The MCP server communicates over stdio. It refuses to start if the
service is unreachable at http://localhost:8000/health.
5. Run agent_memory_sleep (operator-initiated, one-shot)
python -m agent_memory_sleep
Follow the interactive prompts to:
- Select source runtime (opencode / codex)
- Enter agent ID and session export path
- Choose dream source (inline / profile / file)
- Select mode (dry_run to preview, commit to persist)
The sleep tool is one-shot — it exits after processing one session.
Configuration
Format: YAML (frozen baseline — do not substitute JSON or TOML).
Config directory: config/
Frozen config filenames:
| File | Purpose |
|---|---|
config/agents.yaml |
Agent identity and behaviour |
config/providers.yaml |
Model provider and runtime wiring |
config/memory.yaml |
Memory store and persistence |
Typed loading lives under src/agent_memory_service/.
All config is validated at service startup — malformed files prevent boot.
Environment overrides:
| Variable | Config Field | Default |
|---|---|---|
AGENT_MEMORY_CONFIG_DIR |
Config directory path | ./config |
AGENT_MEMORY_AGENT_ID |
Agent ID for MCP server | default (fallback) |
AGENT_MEMORY_SERVICE_URL |
Service URL for MCP server | http://localhost:8000 |
agents_hub Integration
agents_hub consumes agent_memory_mcp as an MCP server over stdio —
it never calls the service endpoints or Qdrant directly.
MCP Client Configuration
Add agent_memory_mcp to your MCP client's server list as a stdio transport:
{
"mcpServers": {
"agent_memory": {
"command": "python",
"args": ["-m", "agent_memory_mcp"],
"env": {
"AGENT_MEMORY_AGENT_ID": "default",
"AGENT_MEMORY_CONFIG_DIR": "./sandbox/agent-memory/config"
}
}
}
}
The MCP server exposes exactly one tool:
| Tool | Arguments | Returns |
|---|---|---|
memory_search |
query (required) |
Formatted memory results with scores |
limit (optional) |
scoped to the configured agent only |
Blocked arguments: agent_id, user_id, user, provider —
the MCP server rejects these immediately. Agent identity is resolved
from host context, not from tool arguments.
Integration contract:
agents_hubmust not usePOST /retrieveorPOST /processdirectlyagents_hubmust not connect to Qdrant or Mem0agents_hubmust not setagent_idinmemory_searcharguments- The MCP server is the only retrieval surface exposed to external clients
Sleep Operator Guide
agent_memory_sleep is an interactive one-shot CLI that processes a
completed agent session into long-term memory.
Step-by-step walkthrough
- Select runtime — choose
opencodeorcodexas session source - Enter agent ID — defaults to
"default", must matchconfig/agents.yaml - Provide session path — absolute or relative path to the session export file
- Choose dream source:
inline— paste a JSON dream rule directlyprofile— select a named profile fromconfig/dream_profiles.yamlfile— provide an absolute path to a YAML/JSON dream file
- Select mode:
dry_run— extract and validate candidates without persistencecommit— persist memory records through Mem0 / Qdrant
Example session
$ python -m agent_memory_sleep
? Select source runtime: opencode
? Agent ID: default
? Path to opencode session export: tests/fixtures/opencode/session_sanitized.json
? Dream source: profile
? Dream profile name: default
? Mode: dry_run
╭────────────────────────────────────────╮
│ Session: ses_124a1da54ffeQ2cp0LkbaiADWt │
│ Agent: default │
│ Source: opencode │
│ Messages: 6 │
╰────────────────────────────────────────╯
Calling http://127.0.0.1:8000/process (mode=dry_run)...
Memory Record Candidates
┌───┬──────────────┬────────────┬──────────┐
│ # │ Content │ Kind │ Evidence │
├───┼──────────────┼────────────┼──────────┤
│ 1 │ ... │ preference │ ... │
│ 2 │ ... │ pattern │ ... │
└───┴──────────────┴────────────┴──────────┘
3 candidate(s)
Extraction: qwen2.5:3b | Embedding: nomic-embed-text
Error handling
- Session load errors: malformed exports, missing IDs, unresolved agents
- Dream input errors: invalid JSON/YAML, missing required sections
- Connection errors: service unreachable at
http://127.0.0.1:8000 - Service errors: extraction/embedding failures returned with error metadata
Service Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /health |
Coarse health check (ok / error) |
| GET | /up-status |
Component-by-component dependency status |
| POST | /process |
Ingest a session (dry_run or commit) |
| POST | /retrieve |
Search memory for an agent (internal use) |
/process request body:
{
"session": { "... normalized session ..." },
"dream_rule": { "... dream rule ..." },
"mode": "dry_run"
}
/retrieve request body:
{
"agent_id": "default",
"query": "user preferences",
"limit": 5
}
Processed-Session Registry
Storage: local SQLite
Ownership: agent_memory_service — the registry is not accessed directly
by agent_memory_mcp or agent_memory_sleep; those packages must go through
the service boundary.
Path source: config/memory.yaml → registry.path (default:
data/processed_sessions.db, relative to the service working directory unless
absolute).
Frozen module: src/agent_memory_service/registry.py
Frozen contract fields:
| Field | Type | Purpose |
|---|---|---|
session_id |
str |
Unique session identifier |
agent_id |
str |
Canonical agent identity |
status |
str |
Processing outcome |
processed_at |
datetime |
Timestamp of processing completion |
The registry enforces idempotency: committing the same session_id twice
returns the existing entry without creating duplicate memory records.
Diagnostics
Common operator failure states and how to resolve them.
Qdrant unavailable
Symptom: /up-status reports qdrant: unavailable
docker ps --filter name=agent-memory-qdrant
curl http://localhost:7333/
Fix: start the Qdrant container — see Startup Order step 1.
Service unreachable
Symptom: MCP server exits with agent_memory_service unreachable,
or sleep CLI reports connection errors.
curl http://localhost:8000/health
Fix: start the service — see Startup Order step 3.
Ollama models missing
Symptom: /up-status reports provider_layer: ok but /process fails
with provider execution errors mentioning the model name.
ollama list
Fix: pull missing models — see Startup Order step 2.
Ollama embeddings not supported (HTTP 501)
Symptom: /process fails with This server does not support embeddings.
curl http://localhost:11434/api/embed -d '{"model":"nomic-embed-text","input":"test"}'
Fix: ensure Ollama is running (ollama serve) and the model is pulled.
Port conflicts (Windows)
Symptom: Docker cannot bind host port 6333.
Reason: Windows reserves TCP ports 6315-6414.
Fix: already configured — config/memory.yaml uses host port 7333.
Duplicate session commit
Symptom: committing the same session twice reports status: completed
but record_count: 0 on the second commit.
Expected behaviour: the registry returns the existing entry without creating duplicate memory records. This is idempotency, not a bug.
Memory not retrievable after commit
Symptom: sleep CLI reports status: completed with record_count > 0,
but /retrieve returns empty results.
Check:
curl -X POST http://localhost:8000/retrieve -H "Content-Type: application/json" -d "{\"agent_id\":\"default\",\"query\":\"test\",\"limit\":10}"
Fix: verify Qdrant collection exists and has the correct dimensions:
curl http://localhost:7333/collections
curl http://localhost:7333/collections/agent_memory
Check that embedding_dims: 768 in config/memory.yaml matches the
model (nomic-embed-text produces 768-dimension vectors). Confirm the
correct agent_id is used in retrieval — memories are scoped per agent.
SQLite registry failure
Symptom: /process commit mode fails with registry-related errors.
Check:
dir data\processed_sessions.db
Fix: ensure the data/ directory exists relative to the service
working directory, and the service process has write permissions.
If the database is locked, stop any other process accessing it and
delete the file to recreate on next boot.
Config loading failure
Symptom: service exits at startup with config errors.
python -c "from agent_memory_service.config import load_memory_config; print(load_memory_config().model_dump())"
Fix: check config/memory.yaml, config/providers.yaml, and
config/agents.yaml for valid YAML syntax and required fields.
End-to-End Verification
Run this sequence after starting the full stack to verify the operating model end to end.
Automated verification (integration tests)
Requires Qdrant, Ollama, and service already running:
python -m pytest tests/test_end_to_end.py -v -m integration
These tests verify:
- Service
/healthreturns ok /up-statusreports Qdrant, Mem0, and provider layer as okPOST /process(commit) persists memory recordsPOST /retrievereturns the persisted memory- Idempotency — duplicate commit returns the existing entry
Manual verification script
- Verify Qdrant:
curl http://localhost:7333/
- Verify service health:
curl http://localhost:8000/health
curl http://localhost:8000/up-status
Expected: all four components (config_loading, qdrant, mem0_oss,
provider_layer) report "status": "ok".
- Process a session via sleep CLI (commit mode):
python -m agent_memory_sleep
Select:
- Source:
opencode - Agent:
default - Session path:
tests/fixtures/opencode/session_sanitized.json - Dream:
profile→default - Mode:
commit
Expected: Status: completed with record count > 0.
- Verify retrieval through the service endpoint (service-level smoke check):
curl -X POST http://localhost:8000/retrieve ^
-H "Content-Type: application/json" ^
-d "{\"agent_id\":\"default\",\"query\":\"user preferences and actions\",\"limit\":5}"
Expected: results array contains at least one memory with content
from the processed session.
- Verify retrieval through the MCP server (MCP-client boundary):
First, start the MCP server in one terminal:
set AGENT_MEMORY_AGENT_ID=default
python -m agent_memory_mcp
Then call memory_search through an MCP client. Example verification
script (run from another terminal):
python -c "import asyncio, sys, os; from mcp import ClientSession; from mcp.client.stdio import StdioServerParameters, stdio_client; async def main(): server_params = StdioServerParameters(command=sys.executable, args=['-m', 'agent_memory_mcp'], env={**os.environ, 'AGENT_MEMORY_AGENT_ID': 'default'}); async with stdio_client(server_params) as (r, w): async with ClientSession(r, w) as session: await session.initialize(); result = await session.call_tool('memory_search', {'query': 'user preferences', 'limit': 5}); print('\\n'.join(c.text for c in result.content if hasattr(c, 'text'))); asyncio.run(main())"
Expected: formatted memory results including content from the processed session, scoped to the configured agent.
- Verify idempotency — re-run the sleep CLI with the same session:
python -m agent_memory_sleep
(Same selections as step 3)
Expected: Status: completed with record_count: 0 — the existing
registry entry is returned without creating duplicates.
Quick smoke checks
python -m pytest tests/ -q
python -c "import agent_memory_service, agent_memory_mcp, agent_memory_sleep; print('imports: ok')"
Test
Run all automated tests (integration tests are skipped when services aren't running):
python -m pytest
Run specific test files:
python -m pytest tests/test_end_to_end.py -v
Run with real services (Qdrant + service + Ollama must be running):
python -m pytest tests/test_end_to_end.py -v -m integration
Markers overview:
| Marker | Purpose |
|---|---|
integration |
Requires live Qdrant, service, and Ollama |
Local Defaults
| Component | Default Value | Config File |
|---|---|---|
| Extraction model | qwen2.5:3b |
providers.yaml |
| Fallback model | qwen2.5:7b |
providers.yaml |
| Embedding model | nomic-embed-text |
providers.yaml |
| Embedding dims | 768 |
memory.yaml |
| Qdrant port | 7333 |
memory.yaml |
| Ollama URL | http://localhost:11434 |
memory.yaml, providers.yaml |
| Service port | 8000 |
(uvicorn default) |
| Registry path | data/processed_sessions.db |
memory.yaml |
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。