Utilisation de la mémoire d'agent avec un serveur MCP

Dans cet article, vous allez présenter les outils MCP (Model Context Protocol) de la mémoire de l'agent Oracle afin que les exécutions d'agent puissent accéder à la mémoire de l'agent via une interface standard.

Vous allez apprendre à :

A savoir : Pour la configuration des packages, reportez-vous à Introduction à la mémoire de l'agent. Si vous avez besoin d'une instance Oracle AI Database locale pour cet exemple, reportez-vous à Exécution locale d'Oracle AI Database. Cet article suppose que vous avez déjà configuré un pool, un intégrateur et un LLM Oracle DB.

Ecrire le serveur MCP

Créez un serveur MCP qui expose les API de mémoire de l'agent Oracle en tant qu'outils.

Dans cet exemple, la surface de l'outil reste intentionnellement petite :

get_or_create_thread, add_messages, get_messages, add_memory et search_memory.

L'exemple renvoie des chaînes JSON via json.dumps(...) pour chaque résultat d'outil. Cela permet de simplifier le schéma de sortie et fonctionne correctement sur les clients MCP.

Remarque : installez la bibliothèque MCP séparément avant d'exécuter cet exemple de serveur.

import json
import os
from typing import Any

from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel

from oracleagentmemory.core.dbschemapolicy import SchemaPolicy
from oracleagentmemory.core.embedders.embedder import Embedder
from oracleagentmemory.core.llms.llm import Llm
from oracleagentmemory.core.oracleagentmemory import OracleAgentMemory

embedder = Embedder(
    model="YOUR_EMBEDDING_MODEL",
    api_base="YOUR_EMBEDDING_API_BASE",
    api_key="YOUR_EMBEDDING_API_KEY",
)
llm = Llm(
    model="YOUR_LLM_MODEL",
    api_base="YOUR_LLM_API_BASE",
    api_key="YOUR_LLM_API_KEY",
)
db_pool = ...  #an oracledb connection or connection pool


class MessageT(BaseModel):
    role: str
    content: str
    id: str | None = None
    timestamp: str | None = None
    metadata: dict[str, Any] | None = None


