# LangChain

> LangChain integration example.

Canonical page: https://xmemory.ai/langchain/

This guide shows how to use xmemory as a persistent memory layer for a [LangChain](https://python.langchain.com/) agent. Two approaches are covered:

- **MCP** — connect LangChain to the xmemory MCP server via `langchain-mcp-adapters`; the agent gets `write` and `read` tools automatically.
- **HTTP API** — call the REST API directly from custom LangChain tools; useful when you want full control.

**API key:** To use xmemory APIs or integrations, you need an API key. Get one from the [xmemory console](https://console.xmemory.ai). Copy and securely store the key. Never share your API key publicly.

---

## Prerequisites

```bash
pip install langchain langchain-anthropic xmemory-ai pyyaml
```

For the MCP approach (Part 3), also install:

```bash
pip install langchain-mcp-adapters
```

---

## Part 1 — Create an instance

xmemory stores data in typed *instances*. Each instance has a schema that describes the objects and relations you want to track. Describe what you want to remember in plain language — xmemory generates a typed schema from that free-text description and returns it ready for instance creation.

The schema is [XMD](https://xmemory.ai/xmd/). An agent may author it directly for exact control or use the
natural-language generator to save time, then review or tune extraction behaviour with the guide.

This is a one-time setup script. Save the returned instance ID (e.g. in an environment variable) and reuse it in your agent.

```python
import os
import yaml
from xmemory import XmemoryClient, SchemaType

API_KEY = os.environ["XMEM_API_KEY"]

# 1. Connect and pick a cluster
client = XmemoryClient(api_key=API_KEY)
clusters = client.admin.list_clusters()
cluster_id = clusters[0].id

# 2. Generate a schema from a plain-language description
schema_response = client.admin.generate_schema(
    cluster_id,
    "Track contacts with name, email, company, and notes.",
)

# 3. Create the instance
inst = client.admin.create_instance(
    cluster_id=cluster_id,
    name="contacts",
    schema_text=yaml.dump(schema_response.data_schema, allow_unicode=True),
    schema_type=SchemaType.YML,
)
print(f"Created instance: {inst.id}")
# → store this in INSTANCE_ID and reuse it on subsequent runs
```

The instance ID is a UUID string. Keep it — you'll use it to get an instance handle on subsequent runs.

---

## Part 2 — Agent with custom xmemory tools (HTTP API)

Wrap `write` and `read` as LangChain tools so the agent can store and recall information during a conversation.

```python
import asyncio
import os
from langchain.agents import create_agent
from langchain_core.tools import tool
from xmemory import XmemoryClient

API_KEY = os.environ["XMEM_API_KEY"]
INSTANCE_ID = os.environ["XMEM_INSTANCE_ID"]  # from Part 1

client = XmemoryClient(api_key=API_KEY)
inst = client.instance(INSTANCE_ID)

@tool
def remember(text: str) -> str:
    """Store information in long-term memory."""
    # Sync write so a follow-up `recall` sees it immediately. In production,
    # prefer inst.write_async(text) for fire-and-forget writes you won't read
    # back right away, then poll inst.write_status(write_id) if you need to.
    result = inst.write(text)
    return f"Stored (write_id={result.write_id})."

@tool
def recall(query: str) -> str:
    """Retrieve information from long-term memory."""
    result = inst.read(query)
    return result.reader_result.get("answer", str(result.reader_result))

agent = create_agent(
    "anthropic:claude-sonnet-4-6",
    tools=[remember, recall],
    system_prompt=(
        "You are a helpful assistant with access to a persistent memory store. "
        "Use `remember` to save new information and `recall` to look things up."
    ),
)

async def main():
    # Store something
    result = await agent.ainvoke(
        {"messages": "Remember that Alice Johnson works at Acme Corp, her email is alice@acme.com."}
    )
    print(result["messages"][-1].content)

    # Recall it later
    result = await agent.ainvoke(
        {"messages": "What do you know about Alice?"}
    )
    print(result["messages"][-1].content)

if __name__ == "__main__":
    asyncio.run(main())
```

### Read modes

The `read` method supports three modes via `read_mode`:

| `read_mode` | `reader_result` shape | When to use |
|---|---|---|
| `"single-answer"` | `{"answer": "..."}` | Natural-language question → plain text answer |
| `"xresponse"` | `{"objects": [...], "relations": [...]}` | Get structured objects back |
| `"raw-tables"` | `{"columns": [{"name": ..., "type": ...}], "rows": [[...]]}`, or `None` when nothing matched | Raw SQL result sets |

---

## Part 3 — MCP approach (fewer lines of code)

LangChain supports MCP servers via the [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters) package. The xmemory MCP server exposes `write` and `read` (and more) as ready-made tools — no boilerplate needed.

### Authentication

This headless flow sends your account **API key** directly as the Bearer token on the `/instance/<instance_id>` shortcut path — no OAuth exchange needed. The instance is bound by the **URL path**, so you don't pass `instance_id` explicitly in tool calls. See the [MCP guide](https://xmemory.ai/mcp/#authentication) for the other connection options.

```python
import asyncio
import os
from langchain.agents import create_agent
from langchain_mcp_adapters.client import MultiServerMCPClient

API_KEY = os.environ["XMEM_API_KEY"]
INSTANCE_ID = os.environ["XMEM_INSTANCE_ID"]  # from Part 1

client = MultiServerMCPClient(
    {
        "xmemory": {
            "transport": "http",
            "url": f"https://mcp.xmemory.ai/instance/{INSTANCE_ID}",
            "headers": {
                "Authorization": f"Bearer {API_KEY}",
            },
        },
    }
)

async def main():
    tools = await client.get_tools()
    agent = create_agent(
        "anthropic:claude-sonnet-4-6",
        tools=tools,
        system_prompt=(
            "You have access to a persistent memory store via the xmemory tools. "
            "Use `write` to remember things and `read` to look them up."
        ),
    )

    result = await agent.ainvoke(
        {"messages": "Remember that Bob Smith is a senior engineer at Globex. "
         "Then tell me what you know about Bob."}
    )
    print(result["messages"][-1].content)

if __name__ == "__main__":
    asyncio.run(main())
```

#### Available MCP tools (instance connection type)

The instance connection exposes 10 default tools — 7 bound (`get_instance_id`, `get_instance_schema`, `get_setup_instructions`, `write`, `write_async`, `write_status`, `read`) and the 3-tool schema-evolution suggestion engine (`review_suggestions`, `decide_suggestions`, `apply_pending_decisions`) — plus an opt-in **Schema management** group (5 more). See the [MCP — Tools](https://xmemory.ai/mcp/#tools) reference for full parameter and return-shape details.
