How to Use MCP (Model Context Protocol) with Oracle AI Agent Memory

MCP (Model Context Protocol) enables LLMs to invoke Python functions as standardized tools, allowing agents to read from and write to Oracle AI Agent Memory for persistent, cross-session context.

The Model Context Protocol (MCP) defines a JSON-RPC interface that bridges generative AI models with external capabilities. In the oracle-devrel/oracle-ai-developer-hub repository, MCP connects Claude Agent SDK-based agents to Oracle AI Agent Memory (OAMP), transforming ephemeral conversations into durable, searchable knowledge bases that survive agent restarts.

Understanding the MCP Architecture for OAMP

MCP creates a standardized contract between the LLM and your business logic. When using MCP with Oracle AI Agent Memory, four core components work together to enable memory-aware agents.

The @tool Decorator

The Claude Agent SDK provides the @tool decorator to convert regular Python functions into MCP-compatible endpoints. These functions must accept a dictionary of arguments and return content in the MCP content format:

{"content": [{"type": "text", "text": "result here"}]}

In notebooks/agent_memory/02_supply_chain_claude_agent_sdk.ipynb, tools like list_shipments and recall_operational_notes are defined using this decorator (lines 95-165).

The MCP Server Wrapper

The create_sdk_mcp_server function bundles multiple @tool-decorated functions into a lightweight HTTP-style server that speaks MCP. This server registers with the agent under a specific name, such as supply-chain or demo, which forms part of the tool invocation pattern.

Oracle AI Agent Memory Integration

The oracleagentmemory package exposes memory_client.add_memory() and memory_client.search() methods. These allow tools to persist facts to Oracle AI Database and perform semantic retrieval across sessions. The vector store and document store reside on Oracle AI Database, ensuring durability and scalability.

Agent Runtime Execution

The ClaudeSDKClient orchestrates the interaction loop. When the model decides it needs external data, it emits a tool call request (e.g., mcp__sc__list_shipments). The runtime forwards this to the MCP server, executes the Python function, and injects the returned text back into the LLM's prompt window.

Implementing Memory-Aware MCP Tools

To build tools that interact with Oracle AI Agent Memory, you define asynchronous functions that handle both storage and retrieval patterns.

Writing Memory with add_memory

Tools that persist operational state use memory_client.add_memory() to store facts with metadata. As shown in the Supply-Chain Assistant example (lines 36-42 in 02_supply_chain_claude_agent_sdk.ipynb), the update_shipment tool records durable facts about shipment status, making the information available to future sessions.

Searching Memory with Semantic Retrieval

Recall tools use memory_client.search() to perform vector similarity searches. The recall_operational_notes tool demonstrates this pattern (lines 56-62), allowing the agent to retrieve relevant historical context based on semantic similarity rather than exact keyword matches.

Step-by-Step: Building a Memory-Augmented Agent

Follow these steps to implement MCP with Oracle AI Agent Memory in your Python environment.

1. Install Dependencies

Install the required packages including oracleagentmemory, claude-agent-sdk, and nest_asyncio:


# 1️⃣ Install required packages (run once)

# %pip install -q "oracleagentmemory[litellm]" claude-agent-sdk nest_asyncio

2. Initialize the Memory Client

Connect to Oracle AI Database and instantiate the memory client with embedding and LLM configurations:

import os, oracledb
from oracleagentmemory.core import OracleAgentMemory
from oracleagentmemory.core.llms import Llm

conn = oracledb.connect(
    user=os.getenv("DB_USER", "VECTOR"),
    password=os.getenv("DB_PASSWORD", "VectorPwd_2025"),
    dsn=os.getenv("DB_CONNECT_STRING", "localhost:1521/FREEPDB1"),
)

extract_llm = Llm("gpt-4o-mini", temperature=0.2)
memory = OracleAgentMemory(
    connection=conn,
    embedder="text-embedding-3-small",
    llm=extract_llm,
    extract_memories=True,
    schema_policy="create_if_necessary",
    table_name_prefix="demo_",
)

3. Define MCP Tools

Create functions decorated with @tool that interact with the memory client. Each tool must return content in the MCP format:

from claude_agent_sdk import tool

@tool(
    "add_fact",
    "Persist a short fact string in Agent Memory for later retrieval.",
    {"fact": str},
)
async def add_fact(args: dict) -> dict:
    fact = args["fact"]
    memory.add_memory(
        fact,
        user_id="demo_user",
        agent_id="demo_agent",
        metadata={"kind": "fact"},
    )
    return {"content": [{"type": "text", "text": f"Fact stored: {fact}"}]}