def create_server(
    memory: OracleAgentMemory | None = None,
    host: str | None = None,
    port: int | None = None,
    path: str | None = None,
) -> FastMCP:
    """Create a FastMCP server exposing Oracle Agent Memory tools."""
    agent_memory = memory or OracleAgentMemory(
        connection=db_pool,
        embedder=embedder,
        llm=llm,
        schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
    )
    resolved_path = path or os.environ.get("MEMORY_MCP_PATH", "/mcp")
    if not resolved_path.startswith("/"):
        resolved_path = f"/{resolved_path}"
    server = FastMCP(
        name="Oracle Agent Memory MCP Server",
        host=host or os.environ.get("MEMORY_MCP_HOST", "localhost"),
        port=int(port if port is not None else os.environ.get("MEMORY_MCP_PORT", "8003")),
        streamable_http_path=resolved_path,
    )

    @server.tool(
        description=(
            "Get an existing thread by thread_id, or create one from user_id and optional "
            "agent_id."
        )
    )
    def get_or_create_thread(
        thread_id: str | None = None,
        user_id: str | None = None,
        agent_id: str | None = None,
    ) -> str:
        create_kwargs: dict[str, str] = {}
        if thread_id is not None:
            try:
                thread = agent_memory.get_thread(thread_id)
                return json.dumps(
                    {
                        "thread_id": thread.thread_id,
                        "user_id": thread.user_id,
                        "agent_id": thread.agent_id,
                    }
                )
            except KeyError:
                create_kwargs["thread_id"] = thread_id
        if user_id is not None:
            create_kwargs["user_id"] = user_id
        if agent_id is not None:
            create_kwargs["agent_id"] = agent_id
        thread = agent_memory.create_thread(**create_kwargs)
        return json.dumps(
            {
                "thread_id": thread.thread_id,
                "user_id": thread.user_id,
                "agent_id": thread.agent_id,
            }
        )

    @server.tool(
        description=(
            "Add durable memory content, optionally scoped by user_id, agent_id, and "
            "thread_id."
        )
    )
    def add_memory(
        content: str,
        user_id: str | None = None,
        agent_id: str | None = None,
        thread_id: str | None = None,
    ) -> str:
        add_kwargs: dict[str, str] = {}
        if user_id is not None:
            add_kwargs["user_id"] = user_id
        if agent_id is not None:
            add_kwargs["agent_id"] = agent_id
        if thread_id is not None:
            add_kwargs["thread_id"] = thread_id
        return json.dumps({"memory_id": agent_memory.add_memory(content, **add_kwargs)})

    @server.tool(
        description="Add messages to an existing thread using messages and thread_id."
    )
    def add_messages(messages: list[MessageT], thread_id: str) -> str:
        thread = agent_memory.get_thread(thread_id)
        payload = [message.model_dump(exclude_none=True) for message in messages]
        return json.dumps({"message_ids": thread.add_messages(payload)})

    @server.tool(description="Get messages from an existing thread using thread_id.")
    def get_messages(thread_id: str) -> str:
        thread = agent_memory.get_thread(thread_id)
        return json.dumps(
            {
                "messages": [
                    {
                        "id": getattr(message, "id", None),
                        "role": message.role,
                        "content": message.content,
                        "timestamp": message.timestamp,
                        "metadata": message.metadata,
                    }
                    for message in thread.get_messages()
                ]
            }
        )

    @server.tool(
        description=(
            "Search Oracle Agent Memory for durable memory and thread content. "
            "Pass user_id directly, or pass thread_id so the server can resolve the user scope."
        )
    )
    def search_memory(
        query: str,
        user_id: str | None = None,
        agent_id: str | None = None,
        thread_id: str | None = None,
    ) -> str:
        if user_id is not None:
            resolved_user_id = user_id
            resolved_agent_id = agent_id
        elif thread_id is not None:
            thread = agent_memory.get_thread(thread_id)
            if thread.user_id is None:
                raise ValueError(
                    f"Thread `{thread_id}` is not associated with a user_id, so "
                    "search_memory cannot build a valid OracleAgentMemory search scope."
                )
            resolved_user_id = thread.user_id
            resolved_agent_id = agent_id if agent_id is not None else thread.agent_id
        else:
            raise ValueError("search_memory requires either `user_id` or `thread_id`.")
        search_kwargs: dict[str, Any] = {"query": query, "user_id": resolved_user_id}
        if resolved_agent_id is not None:
            search_kwargs["agent_id"] = resolved_agent_id
            search_kwargs["exact_agent_match"] = True
        if thread_id is not None:
            search_kwargs["thread_id"] = thread_id
            search_kwargs["exact_thread_match"] = True
        results = agent_memory.search(**search_kwargs)
        return json.dumps(
            {
                "results": [
                    {
                        "id": result.id,
                        "content": result.content,
                        "record_type": result.record.record_type,
                        "user_id": result.record.user_id,
                        "agent_id": result.record.agent_id,
                        "thread_id": result.record.thread_id,
                    }
                    for result in results
                ]
            }
        )

    return server

Exécuter le serveur MCP

Par défaut, le serveur écoute sur http://localhost:8003/mcp. Remplacez l'adresse de liaison par MEMORY_MCP_HOST, MEMORY_MCP_PORT et MEMORY_MCP_PATH si nécessaire.

def main() -> None:
    server = create_server()
    server.run(transport="streamable-http")

if __name__ == "__main__":
    main()

Utiliser le serveur de LangGraph

LangGraph peut utiliser les outils MCP via langchain-mcp-adapters. L'agent ci-dessous se connecte au serveur de mémoire via streamable-http et permet au modèle d'appeler directement les outils de mémoire de l'agent Oracle.

Remarque : installez langchain-mcp-adapters pour cet exemple de client. Les outils MCP LangGraph nécessitent l'exécution de l'agent avec des méthodes asynchrones telles que ainvoke().

Configuration du client LangGraph

import os
from datetime import timedelta

import anyio
from langchain.agents import create_agent
from langchain_core.messages import HumanMessage
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_openai import ChatOpenAI

mcp_url = os.environ.get("MEMORY_MCP_URL", "http://localhost:8003/mcp")

langgraph_llm = ChatOpenAI(
    model="gpt-4.1-mini",
    api_key="YOUR_OPENAI_API_KEY",
)


async def build_langgraph_agent():
    memory_tools = await MultiServerMCPClient(
        {
            "memory": {
                "transport": "streamable_http",
                "url": mcp_url,
                "timeout": timedelta(seconds=30),
                "sse_read_timeout": timedelta(seconds=30),
            }
        }
    ).get_tools()
    return create_agent(
        model=langgraph_llm,
        tools=memory_tools,
        system_prompt=(
            "You are an assistant using Oracle Agent Memory through MCP. "
            "Create threads before writing messages, use add_memory for durable facts, "
            "and call search_memory when the user asks about prior context."
        ),
    )

Exécution d'un agent LangGraph sur le serveur MCP

async def run_langgraph_agent() -> None:
    agent = await build_langgraph_agent()
    first_turn = await agent.ainvoke(
        {
            "messages": [
                HumanMessage(
                    content=(
                        "Use the memory MCP tools to create thread `mcp_demo_thread` for user "
                        "`user_123`, add the durable memory `The user likes orange juice with "
                        "breakfast.`, and confirm when the memory is stored."
                    )
                )
            ]
        }
    )
    print(first_turn["messages"][-1].content)

    second_turn = await agent.ainvoke(
        {
            "messages": [
                HumanMessage(
                    content=(
                        "Search memory for `orange juice` in thread `mcp_demo_thread` and tell "
                        "me what Oracle Agent Memory returned."
                    )
                )
            ]
        }
    )
    print(second_turn["messages"][-1].content)

Sortie :

The durable memory has been stored successfully:
-Thread ID: `mcp_demo_thread`
-User ID: `user_123`

The search returned matching memory records for:
"The user likes orange juice with breakfast."

Utiliser le serveur de WayFlow

WayFlow peut utiliser le même serveur MCP via MCPToolBox avec StreamableHTTPTransport. Pour plus de détails sur l'API, reportez-vous aux documents WayFlow MCPToolBox.

Remarque : installez wayflowcore pour cet exemple de client.

Configuration du client WayFlow

import os

from wayflowcore.agent import Agent
from wayflowcore.mcp import MCPToolBox, StreamableHTTPTransport, enable_mcp_without_auth
from wayflowcore.models import OpenAICompatibleModel

mcp_url = os.environ.get("MEMORY_MCP_URL", "http://localhost:8003/mcp")

wayflow_llm = OpenAICompatibleModel(
    model_id="gpt-4.1-mini",
    base_url="YOUR_OPENAI_API_BASE",
    api_key="YOUR_OPENAI_API_KEY",
)

enable_mcp_without_auth()
memory_tools = MCPToolBox(client_transport=StreamableHTTPTransport(url=mcp_url))
agent = Agent(
    llm=wayflow_llm,
    agent_id="memory_mcp_agent",
    custom_instruction=(
        "You are an assistant using Oracle Agent Memory through MCP. "
        "Create threads before writing messages, use add_memory for durable facts, "
        "and call search_memory when the user asks about prior context."
    ),
    tools=[memory_tools],
)

Exécuter un agent WayFlow sur le serveur MCP

first_session = agent.start_conversation()
first_session.append_user_message(
    "Use the memory MCP tools to create thread `mcp_demo_thread` for user `user_123`, "
    "add the durable memory `The user likes orange juice with breakfast.`, and confirm "
    "when the memory is stored."
)
first_session.execute()
print(first_session.get_last_message().content)

second_session = agent.start_conversation()
second_session.append_user_message(
    "Search memory for `orange juice` in thread `mcp_demo_thread` and tell me what "
    "Oracle Agent Memory returned."
)
second_session.execute()
print(second_session.get_last_message().content)

Sortie :

The durable memory has been stored successfully:
-Thread ID: `mcp_demo_thread`
-User ID: `user_123`

The memory search returned matching records for:
"The user likes orange juice with breakfast."

Notes sur la sécurité et le déploiement

L'exemple de serveur est intentionnellement ouvert et local uniquement. Pour une utilisation en production, ajoutez l'authentification et la sécurité de transport, limitez les utilisateurs ou agents auxquels chaque appelant est autorisé à accéder, et envisagez d'ajouter des portes de confirmation ou d'approbation autour des opérations d'écriture telles que add_memory ou add_messages.

