{
  "schema_version": 2,
  "id": "develop/ai/context-engine/agent-memory/mcp",
  "title": "Connect with MCP",
  "url": "https://redis.io/docs/latest/develop/ai/context-engine/agent-memory/mcp/",
  "summary": "Connect an MCP client to a Redis Agent Memory store to search, curate, and ingest long-term memories.",
  "tags": [
    "docs",
    "develop",
    "ai"
  ],
  "last_updated": "2026-11-03T10:02:56-08:00",
  "page_type": "content",
  "content_hash": "a86c11d26560298f83ffa66bb8b5122bced05d139236baa20ef0417a6d95eca4",
  "sections": [
    {
      "id": "code-examples",
      "title": "Code examples",
      "role": "example",
      "text": "These examples connect to Iris services using SDKs or HTTP requests with curl. Follow one language throughout each walkthrough.\n\n\nEvery Redis Agent Memory store serves a [Model Context Protocol](https://modelcontextprotocol.io) (MCP) endpoint. Connect an MCP client to let an agent search and curate long-term memories and submit documents for extraction without writing API calls.\n\nThe MCP tools cover long-term memory and document ingestion. Session memory is not exposed, because the application that owns the conversation writes its events. Use the [SDK or REST API](https://redis.io/docs/latest/develop/ai/context-engine/agent-memory/sessions) for sessions."
    },
    {
      "id": "before-you-begin",
      "title": "Before you begin",
      "role": "content",
      "text": "Get the data-plane endpoint, store ID, and an API key with write access to the store. The MCP endpoint requires write access for every tool, including search. Save and load the `IRIS_AGENT_MEMORY_*` variables as shown in [Save the connection values](https://redis.io/docs/latest/develop/ai/context-engine/agent-memory/quickstart#connect-to-the-service).\n\nFor the Python client, use Python 3.10 or later and install these dependencies:\n\n**Python**\n\n[code example]\n\n**HTTP**\n\n[code example]"
    },
    {
      "id": "configure-the-connection",
      "title": "Configure the connection",
      "role": "configuration",
      "text": "Use a client that supports Streamable HTTP and custom request headers:\n\n| Setting | Value |\n|:--------|:------|\n| Transport | Streamable HTTP |\n| Endpoint | `<data-plane-base-url>/iris/data/v1/agent-memory/stores/<store-id>/mcp` |\n| Request header | `Authorization: Bearer <api-key>` |\n\nThe server is stateless and returns JSON responses, so clients do not need to keep an MCP session open between calls. The endpoint must be reachable from the client runtime. A hosted client needs an HTTPS endpoint reachable from its provider. Keep the API key in connection settings and out of agent instructions.\n\nOn a self-managed deployment with ownership enforcement, use a delegated or user-bound token as described in [Authentication](https://redis.io/docs/latest/operate/iris/agent-memory/self-managed/authentication). The tools enforce the same ownership rules as the REST API."
    },
    {
      "id": "use-the-tools",
      "title": "Use the tools",
      "role": "content",
      "text": "Call `tools/list` on an initialized connection to get the input schemas. Tool arguments use `snake_case` names, such as `owner_id` and `namespace_id`, rather than the REST API's `camelCase` fields.\n\n| Tool | Use it to |\n|:-----|:----------|\n| `search_long_term_memory` | Search by `text`, or filter by `owner_id`, `namespace_id`, `session_id`, `memory_type`, and `topics`. Text results rank by similarity; filter-only results can sort by `createdAt` or `updatedAt`. |\n| `create_long_term_memories` | Store 1–100 new memories, each with a client-supplied `id` and required `owner_id`. An existing ID is reported in `errors` and left unchanged. |\n| `edit_long_term_memory` | Change only the provided fields of one memory. Changing `text` re-embeds the memory. |\n| `upsert_long_term_memory` | Create or fully replace one memory, including custom `attributes`. Omitted optional fields reset to their defaults. |\n| `delete_long_term_memories` | Delete 1–100 memories by ID. |\n| `create_document_ingestion` | Submit one base64-encoded `text/plain` or `text/markdown` document for [MemoryETL](https://redis.io/docs/latest/develop/ai/context-engine/agent-memory/memory-etl) extraction with an enabled extractor. |\n| `get_document_ingestion` | Check processing progress and source cleanup for an ingestion. |\n| `list_document_ingestion_outputs` | Page through the memory IDs an ingestion produced. |\n| `list_memory_sources`, `list_memory_source_evidence`, `list_source_memories` | Trace a memory to its sources and evidence, or list the memories linked to a source. |\n\n`edit_long_term_memory` and `upsert_long_term_memory` accept `expected_revision` to apply a change only when the memory's `revision` is current. The write tools accept `idempotency_key` so a retry replays the original result instead of writing twice."
    },
    {
      "id": "connect-a-client",
      "title": "Connect a client",
      "role": "content",
      "text": "This client connects, lists the tools, creates a memory, searches for it, and then deletes it.\n\nCopy the complete program and save it as `mcp_client.py` or `mcp_client.sh`. Run `python mcp_client.py` or `bash mcp_client.sh` with the connection values you exported.\n\n**Available in:** Python (Iris), cURL (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n\n\nExpect the tool names, followed by the created memory ID, a search result that contains the memory, and the deleted memory ID. A request or tool error stops the program with an error."
    },
    {
      "id": "troubleshoot-the-connection",
      "title": "Troubleshoot the connection",
      "role": "errors",
      "text": "- If the connection fails, check the full endpoint, network reachability, and API key. A `403` means the key lacks write access to the store.\n- If a tool result has `isError` set, read its content before using the result. Connection and transport failures raise separately.\n- If a search returns nothing for a new memory, check `owner_id` and other filters. Memories created by extraction appear only after background processing.\n\nKeep diagnostic details without logging keys or private content."
    }
  ],
  "examples": [
    {
      "id": "before-you-begin-ex0",
      "language": "bash",
      "code": "python -m pip install mcp==2.3.0 httpx2==2.13.1",
      "section_id": "before-you-begin"
    },
    {
      "id": "before-you-begin-ex1",
      "language": "bash",
      "code": "curl --version\njq --version",
      "section_id": "before-you-begin"
    },
    {
      "id": "connect-a-client-ex0",
      "language": "python",
      "code": "import asyncio\nimport json\nimport os\nfrom uuid import uuid4\n\nimport httpx2\nfrom mcp import Client\nfrom mcp.client.streamable_http import streamable_http_client\n\nOWNER_ID = \"mcp-quickstart-user\"\n\n\ndef read_result(result):\n    if result.is_error:\n        raise RuntimeError(f\"Agent Memory tool failed: {result.content}\")\n    if result.structured_content is not None:\n        return result.structured_content\n    return json.loads(next(block.text for block in result.content if block.type == \"text\"))\n\n\nasync def main():\n    url = (\n        f\"{os.environ['IRIS_AGENT_MEMORY_URL'].rstrip('/')}\"\n        f\"/iris/data/v1/agent-memory/stores/{os.environ['IRIS_AGENT_MEMORY_STORE_ID']}/mcp\"\n    )\n    memory_id = f\"mcp-example-{uuid4().hex[:12]}\"\n    async with httpx2.AsyncClient(\n        headers={\"Authorization\": f\"Bearer {os.environ['IRIS_AGENT_MEMORY_API_KEY']}\"}\n    ) as http:\n        async with Client(streamable_http_client(url, http_client=http)) as client:\n            print(\"Tools:\", [tool.name for tool in (await client.list_tools()).tools])\n\n            created = await client.call_tool(\n                \"create_long_term_memories\",\n                {\n                    \"idempotency_key\": str(uuid4()),\n                    \"memories\": [\n                        {\n                            \"id\": memory_id,\n                            \"text\": \"The user prefers aisle seats on long flights.\",\n                            \"owner_id\": OWNER_ID,\n                            \"topics\": [\"travel\"],\n                        }\n                    ],\n                },\n            )\n            print(json.dumps(read_result(created), indent=2))\n\n            found = await client.call_tool(\n                \"search_long_term_memory\",\n                {\"text\": \"Which seat does the user like?\", \"owner_id\": OWNER_ID, \"limit\": 3},\n            )\n            print(json.dumps(read_result(found), indent=2))\n\n            deleted = await client.call_tool(\n                \"delete_long_term_memories\", {\"memory_ids\": [memory_id]}\n            )\n            print(json.dumps(read_result(deleted), indent=2))\n\n\nasyncio.run(main())",
      "section_id": "connect-a-client"
    },
    {
      "id": "connect-a-client-ex1",
      "language": "bash",
      "code": "set -euo pipefail\nMCP_URL=\"${IRIS_AGENT_MEMORY_URL%/}/iris/data/v1/agent-memory/stores/$IRIS_AGENT_MEMORY_STORE_ID/mcp\"\nPROTOCOL_VERSION=2025-11-25\nOWNER_ID=mcp-quickstart-user\nMEMORY_ID=\"mcp-example-$(openssl rand -hex 6)\"\n\npost() {\n  curl --fail-with-body --silent --show-error \"$MCP_URL\" \\\n    -H \"Authorization: Bearer $IRIS_AGENT_MEMORY_API_KEY\" \\\n    -H 'Content-Type: application/json' \\\n    -H 'Accept: application/json, text/event-stream' \\\n    -H \"MCP-Protocol-Version: $PROTOCOL_VERSION\" \\\n    --data-binary \"$1\"\n}\n\nrpc() {\n  local request response\n  request=$(jq -n --arg method \"$1\" --argjson params \"$2\" --argjson id \"$3\" \\\n    '{jsonrpc: \"2.0\", id: $id, method: $method, params: $params}') || return $?\n  response=$(post \"$request\") || return $?\n  jq -e '\n    if .error then error(\"MCP request failed: \" + .error.message)\n    elif .result.isError then error(\"Agent Memory tool failed: \" + (.result.content | tostring))\n    elif has(\"result\") | not then error(\"MCP response has no result\")\n    else .result end\n  ' <<< \"$response\"\n}\n\nread_result() {\n  jq -e '.structuredContent // ([.content[] | select(.type == \"text\")][0].text | fromjson)'\n}\n\nINITIALIZED=$(rpc initialize '{\n  \"protocolVersion\": \"2025-11-25\",\n  \"capabilities\": {},\n  \"clientInfo\": {\"name\": \"agent-memory-curl-example\", \"version\": \"1.0.0\"}\n}' 1)\nPROTOCOL_VERSION=$(jq -er '.protocolVersion' <<< \"$INITIALIZED\")\npost '{\"jsonrpc\":\"2.0\",\"method\":\"notifications/initialized\"}' > /dev/null\nrpc tools/list '{}' 2 | jq -r '.tools[].name'\n\nrpc tools/call \"$(jq -n --arg id \"$MEMORY_ID\" --arg owner \"$OWNER_ID\" --arg key \"$(uuidgen)\" '{\n  name: \"create_long_term_memories\",\n  arguments: {idempotency_key: $key, memories: [{\n    id: $id, text: \"The user prefers aisle seats on long flights.\",\n    owner_id: $owner, topics: [\"travel\"]\n  }]}\n}')\" 3 | read_result\n\nrpc tools/call \"$(jq -n --arg owner \"$OWNER_ID\" '{\n  name: \"search_long_term_memory\",\n  arguments: {text: \"Which seat does the user like?\", owner_id: $owner, limit: 3}\n}')\" 4 | read_result\n\nrpc tools/call \"$(jq -n --arg id \"$MEMORY_ID\" '{\n  name: \"delete_long_term_memories\", arguments: {memory_ids: [$id]}\n}')\" 5 | read_result",
      "section_id": "connect-a-client"
    }
  ]
}
