--- title: "Pydantic AI memory: message history and a memory API" description: "Pydantic AI memory starts with message history that the application stores. Add timestamped, source-backed memory through a function tool or an MCPToolset." canonical: https://past.dev/integrations/pydantic-ai last-updated: 2026-10-09 --- # Add memory to Pydantic AI agents Source: https://past.dev/integrations/pydantic-ai Pydantic AI memory starts with message history: a run returns its messages, and the next run receives them as its message history. Storing that history is the application's job. The Pydantic AI Harness package adds a Memory capability, a notebook of Markdown files per user namespace that the agent writes and searches. A function tool that calls past.dev over HTTP adds timestamped ingestion and recall that returns ranked documents with dates and source excerpts. ## Pydantic AI memory scope [Message history](https://pydantic.dev/docs/ai/core-concepts/message-history/) is the core mechanism. `result.all_messages()` returns every message of a run, including earlier ones, and `result.new_messages()` returns the messages of the current run. The next run takes them through `message_history`. `ModelMessagesTypeAdapter` serializes them for storage, and the database schema is left to the application. The [persistence guide](https://pydantic.dev/docs/ai/core-concepts/persistence/) maps the other options. Durable execution keeps one run alive through a crash. `StepPersistence` records each step of a run, and `ConversationSearch` gives the model a search tool over that stored history. [Memory](https://pydantic.dev/docs/ai/harness/memory/) gives the agent a notebook of Markdown files that it writes, reads and searches through its own tools. - **Memory notes are text files.** The notebook is isolated per namespace, which the application resolves for each user or tenant. A note carries no event time or validity period. - **Search is literal.** `search_memory` runs a literal text search across the notes. - **The harness is version 0.x.** Its documentation states that the API may change between minor releases. ## The integration: two function tools Pydantic AI registers a function as a tool with `@agent.tool`, which receives a `RunContext`, or with `@agent.tool_plain`, which does not. The docstring becomes the tool description ([function tools](https://pydantic.dev/docs/ai/tools-toolsets/tools/)). The recipe passes the signed-in user's identity as the run's dependencies, so the model never chooses it. ```python import os, requests from pydantic_ai import Agent, RunContext BASE = "https://api.past.dev/api/v1" HEADERS = {"Authorization": f"Bearer {os.environ['PAST_API_KEY']}"} agent = Agent( model, # any model Pydantic AI supports deps_type=str, # the signed-in user's identity instructions="Call recall_memory before you answer questions about people, decisions or history.", ) @agent.tool def remember(ctx: RunContext[str], text: str, happened_at: str) -> dict: """Store timestamped source text, readable by the whole project, authored by the current user.""" return requests.post(f"{BASE}/ingest", headers=HEADERS, json={ "content": text, "timestamp": happened_at, "identity": ctx.deps, }).json() @agent.tool def recall_memory(ctx: RunContext[str], question: str) -> dict: """Return ranked documents with dates and source excerpts for the current user.""" return requests.post(f"{BASE}/recall", headers=HEADERS, json={ "query": question, "identity": ctx.deps, }).json() result = agent.run_sync("What did we decide about the Q4 budget?", deps="demo-user") ``` > **Identity** > > The application sets the identity. The model never chooses it. Recall returns what the identity in the request may read, so take the identity from the signed-in user in code, and keep it out of every value that the model fills. Recall returns ranked documents with dates and source excerpts. The application decides whether those documents support an answer, contain a disagreement, or are insufficient; HTTP failures are handled separately. ## Or connect the MCP server Pydantic AI connects to a remote MCP server with `MCPToolset` from `pydantic_ai.mcp`, passed to the agent through `toolsets`. A URL that does not end in `/sse` uses Streamable HTTP ([MCP client](https://pydantic.dev/docs/ai/mcp/client/)). The project's end-user MCP server then gives the agent `recall`, `answer` and `who_am_i`, plus `remember` while the project's write toggle is on, with no tool code to write. 1. Turn on the project's end-user MCP server on **Build › MCP server** in the console. 2. Mint an access link there, or with the account server's `create_mcp_access_link` tool. The link has the form `https://api.past.dev/mcp//link/`. It is one URL that is one identity, and the server answers it with no sign-in step. 3. Keep the link in a secret store, such as the `PAST_MCP_URL` environment variable that the code below reads. The secret in its path is the credential. ```python import asyncio, os from pydantic_ai import Agent from pydantic_ai.mcp import MCPToolset past = MCPToolset(os.environ["PAST_MCP_URL"]) agent = Agent( model, # any model Pydantic AI supports toolsets=[past], instructions="Call recall before you answer questions about people, decisions or history.", ) async def main(): async with agent: result = await agent.run("What did we decide about the Q4 budget?") print(result.output) asyncio.run(main()) ``` Every call through the link runs as its identity, with that identity's audiences. Mint one link per install, so that a revoked link stops one agent only. When the agent serves several people, mint one link per end user, and connect each request with the link of the user who makes it. Never share one link between users. `remember` writes to the identity's own private audience, and only that identity recalls it. Send data that the whole project must recall through the ingest call. The [end-user server documentation](/docs/mcp/serving-your-own-users) describes the tools, the links and revocation. ## Choosing a layer per requirement - Continue a conversation: message history that your application stores and passes back. - Notes the agent keeps for one user: the harness Memory capability. - Timestamped source history shared across agents, applications and identities, with dated source excerpts on recall: the function tools or the MCP server above. The [quickstart](/docs/memory-api/quickstart) shows how to ingest, wait until ingestion completes, and recall. The [benchmarks](/benchmarks) document how recall is measured. [Cross-session memory](/glossary/cross-session-memory) defines the layer the tools add. ## Frequently asked questions ### Does Pydantic AI have built-in memory? The core library passes message history between runs and leaves storage to the application. The Pydantic AI Harness package adds a Memory capability that keeps Markdown notes per user namespace. ### How does the tool know which user is asking? The recipe sets the identity as the run's dependencies. Each tool reads it from the RunContext, so the model cannot select another user's identity. ## Related - [Memory for the OpenAI Agents SDK](https://past.dev/integrations/openai-agents-sdk) - [Memory for Agno](https://past.dev/integrations/agno) - [Memory for DSPy](https://past.dev/integrations/dspy) - [Cross-session memory](https://past.dev/glossary/cross-session-memory) - [Quickstart](https://past.dev/docs/memory-api/quickstart)