Pour plus d'informations, reportez-vous à Remarques concernant la sécurité.

Conclusion

Dans cet article, vous avez appris à exposer la mémoire de l'agent Oracle via MCP et à réutiliser la même surface d'outils de LangGraph et de WayFlow.

A savoir : Vous ne pouvez ajouter d'autres outils de mémoire que si vos workflows d'agent en ont besoin. Reportez-vous à Exemples de code de référence rapide. Pour adapter le serveur à votre environnement de déploiement et aux contraintes opérationnelles, reportez-vous à Exécution locale d'Oracle AI Database.

Code complet

Serveur MCP

#Copyright © 2026 Oracle and/or its affiliates.
#This software is under the Apache License 2.0
#(LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or Universal Permissive License
#(UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl), at your option.

#Oracle Agent Memory Code Example - Integration with MCP Server
#--------------------------------------------------------------

#How to use:
#Create a new Python virtual environment and install the latest oracleagentmemory version.

#You can now run the script
#1. As a Python file:
#```bash
#python integration_with_mcp_server.py
#```
#2. As a Notebook (in VSCode):
#When viewing the file,
#- press the keys Ctrl + Enter to run the selected cell
#- or Shift + Enter to run the selected cell and move to the cell below

##Build the MCP server

#%%
import json
import os
from typing import Any

from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel

from oracleagentmemory.core.dbschemapolicy import SchemaPolicy
from oracleagentmemory.core.embedders.embedder import Embedder
from oracleagentmemory.core.llms.llm import Llm
from oracleagentmemory.core.oracleagentmemory import OracleAgentMemory

embedder = Embedder(
    model="YOUR_EMBEDDING_MODEL",
    api_base="YOUR_EMBEDDING_API_BASE",
    api_key="YOUR_EMBEDDING_API_KEY",
)
llm = Llm(
    model="YOUR_LLM_MODEL",
    api_base="YOUR_LLM_API_BASE",
    api_key="YOUR_LLM_API_KEY",
)
db_pool = ...  #an oracledb connection or connection pool


class MessageT(BaseModel):
    role: str
    content: str
    id: str | None = None
    timestamp: str | None = None
    metadata: dict[str, Any] | None = None


