Experience Layer for Agent Frameworks
Agents repeat mistakes. Mnemoverse gives them experience.
The Problem
Your LangChain agent solves a task, learns nothing, and starts from scratch next time. Multi-step agents waste tokens rediscovering what worked. CrewAI agents don't share learnings across runs.
The Solution
An experience layer between your agent framework and the LLM. Agents write what worked (and what didn't), read past experience before planning, and improve over time.
For a complete program without a framework (recall, call a model, store the answer, give feedback), see Minimal agent. The examples below need pip install --upgrade "mnemoverse>=0.3.0" plus the framework's own package. They make several calls on one client, and 0.3.0 is the release where that stopped failing on every second call.
Frameworks with an MCP client can use the Mnemoverse MCP tools instead of wrapping the SDK. There are two ways in. The npm package @mnemoverse/mcp-memory-server runs as a local process with your API key in MNEMOVERSE_API_KEY; it needs Node.js 18+ on the machine that runs the agent. The hosted server at https://mcp.mnemoverse.com/mcp signs you in with OAuth in a browser. It does not accept an API key in an Authorization header, so a framework that can only send fixed headers cannot use it: use the npm package or the SDK there. Each section from OpenAI Agents SDK onward says how far its paths were checked.
LangChain
from mnemoverse import MnemoClient
from langchain.tools import tool
client = MnemoClient(api_key="mk_live_YOUR_KEY")
@tool
def remember(insight: str, concepts: list[str] = []) -> str:
"""Store a lesson learned for future reference."""
result = client.write(insight, concepts=concepts, domain="agent:experience")
return f"Remembered (importance: {result.importance:.2f})"
@tool
def recall(query: str) -> str:
"""Check past experience before starting a task."""
memories = client.read(query, domain="agent:experience", top_k=5)
if not memories.items:
return "No relevant past experience."
return "\n".join(
f"- [{m.relevance:.0%}] {m.content}" for m in memories.items
)Add to your agent:
from langchain.agents import create_agent
agent = create_agent(
model="anthropic:claude-opus-5", # a model string needs its provider package: pip install langchain-anthropic
tools=[remember, recall], # add your other tools to this list
system_prompt="Before you start a task, call recall to check past experience.",
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "Deploy the billing service to staging"}]}
)This is LangChain 1.x. create_tool_calling_agent moved to the langchain-classic package, so an import of it from langchain.agents fails.
LangGraph
Memory as a node in your graph:
from langgraph.graph import END, START, StateGraph
from mnemoverse import MnemoClient
from typing_extensions import TypedDict
client = MnemoClient(api_key="mk_live_YOUR_KEY")
class State(TypedDict, total=False):
task: str
experience: list[str]
outcome: str
concepts: list[str]
def check_experience(state: State) -> dict:
"""Node: check if we've done this before."""
memories = client.read(state["task"], domain="agent:experience")
return {"experience": [m.content for m in memories.items]}
def plan_task(state: State) -> dict:
# Your planning node: read state["experience"] here
return {}
def execute_task(state: State) -> dict:
# Your execution node: return the real result as "outcome"
return {"outcome": "done"}
def save_experience(state: State) -> dict:
"""Node: save what we learned."""
if state.get("outcome"):
client.write(
f"Task: {state['task']} → {state['outcome']}",
concepts=state.get("concepts", []),
domain="agent:experience",
)
return {}
graph = StateGraph(State)
graph.add_node("check_experience", check_experience)
graph.add_node("plan", plan_task)
graph.add_node("execute", execute_task)
graph.add_node("save_experience", save_experience)
graph.add_edge(START, "check_experience")
graph.add_edge("check_experience", "plan")
graph.add_edge("plan", "execute")
graph.add_edge("execute", "save_experience")
graph.add_edge("save_experience", END)
app = graph.compile()
app.invoke({"task": "Rotate the API keys for the staging cluster"})Each node returns only the keys it changes, and LangGraph merges them into the state. The graph runs only after compile().
n8n
Use the HTTP Request node to call Mnemoverse API directly (REST endpoints — not a server URL for n8n's MCP Client node):
Write memory:
- Method:
POST - URL:
https://core.mnemoverse.com/api/v1/memory/write - Headers:
X-Api-Key: mk_live_YOUR_KEY - Body:
{"content": "$json.insight", "concepts": ["$json.topic"]}
Read memory:
- Method:
POST - URL:
https://core.mnemoverse.com/api/v1/memory/read - Headers:
X-Api-Key: mk_live_YOUR_KEY - Body:
{"query": "$json.question", "top_k": 5}
CrewAI
from crewai import Agent
from crewai.tools import tool as crewai_tool
from mnemoverse import MnemoClient
client = MnemoClient(api_key="mk_live_YOUR_KEY")
@crewai_tool("Remember")
def remember(insight: str) -> str:
"""Store experience for future tasks."""
result = client.write(insight, domain="agent:crew")
return f"Stored: {result.atom_id}"
@crewai_tool("Recall")
def recall(query: str) -> str:
"""Check past experience."""
memories = client.read(query, domain="agent:crew", top_k=5)
return "\n".join(m.content for m in memories.items) or "No experience."
researcher = Agent(
role="Researcher",
goal="Research questions and record what you learn",
backstory="You learn from past research. Always check Recall first.",
tools=[remember, recall], # add your other tools to this list
)OpenAI Agents SDK
Checked 2026-09-27 with openai-agents 0.22.3 and mcp 2.2.0. npm package: started, listed its tools, and a fake key got our 401 reply. Hosted server: the client registered itself and built our sign-in URL; no sign-in was completed.
With the npm package (API key):
import asyncio, os
from agents import Agent, Runner
from agents.mcp import MCPServerStdio
async def main():
async with MCPServerStdio(
name="mnemoverse",
params={
"command": "npx", # on Windows: "npx.cmd"
"args": ["-y", "@mnemoverse/mcp-memory-server@latest"],
"env": {"MNEMOVERSE_API_KEY": os.environ["MNEMOVERSE_API_KEY"]},
},
client_session_timeout_seconds=30, # the first run downloads the package
) as memory:
agent = Agent(
name="Assistant",
instructions="Before a task, call memory_read. After it, store what worked with memory_write.",
mcp_servers=[memory],
)
result = await Runner.run(agent, "Deploy the billing service to staging")
print(result.final_output)
asyncio.run(main())With the hosted server (OAuth): the MCP Python SDK's OAuthClientProvider registers a client, sends you to our sign-in page and exchanges the code for a token. You supply two functions: one shows the sign-in link, the other returns the code from the redirect.
import asyncio
from urllib.parse import parse_qs, urlparse
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp
from mcp.client.auth import OAuthClientProvider, TokenStorage
from mcp.shared.auth import AuthorizationCodeResult, OAuthClientMetadata
class MemoryTokenStorage(TokenStorage): # keeps tokens in memory: you sign in on every start
def __init__(self): self.tokens = self.client = None
async def get_tokens(self): return self.tokens
async def set_tokens(self, tokens): self.tokens = tokens
async def get_client_info(self): return self.client
async def set_client_info(self, info): self.client = info
async def show_link(url: str) -> None:
print("Sign in to Mnemoverse:", url)
async def read_redirect() -> AuthorizationCodeResult: # mcp 2.x signature
redirected = input("Paste the full URL you were redirected to: ")
q = parse_qs(urlparse(redirected).query)
return AuthorizationCodeResult(code=q["code"][0], state=q.get("state", [None])[0])
auth = OAuthClientProvider(
server_url="https://mcp.mnemoverse.com/mcp",
client_metadata=OAuthClientMetadata(
client_name="My agent",
redirect_uris=["http://localhost:3030/callback"],
grant_types=["authorization_code", "refresh_token"],
response_types=["code"],
token_endpoint_auth_method="none",
),
storage=MemoryTokenStorage(),
redirect_handler=show_link,
callback_handler=read_redirect,
)
async def main():
async with MCPServerStreamableHttp(
name="mnemoverse",
params={"url": "https://mcp.mnemoverse.com/mcp", "auth": auth},
) as memory:
agent = Agent(name="Assistant", mcp_servers=[memory])
print((await Runner.run(agent, "What do you remember about staging?")).final_output)
asyncio.run(main())The callback's return type depends on the MCP SDK major version: with mcp 2.x it returns AuthorizationCodeResult, with mcp 1.x a (code, state) tuple. pip install openai-agents accepts either (mcp>=1.19,<3); the example is for 2.x. Our check stopped at the sign-in page, so read_redirect and the code exchange did not run. Sign-in happens in a browser, so this path fits an agent a person starts. For a server or a scheduled job, use the npm package or the Python SDK.
Source: OpenAI Agents SDK, MCP, read 2026-09-27: "Use an Authorization header when possible" and params["auth"] takes httpx.Auth (MCP v1) or httpx2.Auth (MCP v2); agents/mcp/server.py in openai-agents 0.22.3 and mcp/client/auth/oauth2.py in mcp 2.2.0 (OAuthClientProvider is an httpx2.Auth), both installed from PyPI 2026-09-27. Local run 2026-09-27 with a fake key, up to the sign-in URL.
Microsoft Agent Framework
Python, checked 2026-09-27 with agent-framework-core 1.19.0 and mcp 1.30.0. npm package: started, listed its tools, and a fake key got our 401 reply. Hosted server: the client registered itself and built our sign-in URL; no sign-in was completed. .NET: from documentation and source, not tested.
Agent Framework needs the 1.x line of the MCP SDK (mcp<2), and the OpenAI client is a separate package:
pip install agent-framework-core agent-framework-openai "mcp<2"With the npm package (API key):
import asyncio, os
from agent_framework import Agent, MCPStdioTool
from agent_framework.openai import OpenAIChatClient
async def main():
async with (
MCPStdioTool(
name="mnemoverse",
command="npx", # on Windows: "npx.cmd"
args=["-y", "@mnemoverse/mcp-memory-server@latest"],
env={"MNEMOVERSE_API_KEY": os.environ["MNEMOVERSE_API_KEY"]},
load_prompts=False,
) as memory,
Agent(
client=OpenAIChatClient(), # reads OPENAI_API_KEY and OPENAI_CHAT_MODEL
name="Assistant",
instructions="Check memory_read before a task; store what worked with memory_write.",
) as agent,
):
result = await agent.run("Deploy the billing service to staging", tools=memory)
print(result.text)
asyncio.run(main())The package also serves four prompts (recall, save_insight, what_do_you_know, setup_memory). Agent Framework loads prompts as functions by default; load_prompts=False keeps only the tools.
With the hosted server (OAuth): give MCPStreamableHTTPTool an httpx.AsyncClient that carries the MCP SDK's OAuthClientProvider. It is the same setup as in the OpenAI Agents SDK example, with one difference: under mcp 1.x the callback returns a (code, state) tuple.
import asyncio
from urllib.parse import parse_qs, urlparse
import httpx
from agent_framework import Agent, MCPStreamableHTTPTool
from agent_framework.openai import OpenAIChatClient
from mcp.client.auth import OAuthClientProvider, TokenStorage
from mcp.shared.auth import OAuthClientMetadata
class MemoryTokenStorage(TokenStorage): # keeps tokens in memory: you sign in on every start
def __init__(self): self.tokens = self.client = None
async def get_tokens(self): return self.tokens
async def set_tokens(self, tokens): self.tokens = tokens
async def get_client_info(self): return self.client
async def set_client_info(self, info): self.client = info
async def show_link(url: str) -> None:
print("Sign in to Mnemoverse:", url)
async def read_redirect() -> tuple[str, str | None]: # mcp 1.x signature
redirected = input("Paste the full URL you were redirected to: ")
q = parse_qs(urlparse(redirected).query)
return q["code"][0], q.get("state", [None])[0]
auth = OAuthClientProvider(
server_url="https://mcp.mnemoverse.com/mcp",
client_metadata=OAuthClientMetadata(
client_name="My agent",
redirect_uris=["http://localhost:3030/callback"],
grant_types=["authorization_code", "refresh_token"],
response_types=["code"],
token_endpoint_auth_method="none",
),
storage=MemoryTokenStorage(),
redirect_handler=show_link,
callback_handler=read_redirect,
)
async def main():
async with (
MCPStreamableHTTPTool(
name="mnemoverse",
url="https://mcp.mnemoverse.com/mcp",
http_client=httpx.AsyncClient(auth=auth, timeout=30),
load_prompts=False,
) as memory,
Agent(client=OpenAIChatClient(), name="Assistant") as agent,
):
result = await agent.run("What do you remember about staging?", tools=memory)
print(result.text)
asyncio.run(main())Nothing listens on localhost:3030: after sign-in the browser shows an error page, and you paste its address, which carries the code, into the prompt. As with the OpenAI Agents SDK, our check stopped at the sign-in page, so read_redirect and the code exchange did not run.
Do not put a Mnemoverse API key in static_headers or header_provider: the hosted server does not accept an API key in the Authorization header.
.NET (from documentation and source, not tested): Agent Framework uses the official MCP C# SDK. For the npm package, use StdioClientTransport with npx and the arguments -y and @mnemoverse/mcp-memory-server@latest, and pass MNEMOVERSE_API_KEY in its environment variables. For the hosted server, use HttpClientTransport with ClientOAuthOptions; when no ClientId is set, the SDK registers a client itself.
Source: Using MCP tools with Agents, updated 2026-09-23, read 2026-09-27: "use static_headers for fixed credentials or header_provider for values derived from each run" and "pass a configured httpx.AsyncClient through http_client="; agent_framework/_mcp.py in agent-framework-core 1.19.0, whose metadata requires mcp>=1.24.0,<2, installed from PyPI 2026-09-27; ClientOAuthOptions.cs in the MCP C# SDK, read 2026-09-27: "If not provided, the client will attempt to register dynamically." Local run (Python) 2026-09-27 with a fake key, up to the sign-in URL.
Semantic Kernel
Semantic Kernel is superseded by Microsoft Agent Framework: use the Agent Framework section.
Source: microsoft/semantic-kernel README, read 2026-09-27: "Semantic Kernel is now Microsoft Agent Framework!"
Langflow
Checked 2026-09-27 with lfx 1.12.3, Langflow's engine package: its stdio client started the npm package and listed the tools. Its HTTP client got a 401 from the hosted server, with no header and with a fake mk_live_ key as a bearer token. The Langflow UI itself was not run.
Langflow's MCP client sends fixed headers and has no OAuth sign-in. The hosted server accepts only an OAuth sign-in, not an API key in a header, so there is no path from Langflow to the hosted server until the server accepts API keys as bearer tokens. Native OAuth in Langflow's MCP client is requested in langflow#15408. Use the npm package:
- Install Node.js (LTS) where Langflow runs. In Docker, add it to the image and rebuild.
- Store your key as a Langflow global variable, for example
MNEMOVERSE_KEY. - In MCP Tools, add an MCP server of type STDIO: command
npx, arguments-yand@mnemoverse/mcp-memory-server@latest, environment variableMNEMOVERSE_API_KEYwith the valueMNEMOVERSE_KEY, the name of the global variable from step 2. Langflow replaces the name with the stored key when it starts the process.
If the operator has set LANGFLOW_MCP_SERVER_ALLOWED_PACKAGES, it must include @mnemoverse/mcp-memory-server. The alternative is to call the Python SDK from a custom component.
Source: Use Langflow as an MCP client, read 2026-09-27: "To use npx server commands, you must first install an LTS release of Node.js"; src/lfx/src/lfx/base/mcp/util.py at tag v1.12.3, read 2026-09-27: the HTTP client passes headers and no auth, and stdio env values resolve global variables by name or as {{NAME}}; src/lfx/src/lfx/base/mcp/security.py at the same tag: npx may take -y, and LANGFLOW_MCP_SERVER_ALLOWED_PACKAGES restricts packages when set. Local run 2026-09-27 with a fake key.
Flowise
From Flowise 3.1.4 documentation and source. Checked 2026-09-27: the MCP TypeScript SDK version Flowise pins (1.29.0) listed the npm package's tools over stdio with npx and no -y, and got a 401 from the hosted server; Flowise's own config check, run on its own, accepted the config below. Flowise itself was not run.
Flowise's Custom MCP tool sends fixed headers only, so it cannot sign in to the hosted server. On a self-hosted Flowise the operator can allow the npm package over stdio with these environment variables:
CUSTOM_MCP_PROTOCOL=stdio
CUSTOM_MCP_ALLOWED_COMMANDS=npx
CUSTOM_MCP_ALLOWED_ENV_VARS=MNEMOVERSE_API_KEY
CUSTOM_MCP_ALLOWED_ABSOLUTE_SCRIPT_PATHS=@mnemoverse/mcp-memory-server@latestThe last one is needed although the value is not a path: Flowise checks the first argument of every stdio command against that list. Flowise's own warning for stdio: "'stdio' can run arbitrary commands on your server, enable only if you trust all users".
Then store the key as a Flowise variable, for example mnemoverseKey, and use this server config in the Custom MCP node:
{
"command": "npx",
"args": ["@mnemoverse/mcp-memory-server@latest"],
"env": { "MNEMOVERSE_API_KEY": "{{$vars.mnemoverseKey}}" }
}Leave out -y: Flowise rejects it for npx. Without a terminal, npx installed the package without asking in our check. On Flowise Cloud, or when stdio stays off, call the REST API from an HTTP node as in the n8n section, or the Python SDK from your own code.
Source: Tools & MCP, read 2026-09-27: stdio "Only use this when using Flowise locally, not when deployed to cloud services"; tag flowise@3.1.4, read 2026-09-27: packages/components/nodes/tools/MCP/core.ts (headers only on the HTTP transport; validateMCPServerConfig with the allow-lists, the first-argument check and -y in the npx deny-list), CustomMCP.ts (stdio only when CUSTOM_MCP_PROTOCOL=stdio), docker/.env.example, and packages/server/src/Interface.ts (Custom MCP server auth types: none or custom headers). Local run 2026-09-27 with a fake key.
The Feedback Loop
What makes this an experience layer, not just a memory layer:
from mnemoverse import MnemoClient
client = MnemoClient(api_key="mk_live_YOUR_KEY")
task = "Deploy the billing service to staging"
# Before the task: the memories the agent will use
used_memories = client.read(task, domain="agent:experience").items
# ... the agent runs the task with these memories as context ...
succeeded = True # replace with your own check of the result
# After the task: a positive outcome if it worked, a negative one if it failed
if used_memories:
client.feedback(
atom_ids=[memory.atom_id for memory in used_memories],
outcome=1.0 if succeeded else -0.5,
domain="agent:experience",
)Successful strategies rank higher in future searches. Failed approaches fade. The agent gets better over time.
Multi-Agent Memory Sharing
Different agents, same memory pool:
# Researcher agent finds something
client.write(
"API rate limit is 100 req/min, not 1000 as documented",
concepts=["api", "rate-limit"],
domain="project:acme"
)
# Developer agent reads it later
memories = client.read(
"API rate limits for this project",
domain="project:acme"
)
# → Knows about the real rate limitCommon questions
How do I add long-term memory to a LangChain or LangGraph agent?
Wrap Mnemoverse write/read as tools in LangChain, or as nodes in a LangGraph graph. The agent recalls past experience before planning (memory_read) and stores what worked afterward (memory_write), so it carries knowledge across runs instead of starting cold.
How do AI agents remember what worked across runs?
Store each outcome with memory_write and rate it with memory_feedback. Successful strategies rank higher in future searches; failed ones fade. That feedback loop is what makes it an experience layer, not just storage.
Can multiple agents share the same memory?
Yes. Point them at the same domain (for example domain="project:acme") and any agent's findings become available to the others — a researcher agent's discovery is readable by a developer agent later.
Does Mnemoverse work with CrewAI and n8n?
Yes. In CrewAI, expose write/read with the tool decorator and reference them in the agent's backstory. In n8n, call the REST API directly from an HTTP Request node — no SDK required.
What's the best way to give an AI agent long-term memory?
Give it a persistent memory service it can call as tools: recall past experience before planning (memory_read), store what worked afterward (memory_write), and rate outcomes with feedback so useful memories rank higher next time. With Mnemoverse this drops into LangChain, LangGraph, CrewAI, or any framework via the SDK or REST.
Get Started
- Get an API key (free)
pip install mnemoverse- Wrap
write/readas tools for your framework - Add to agent prompt: "Always check past experience before planning"
Building in TypeScript on the Vercel AI SDK? The same three tools, written with tool() and run live, are on the Vercel AI SDK page.