Mastra integration
The v4 version of @getzep/zep-mastra is not released yet. The current @getzep/zep-mastra release uses the v3 API. To use this integration now, follow the v3 version of this page.
Zep context can include content that your users, documents, or tools supplied. A system or developer message gives that content higher instruction priority than ordinary input. Some convenience integrations use system-message injection. Use direct SDK retrieval or an actual retrieval tool call unless all stored content is application-authored and trusted. Follow Memory security best practices for provider-specific placement.
To build an agent that plans its retrieval and uses several Zep tools, read Build an Agent with Zep. The guide shows how to add domain knowledge, design tools, and evaluate the agent.
Mastra agents using Zep gain long-term memory backed by a temporal knowledge graph. The @getzep/zep-mastra package provides two complementary surfaces:
- Automatic memory for trusted content —
createZepProcessorsbuilds aZepInputProcessor/ZepOutputProcessorpair that plugs into Mastra’s nativeinputProcessors/outputProcessorspipeline. The input processor inserts context into a system message. - Tools —
createZepToolsetbuildszepRemember/zepSearch/zepContexttools that let the model decide when to persist or recall. Use retrieval tools for end-user or third-party context.
Core benefits
- Automatic memory loop for trusted content: Processors can inject application-authored context and persist each completed turn
- Model-in-the-loop tools:
zepRemember,zepSearch, andzepContextdrop straight into anAgent’stoolsrecord - Per-call identity: Resolve
graphUuid/threadUuidfrom Mastra’srequestContextso one processor or tool instance serves many end users - User and shared Context Graphs: Bind to a user’s personal graph or a shared knowledge base
- Graceful degradation: A Zep outage is logged and surfaced as a non-fatal result — it never crashes the host agent
How it works
The processors sit on opposite sides of the model call:
ZepInputProcessorruns before the model is called. It extracts the latest user message, retrieves a Zep context block (thread.getContext, or a customcontextBuilder), wraps it withcontextTemplate/formatContext, and injects it as a system message.ZepOutputProcessorruns after the model responds. It persists the completed turn — the latest user message plus the assistant’s response — to the bound thread via a singlethread.addMessagescall. The assistant text persisted is the final step’s text; when generation ends mid-tool-loop (finishReason === "tool-calls"), the user message is still persisted.
Because injection and persistence sit on opposite sides of the model call, it’s safe to enable both processors together — they don’t interfere with each other. Every Zep call is wrapped: a missing threadUuid or any Zep failure degrades gracefully — messages pass through unchanged, a warning is logged — and the input processor never calls abort() or throws into the agent loop.
Zep is a temporal knowledge graph, not a row-oriented message store, so the package exposes Zep’s two real operations — persist and retrieve — through processors and tools rather than a MastraStorage adapter, which would require CRUD operations a temporal knowledge graph can’t honor faithfully.
Installation
Requires Node.js 20+, @mastra/core>=1.42.0 (peer), @getzep/zep-cloud, and a Zep Cloud API key. Get your API key from app.getzep.com.
Set up your environment variables:
Identifiers
Zep v4 addresses every user, thread, and graph by a server-generated UUID. A create call accepts no client-chosen identifier, so a new user, thread, or graph has no name.
createZepUserAndThreadreturnsuserUuid,graphUuid, andthreadUuid. Store all three in your own database.- The processors take
graphUuidandthreadUuid. The tools take them on aZepBinding. - The integration never calls
lookupat run time. Resolve a v3 name to its UUID one time, then reuse the UUID.
Upgrading from @getzep/zep-mastra 0.2.0
The package now targets the Zep v4 SDK, and the public API takes UUIDs:
ensureZepUserAndThreadis replaced bycreateZepUserAndThread, which returns{ userUuid, graphUuid, threadUuid }ornull. Zep v4 has no name-addressed create, so the function is not idempotent on a name.ZepBindingtakesgraphUuidin place ofuserId/graphId, andZepThreadBindingtakesthreadUuidin place ofthreadId.- The processors take
graphUuidandthreadUuid, andResolvedZepIdentityreturns the same two fields. templateIdbecomestemplateUuid, andsearchFiltersbecomesfilters.
See the CHANGELOG for the full migration notes.
Automatic memory for trusted deployments
createZepProcessors inserts retrieved context into a system message. Use this processor pair only when all stored content is fully trusted and application-authored:
Customizing context injection
By default the input processor retrieves the context block with thread.getContext and wraps it in DEFAULT_CONTEXT_TEMPLATE — the canonical <ZEP_CONTEXT> wrapper shared by Zep’s framework integrations. Three options change that, in increasing order of control:
contextBuilderreplaces the default retrieval with your own async function. It receives aZepContextBuilderInput— the client, the resolvedgraphUuid/threadUuid, and the latest user message — and returns the context string (orundefinedto inject nothing for that turn). The result still passes through the template orformatContext.contextTemplatecustomizes the wrapping text. It must contain a literal{context}placeholder, replaced via literal string replacement (not a format string), so braces,%, and$in the retrieved context are safe.formatContexttakes over formatting entirely and wins overcontextTemplate.
Per-call identity
Pass resolveIdentity (a ZepIdentityResolver, sync or async) to resolve graphUuid/threadUuid per call from Mastra’s requestContext instead of binding a fixed identity at construction time — useful when a single processor instance serves many end users:
The same resolveIdentity option is accepted by createZepSearchTool, createZepRememberTool, and createZepContextTool (resolved from each tool call’s context.requestContext), and createZepToolset forwards it to all three tools.
If both a fixed graphUuid/threadUuid and resolveIdentity are set, resolveIdentity’s result wins for whichever fields it returns; any field it omits or resolves to undefined falls back to the constructor-bound value.
Provisioning with createZepUserAndThread
Zep requires the user and thread to exist before messages are added. Call createZepUserAndThread once, out-of-band, before the first turn, then store the returned UUIDs. Zep v4 addresses every later call by UUID, so this function is not idempotent on a name: a second call creates a second user. A failure (auth, network, 5xx) is logged at warn and reported as null, never thrown.
Pass onUserCreated (a ZepUserCreatedHook) to run one-time setup — per-user ontology, custom instructions, seeding — immediately after the user is created. The hook receives the userUuid:
The function sends no client-chosen identifier. The v4 create endpoints reject a userId or a threadId, and the returned UUIDs are the only addresses.
Tools
The toolset puts the model in the loop: the agent calls a tool when it decides to persist or recall. Use it standalone or alongside the processors.
The toolset provides three tools:
Each tool is also exported as a standalone factory (createZepRememberTool, createZepSearchTool, createZepContextTool) for wiring a single tool with custom options.
Each tool has a typed input and output schema:
zepSearch returns facts as extracted strings tailored to the search scope — edge facts, "name: summary" for entities, episode content, and so on — with found set to true when the result is non-empty.
Pin-or-expose search parameters
createZepSearchTool exposes each search parameter to the model by default, alongside the always-required query, so the model can tune its own searches per call:
Each parameter is independently tri-state at construction time (ZepSearchPinnableParams):
pinnedParamsfixes a parameter to a constant value: hidden from the model’s schema, always sent.hiddenParamsremoves a parameter from the schema without pinning it: omitted from the search call entirely, so Zep’s own server default applies.- Omitted from both — exposed to the model with the documented default.
filters and bfsOriginNodeUuids are always constructor-only — never exposed to the model — and applied whenever set. The legacy scope/reranker/limit constructor arguments pin (and hide) their parameter, equivalent to the corresponding pinnedParams entry.
Binding: user graph vs shared Context Graph
Zep v4 addresses every graph by its server-generated UUID, so a user graph and a standalone graph are the same kind of address. Tools and processors are bound with graphUuid, and the thread-scoped surfaces are bound with threadUuid:
- The
graphUuidof a user graph is thegraphUuidfield of theUserthatuser.createreturns. A user graph is the home for personalized agent memory. - The
graphUuidof a shared Context Graph is theuuidfield of theGraphthatgraph.createreturns. A shared Context Graph holds shared or domain knowledge such as a product knowledge base or runbooks. It has no user node and no user summary. - The
threadUuidis theuuidfield of theThreadthatthread.createreturns. Context retrieval and thezepContexttool need it. The thread scopes relevance; retrieval still spans the whole user graph.
If no graphUuid or no threadUuid can be resolved, tools and processors degrade gracefully instead of throwing.
Roles
zepRemember accepts an arbitrary role string and maps it onto Zep’s closed RoleType enum: user, assistant, system, tool, or function. Host-framework role names like human or ai are coerced safely; an unknown role is omitted. The mapper is exported as toRoleType.
Best practices
- Use tools for untrusted context. Use processors only when all stored content is application-authored and trusted.
- Call
createZepUserAndThreadonce before the first turn, store the returned UUIDs, then reuse a singleZepClient - Pass real names so Zep can anchor the user’s identity node in the graph
- Don’t read-after-write within a turn — Zep builds the graph asynchronously, so a just-stored fact is not instantly retrievable
- Pass a custom
loggerto route Zep warnings into your logging stack
Next steps
- Explore customizing graph structure for advanced knowledge organization
- Learn about searching the graph and how to tune search
- See code examples for additional patterns