def create_server(
    memory: OracleAgentMemory | None = None,
    host: str | None = None,
    port: int | None = None,
    path: str | None = None,
) -> FastMCP:
    """Create a FastMCP server exposing Oracle Agent Memory tools."""
    agent_memory = memory or OracleAgentMemory(
        connection=db_pool,
        embedder=embedder,
        llm=llm,
        schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
    )
    resolved_path = path or os.environ.get("MEMORY_MCP_PATH", "/mcp")
    if not resolved_path.startswith("/"):
        resolved_path = f"/{resolved_path}"
    server = FastMCP(
        name="Oracle Agent Memory MCP Server",
        host=host or os.environ.get("MEMORY_MCP_HOST", "localhost"),
        port=int(port if port is not None else os.environ.get("MEMORY_MCP_PORT", "8003")),
        streamable_http_path=resolved_path,
    )

    @server.tool(
        description=(
            "Get an existing thread by thread_id, or create one from user_id and optional "
            "agent_id."
        )
    )
    def get_or_create_thread(
        thread_id: str | None = None,
        user_id: str | None = None,
        agent_id: str | None = None,
    ) -> str:
        create_kwargs: dict[str, str] = {}
        if thread_id is not None:
            try:
                thread = agent_memory.get_thread(thread_id)
                return json.dumps(
                    {
                        "thread_id": thread.thread_id,
                        "user_id": thread.user_id,
                        "agent_id": thread.agent_id,
                    }
                )
            except KeyError:
                create_kwargs["thread_id"] = thread_id
        if user_id is not None:
            create_kwargs["user_id"] = user_id
        if agent_id is not None:
            create_kwargs["agent_id"] = agent_id
        thread = agent_memory.create_thread(**create_kwargs)
        return json.dumps(
            {
                "thread_id": thread.thread_id,
                "user_id": thread.user_id,
                "agent_id": thread.agent_id,
            }
        )

    @server.tool(
        description=(
            "Add durable memory content, optionally scoped by user_id, agent_id, and "
            "thread_id."
        )
    )
    def add_memory(
        content: str,
        user_id: str | None = None,
        agent_id: str | None = None,
        thread_id: str | None = None,
    ) -> str:
        add_kwargs: dict[str, str] = {}
        if user_id is not None:
            add_kwargs["user_id"] = user_id
        if agent_id is not None:
            add_kwargs["agent_id"] = agent_id
        if thread_id is not None:
            add_kwargs["thread_id"] = thread_id
        return json.dumps({"memory_id": agent_memory.add_memory(content, **add_kwargs)})

    @server.tool(
        description="Add messages to an existing thread using messages and thread_id."
    )
    def add_messages(messages: list[MessageT], thread_id: str) -> str:
        thread = agent_memory.get_thread(thread_id)
        payload = [message.model_dump(exclude_none=True) for message in messages]
        return json.dumps({"message_ids": thread.add_messages(payload)})

    @server.tool(description="Get messages from an existing thread using thread_id.")
    def get_messages(thread_id: str) -> str:
        thread = agent_memory.get_thread(thread_id)
        return json.dumps(
            {
                "messages": [
                    {
                        "id": getattr(message, "id", None),
                        "role": message.role,
                        "content": message.content,
                        "timestamp": message.timestamp,
                        "metadata": message.metadata,
                    }
                    for message in thread.get_messages()
                ]
            }
        )

    @server.tool(
        description=(
            "Search Oracle Agent Memory for durable memory and thread content. "
            "Pass user_id directly, or pass thread_id so the server can resolve the user scope."
        )
    )
    def search_memory(
        query: str,
        user_id: str | None = None,
        agent_id: str | None = None,
        thread_id: str | None = None,
    ) -> str:
        if user_id is not None:
            resolved_user_id = user_id
            resolved_agent_id = agent_id
        elif thread_id is not None:
            thread = agent_memory.get_thread(thread_id)
            if thread.user_id is None:
                raise ValueError(
                    f"Thread `{thread_id}` is not associated with a user_id, so "
                    "search_memory cannot build a valid OracleAgentMemory search scope."
                )
            resolved_user_id = thread.user_id
            resolved_agent_id = agent_id if agent_id is not None else thread.agent_id
        else:
            raise ValueError("search_memory requires either `user_id` or `thread_id`.")
        search_kwargs: dict[str, Any] = {"query": query, "user_id": resolved_user_id}
        if resolved_agent_id is not None:
            search_kwargs["agent_id"] = resolved_agent_id
            search_kwargs["exact_agent_match"] = True
        if thread_id is not None:
            search_kwargs["thread_id"] = thread_id
            search_kwargs["exact_thread_match"] = True
        results = agent_memory.search(**search_kwargs)
        return json.dumps(
            {
                "results": [
                    {
                        "id": result.id,
                        "content": result.content,
                        "record_type": result.record.record_type,
                        "user_id": result.record.user_id,
                        "agent_id": result.record.agent_id,
                        "thread_id": result.record.thread_id,
                    }
                    for result in results
                ]
            }
        )

    return server


##Run the MCP server

#%%
def main() -> None:
    server = create_server()
    server.run(transport="streamable-http")


if __name__ == "__main__":
    main()

Client LangGraph

#Copyright © 2026 Oracle and/or its affiliates.
#This software is under the Apache License 2.0
#(LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or Universal Permissive License
#(UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl), at your option.
#Oracle Agent Memory Code Example - LangGraph MCP Client
#-------------------------------------------------------

#How to use:
#Create a new Python virtual environment and install the latest oracleagentmemory version.

#You can now run the script
#1. As a Python file:
#```bash
#python integration_with_mcp_langgraph.py
#```
#2. As a Notebook (in VSCode):
#When viewing the file,
#- press the keys Ctrl + Enter to run the selected cell
#- or Shift + Enter to run the selected cell and move to the cell below

##Connect LangGraph to the MCP server

#%%
import os
from datetime import timedelta

import anyio
from langchain.agents import create_agent
from langchain_core.messages import HumanMessage
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_openai import ChatOpenAI

mcp_url = os.environ.get("MEMORY_MCP_URL", "http://localhost:8003/mcp")

langgraph_llm = ChatOpenAI(
    model="gpt-4.1-mini",
    api_key="YOUR_OPENAI_API_KEY",
)