@tool(
    "search_facts",
    "Semantic search for facts previously stored.",
    {"query": str, "max_results": int},
)
async def search_facts(args: dict) -> dict:
    results = memory.search(
        args["query"], 
        user_id="demo_user", 
        agent_id="demo_agent",
        max_results=args.get("max_results", 5),
    )
    if not results:
        return {"content": [{"type": "text", "text": "(no facts found)"}]}
    lines = [f"- {r.content} [dist={r.distance:.3f}]" for r in results]
    return {"content": [{"type": "text", "text": "\n".join(lines)}]}

4. Create and Register the MCP Server

Bundle your tools into an MCP server and register it with the agent using ClaudeAgentOptions. Note the mcp__{server}__{tool} naming convention in the allowlist:

from claude_agent_sdk import create_sdk_mcp_server, ClaudeAgentOptions, ClaudeSDKClient

# Wrap tools in MCP server

demo_server = create_sdk_mcp_server(
    name="demo",
    tools=[add_fact, search_facts],
)

# Configure agent to use the MCP server

options = ClaudeAgentOptions(
    system="You are a helpful assistant that can store and recall facts via MCP.",
    mcp_servers=[demo_server],
    tool_allowlist=[
        "mcp__demo__add_fact", 
        "mcp__demo__search_facts"
    ],
)

5. Execute Memory-Enabled Conversations

Run the agent. The model automatically invokes add_fact when it needs to store information and search_facts when it needs to retrieve context:

client = ClaudeSDKClient(options=options)

# Store a fact

resp1 = client.chat("Remember that the Office is on the 3rd floor.")
print(resp1.message)

# Retrieve the fact

resp2 = client.chat("What did I say about the Office location?")
print(resp2.message)

Key Implementation Details from the Supply-Chain Assistant

The 02_supply_chain_claude_agent_sdk.ipynb notebook demonstrates production patterns for MCP with OAMP:

  • Tool Definitions: Lines 95-165 define list_shipments, get_shipment_status, update_shipment, and recall_operational_notes using the @tool decorator
  • MCP Server Creation: Lines 95-99 bundle these tools under the server name supply-chain using create_sdk_mcp_server
  • Agent Configuration: Lines 108-112 show ClaudeAgentOptions configuration with the mcp__sc__* naming pattern in the allowlist
  • Memory Operations: Lines 36-42 demonstrate memory_client.add_memory() for persistence, while lines 56-62 show memory_client.search() for semantic recall

Summary

  • MCP standardizes tool invocation between LLMs and Python functions through a JSON-RPC interface
  • The @tool decorator converts async functions into MCP-compatible endpoints that must return {"content": [...]} format
  • Oracle AI Agent Memory provides durable vector storage via add_memory() and semantic search via search()
  • The naming convention mcp__{server_name}__{tool_name} maps LLM tool calls to specific Python functions
  • Memory-augmented agents maintain low token budgets by retrieving only relevant context rather than full conversation history

Frequently Asked Questions

What is the exact naming convention for MCP tools in ClaudeAgentOptions?

Tools follow the pattern mcp__{server_name}__{tool_name}. For example, if you create a server named demo with a tool named add_fact, you must include mcp__demo__add_fact in the tool_allowlist of ClaudeAgentOptions. This convention enables the ClaudeSDKClient to route tool calls from the LLM to the correct Python function.

How does Oracle AI Agent Memory persist data across agent restarts?

Oracle AI Agent Memory stores data in Oracle AI Database using the OracleAgentMemory class. When you call memory_client.add_memory(), the system writes to a persistent vector store and document store on the database. Because the memory resides in Oracle AI Database rather than in-memory Python objects, the data survives agent restarts, container redeployments, and is accessible across multiple concurrent sessions using the same user_id and agent_id.

What format must MCP tool functions return to be compatible with the Claude Agent SDK?

MCP tools must return a dictionary containing a content key with a list of content blocks. For text responses, use {"content": [{"type": "text", "text": "your result here"}]}. This standardized format allows the ClaudeSDKClient to inject the tool result back into the LLM's prompt window as part of the conversation context.

Can I use multiple MCP servers with a single Claude Agent?

Yes. The ClaudeAgentOptions class accepts a list of servers via the mcp_servers parameter. You can create multiple servers using create_sdk_mcp_server(), each with its own set of tools, and pass them all to the options object. Ensure that each tool name in your tool_allowlist uses the correct mcp__{server_name}__{tool_name} prefix to avoid naming collisions between servers.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →