Skip to content

LangGraph

LangGraph agents reach Meaning Memory through langchain-mcp-adapters, which turns MCP tools into LangChain tools. No custom glue is needed. Set up an agent workspace and an access policy first: steps 1 to 4 of the Quickstart.

Tested with langgraph 1.2.12, langchain-mcp-adapters 0.3.2 and Meaning Memory 3.20.0 on the file backend.

Terminal window
pip install langgraph langchain-mcp-adapters
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({
"meaning-memory": {
"transport": "stdio",
"command": "mm-mcp",
"args": [],
"env": {
"MM_AGENT": "support-bot",
"MM_ACTOR": "support-bot",
"MM_BACKEND": "file",
"MM_WORKSPACE": "/srv/support-bot-mm",
"MM_CONFIG_DIR": "/srv/support-bot-mm",
"MM_SCOPE_AUTH_CONFIG": "/srv/scope_auth.yaml",
"MM_ALLOW_INTERNAL": "1",
},
}
})
all_tools = await client.get_tools()

All 53 tools load. Give the agent only the ones it needs; a short list keeps the model’s context for the task and makes tool choice more reliable:

wanted = {"mm_remember", "mm_search", "mm_due_commitments"}
tools = [tool for tool in all_tools if tool.name in wanted]

A complete example: a promise kept across sessions

Section titled “A complete example: a promise kept across sessions”

The agent stores a promise in one invocation and answers a question about it in a second invocation that has no chat history, so the answer can only come from memory.

import asyncio
from langchain_core.messages import HumanMessage
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent
SERVER = {
"meaning-memory": {
"transport": "stdio",
"command": "mm-mcp",
"args": [],
"env": {
"MM_AGENT": "support-bot",
"MM_ACTOR": "support-bot",
"MM_BACKEND": "file",
"MM_WORKSPACE": "/srv/support-bot-mm",
"MM_CONFIG_DIR": "/srv/support-bot-mm",
"MM_SCOPE_AUTH_CONFIG": "/srv/scope_auth.yaml",
"MM_ALLOW_INTERNAL": "1",
},
}
}
PROMPT = (
"You are a support agent with long-term memory tools. Use mm_remember to store "
"anything the user asks you to remember; store promises with memory_type='commitment' "
"and due_at as an ISO date. Do not set party. To answer questions about promises, call "
"mm_due_commitments. For facts, call mm_search with one or two key words."
)
async def main(model) -> None:
client = MultiServerMCPClient(SERVER)
wanted = {"mm_remember", "mm_search", "mm_due_commitments"}
tools = [tool for tool in await client.get_tools() if tool.name in wanted]
agent = create_react_agent(model, tools, prompt=PROMPT)
await agent.ainvoke({"messages": [HumanMessage(
"Remember this for later: I promised Dana at Acme I'd send her the "
"updated pricing sheet by November 7, 2026."
)]})
# A fresh invocation: nothing carries over except what is in memory.
result = await agent.ainvoke({"messages": [HumanMessage(
"What did I promise Acme, and by when?"
)]})
print(result["messages"][-1].content)
# asyncio.run(main(model)) with any LangChain chat model that supports tool calling.

In our test the second invocation called mm_due_commitments and answered: “You promised Dana at Acme … the updated pricing sheet by November 7, 2026.”

Commitments come back through mm_due_commitments. Give the agent that tool and tell it to use it for questions about promises. It is more reliable than searching for them.

Don’t let the agent set party unless you configured it. party must be one of the tags in the agent’s configuration ([parties] tags). An agent that invents one, such as "Acme Corp", gets the write refused. Either add the tags you want, or tell the agent not to set it, as the prompt above does.

On the file backend, search with one or two words. Search there matches the query as one phrase, so a natural multi-word question often finds nothing. Postgres matches words in any order. See When memories become searchable.

Facts are queued; commitments are not. A fact the agent stores is searchable by that agent at once, and reaches the compiled memory file at the next consolidation. Schedule consolidation as in the Quickstart.

Calling a tool node directly. If you run the tools in your own graph rather than through create_react_agent, put the ToolNode inside a StateGraph. LangGraph 1.2 does not run a bare ToolNode on its own.