async def build_langgraph_agent():
    memory_tools = await MultiServerMCPClient(
        {
            "memory": {
                "transport": "streamable_http",
                "url": mcp_url,
                "timeout": timedelta(seconds=30),
                "sse_read_timeout": timedelta(seconds=30),
            }
        }
    ).get_tools()
    return create_agent(
        model=langgraph_llm,
        tools=memory_tools,
        system_prompt=(
            "You are an assistant using Oracle Agent Memory through MCP. "
            "Create threads before writing messages, use add_memory for durable facts, "
            "and call search_memory when the user asks about prior context."
        ),
    )


##Use the MCP server from LangGraph

#%%
async def run_langgraph_agent() -> None:
    agent = await build_langgraph_agent()
    first_turn = await agent.ainvoke(
        {
            "messages": [
                HumanMessage(
                    content=(
                        "Use the memory MCP tools to create thread `mcp_demo_thread` for user "
                        "`user_123`, add the durable memory `The user likes orange juice with "
                        "breakfast.`, and confirm when the memory is stored."
                    )
                )
            ]
        }
    )
    print(first_turn["messages"][-1].content)
    #The durable memory has been stored successfully:
    #- Thread ID: `mcp_demo_thread`
    #- User ID: `user_123`

    second_turn = await agent.ainvoke(
        {
            "messages": [
                HumanMessage(
                    content=(
                        "Search memory for `orange juice` in thread `mcp_demo_thread` and tell "
                        "me what Oracle Agent Memory returned."
                    )
                )
            ]
        }
    )
    print(second_turn["messages"][-1].content)
    #The search returned matching memory records for:
    #"The user likes orange juice with breakfast."

anyio.run(run_langgraph_agent)

Client WayFlow

#Copyright © 2026 Oracle and/or its affiliates.
#This software is under the Apache License 2.0
#(LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or Universal Permissive License
#(UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl), at your option.

#Oracle Agent Memory Code Example - WayFlow MCP Client
#-----------------------------------------------------

#How to use:
#Create a new Python virtual environment and install the latest oracleagentmemory version.

#You can now run the script
#1. As a Python file:
#```bash
#python integration_with_mcp_wayflow.py
#```
#2. As a Notebook (in VSCode):
#When viewing the file,
#- press the keys Ctrl + Enter to run the selected cell
#- or Shift + Enter to run the selected cell and move to the cell below

##Connect WayFlow to the MCP server

#%%
import os

from wayflowcore.agent import Agent
from wayflowcore.mcp import MCPToolBox, StreamableHTTPTransport, enable_mcp_without_auth
from wayflowcore.models import OpenAICompatibleModel

mcp_url = os.environ.get("MEMORY_MCP_URL", "http://localhost:8003/mcp")

wayflow_llm = OpenAICompatibleModel(
    model_id="gpt-4.1-mini",
    base_url="YOUR_OPENAI_API_BASE",
    api_key="YOUR_OPENAI_API_KEY",
)

enable_mcp_without_auth()
memory_tools = MCPToolBox(client_transport=StreamableHTTPTransport(url=mcp_url))
agent = Agent(
    llm=wayflow_llm,
    agent_id="memory_mcp_agent",
    custom_instruction=(
        "You are an assistant using Oracle Agent Memory through MCP. "
        "Create threads before writing messages, use add_memory for durable facts, "
        "and call search_memory when the user asks about prior context."
    ),
    tools=[memory_tools],
)


##Use the MCP server from WayFlow

#%%
first_session = agent.start_conversation()
first_session.append_user_message(
    "Use the memory MCP tools to create thread `mcp_demo_thread` for user `user_123`, "
    "add the durable memory `The user likes orange juice with breakfast.`, and confirm "
    "when the memory is stored."
)
first_session.execute()
print(first_session.get_last_message().content)
#The durable memory has been stored successfully:
#- Thread ID: `mcp_demo_thread`
#- User ID: `user_123`

second_session = agent.start_conversation()
second_session.append_user_message(
    "Search memory for `orange juice` in thread `mcp_demo_thread` and tell me what "
    "Oracle Agent Memory returned."
)
second_session.execute()
print(second_session.get_last_message().content)
#The memory search returned matching records for:
#"The user likes orange juice with breakfast."