MemoryRouter / Documentation
CrewAI Memory Across Runs and Deploys
Give CrewAI agents durable, per-user memory with two MemoryRouter API tools, so recall survives new runs, redeploys, and other crews.
CrewAI agents use MemoryRouter through two small custom tools: one searches a MemoryRouter vault, one stores a new memory in it. Each tool is a plain HTTPS call to the MemoryRouter API authenticated with a Memory Key. The vault lives outside your process, so memories survive a new kickoff(), a fresh container, a redeploy, and a different crew that holds the same key.
This is an API integration you add to your code, not a published CrewAI package or a replacement for CrewAI's Memory class. The agent decides when to call the tools, the same way it decides when to call any other CrewAI tool.
How this fits with CrewAI memory
CrewAI ships a unified Memory class. Pass memory=True to a crew and it analyzes what to save, infers scope and importance, and recalls with a composite score of similarity, recency, and importance. By default it stores data in LanceDB under ./.crewai/memory, or $CREWAI_STORAGE_DIR/memory, and you can plug in another storage backend.
Keep using it for crew state. MemoryRouter covers a different job: a hosted vault per end user that you do not run, that outlives the deployment, and that other crews and tools can search. You can use both at once.
Why a Memory Key and not MCP OAuth
CrewAI supports MCP servers over Streamable HTTP, but its MCPServerHTTP transport takes static headers and does not run an OAuth authorization flow against the server. MemoryRouter's MCP server at https://mcp.memoryrouter.ai/mcp requires an OAuth access token for every search and store and does not accept mk_ keys. So the supported route for a crew today is the REST API with a Memory Key, which is also the right shape for per-user vaults in a product.
Prerequisites
- Python 3.10 to 3.13 and a working CrewAI project (
pip install crewai). - A MemoryRouter account and Memory Key. Use a separate test key for the proof below.
- Network access to
https://api.memoryrouter.ai. - Your normal CrewAI model and provider credentials. This setup does not change them.
pip install crewai httpx
export MEMORYROUTER_API_KEY='YOUR_MEMORYROUTER_KEY'Keep the key server-side. Never ship it to a browser or commit it.
Add the memory tools
Save this as memory_tools.py:
import json
import os
import httpx
from crewai.tools import tool
API = "https://api.memoryrouter.ai/v1/memory"
def _headers() -> dict:
return {
"Authorization": f"Bearer {os.environ['MEMORYROUTER_API_KEY']}",
"Content-Type": "application/json",
}
@tool("Search long-term memory")
def search_memory(query: str) -> str:
"""Search the user's long-term memory for earlier facts, preferences, and decisions. Use before answering questions about past work."""
response = httpx.post(
f"{API}/search",
headers=_headers(),
json={"query": query, "limit": 8},
timeout=30,
)
response.raise_for_status()
memories = response.json().get("memories", [])
if not memories:
return "No relevant memories found."
return "\n".join(f"- {m['content']}" for m in memories)
@tool("Save to long-term memory")
def save_memory(fact: str) -> str:
"""Save one concise, durable fact or decision to the user's long-term memory."""
response = httpx.post(
f"{API}/upload",
headers={**_headers(), "Content-Type": "application/x-ndjson"},
content=json.dumps({"content": fact}) + "\n",
timeout=30,
)
response.raise_for_status()
return "Saved."search_memory calls POST /v1/memory/search, which returns ranked memories with their text. save_memory calls POST /v1/memory/upload with a single JSONL line, which stores that text as a memory in the vault behind the key.
Give both tools to any agent that should remember:
from crewai import Agent
from memory_tools import save_memory, search_memory
assistant = Agent(
role="Project assistant",
goal="Answer using what the user has already decided",
backstory="You check long-term memory before answering and save new decisions.",
tools=[search_memory, save_memory],
)The tool docstrings are what the model reads when it chooses a tool, so keep them specific.
Cross-run proof
Seed a synthetic fact in one run and recall it in another, without involving model judgment:
# run_a.py
from memory_tools import save_memory
print(save_memory.run(fact="The demo project's release phrase is ORCHID-7419."))# run_b.py
from memory_tools import search_memory
print(search_memory.run(query="demo project release phrase"))- Run
python run_a.pyand confirm it printsSaved. - Wait a few seconds for indexing, then run
python run_b.pyin a new process. - Confirm the output contains
ORCHID-7419. - Now put the same question to a crew whose agent has
search_memory, and check the tool output in the run logs, not only the final answer.
The second process shares no state with the first. The only link is the Memory Key. This is a test you run in your own account.
One vault per end user
A Memory Key is the vault. If your crew serves many users, give each user their own key and pick it per request instead of reading one global environment variable. Create keys programmatically with POST /v1/keys and store the mapping server-side. A shared key means a shared vault, so never let one user's crew run with another user's key.
Storing whole conversations
If your app already has the user's message and the final answer, you can store the exchange instead of single facts. Call POST /v1/memory/ingest with the user and assistant messages after the crew finishes. It returns 202 and stores in the background. To inject recall without a tool call, call POST /v1/memory/prepare before kickoff and pass the returned context text in as an input. See local inference mode for that pattern.
About the proxy route
CrewAI can point a model at an OpenAI-compatible endpoint with base_url, and MemoryRouter has one. That route is not documented here. The proxy stores and recalls message text and does not guarantee tool-calling parity, which CrewAI agents rely on. The tool route above keeps your provider and your crew exactly as they are.
Limitations
- Recall and storage are model-directed. An agent that never calls the tools neither recalls nor stores anything.
save_memorystores the text you pass, as is. It does not decide what is worth keeping.- This setup does not migrate existing CrewAI LanceDB memory into MemoryRouter. Export it yourself and use
/v1/memory/uploadif you want it in the vault. - Tools run in your process, so failures surface as tool errors. Handle
401,429, and timeouts in the tool if your crew must keep going.
Troubleshooting
| Symptom | Fix |
|---|---|
401 from the API | Check MEMORYROUTER_API_KEY in the environment that actually runs the crew. |
| Search returns nothing right after a save | Allow a few seconds for indexing and use a query close to the stored text. |
| The agent never calls the tools | Make the task description ask it to check memory, and make the tool docstrings specific. |
| Wrong user's memory appears | Fix the user-to-key mapping on your server. Changing crews or tasks does not isolate vaults. |