Metadata-Version: 2.4
Name: maxmem-mcp
Version: 0.1.0
Summary: MCP server exposing MaxMem.it long-term memory to any MCP-compatible agent
Author: MaxMem / WebLabFattory
License: MIT
Project-URL: Homepage, https://maxmem.it
Keywords: mcp,memory,agents,llm,long-term-memory,maxmem
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: mcp[cli]>=1.2.0
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.0

# maxmem-mcp

**MCP server exposing [MaxMem.it](https://maxmem.it) long-term memory to any MCP-compatible agent.**

> Agent-agnostic. Works with Claude Code, Claude Desktop, Cursor, Continue.dev,
> Cline, custom Python/TS agents using the official MCP SDKs, and any future
> client that speaks the Model Context Protocol.

## What you get

Eight tools, all authenticated with a single MaxMem API key (`mm_live_*`):

| Tool | Purpose |
|------|---------|
| `memory_list_collections` | Discover memory collections owned by the tenant |
| `memory_write` | Persist a memory entry (content + tags + user/session id) |
| `memory_search` | Semantic search across stored memories |
| `memory_user_context` | Compact per-user summary ready for prompt injection |
| `memory_list_user` | Full list of memories for a specific user |
| `memory_delete_user` | GDPR right-to-erasure |
| `memory_bulk_write` | Persist many entries in one call |
| `memory_stats` | Aggregate statistics for the tenant |

## Transports

| Transport | Use case | Entry point |
|-----------|----------|-------------|
| **stdio** | Local MCP clients that spawn the server as a subprocess (Claude Desktop, Claude Code, Cursor, ...) | `maxmem-mcp` |
| **streamable-http** | Remote clients / shared deployments over the network | `maxmem-mcp-http` (default: `127.0.0.1:8765`) |

On the Weblabfactory VPS the HTTP transport is managed by systemd:
`sudo systemctl status maxmem-mcp-http`.

## Installation (local)

```bash
pip install maxmem-mcp        # coming soon (not yet on PyPI)
# or from source:
git clone https://github.com/weblabfactory/maxmem-mcp   # placeholder
pip install -e /opt/maxmem-mcp
```

## Quick start

1. Generate an API key in the MaxMem dashboard (`mm_live_...`) with the scopes
   you need: `memory:read`, `memory:write`, `memory:delete`, `kb:read`.
2. Export the key and point to your MaxMem instance:
   ```bash
   export MAXMEM_API_KEY=mm_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
   export MAXMEM_BASE_URL=https://maxmem.it      # default
   ```
3. Configure your MCP client (see below for the most common ones).

## Client configs

### Claude Code (`~/.claude.json` or project-level `.claude/mcp.json`)

```json
{
  "mcpServers": {
    "maxmem": {
      "command": "maxmem-mcp",
      "env": {
        "MAXMEM_API_KEY": "mm_live_xxxxxxxxxxxxxxxx"
      }
    }
  }
}
```

Remote/HTTP transport:

```json
{
  "mcpServers": {
    "maxmem": {
      "url": "https://mcp.maxmem.it/mcp",
      "headers": { "X-MaxMem-Api-Key": "mm_live_xxxxxxxxxxxxxxxx" }
    }
  }
}
```

### Claude Desktop (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS)

```json
{
  "mcpServers": {
    "maxmem": {
      "command": "/absolute/path/to/maxmem-mcp",
      "env": { "MAXMEM_API_KEY": "mm_live_xxxxxxxxxxxxxxxx" }
    }
  }
}
```

### Cursor (`.cursor/mcp.json` in repo or `~/.cursor/mcp.json` globally)

```json
{
  "mcpServers": {
    "maxmem": {
      "command": "maxmem-mcp",
      "env": { "MAXMEM_API_KEY": "mm_live_xxxxxxxxxxxxxxxx" }
    }
  }
}
```

### Generic MCP client via Python SDK

```python
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def main():
    params = StdioServerParameters(
        command="maxmem-mcp",
        env={"MAXMEM_API_KEY": "mm_live_..."},
    )
    async with stdio_client(params) as (r, w):
        async with ClientSession(r, w) as session:
            await session.initialize()
            res = await session.call_tool("memory_search", {
                "query": "what does the user prefer?",
                "external_user_id": "user-42",
            })
            print(res.content[0].text)

asyncio.run(main())
```

## Configuration reference

All configuration is env-based:

| Variable | Default | Purpose |
|----------|---------|---------|
| `MAXMEM_API_KEY` | *(required for stdio)* | MaxMem tenant API key |
| `MAXMEM_BASE_URL` | `https://maxmem.it` | Override for staging/self-hosted instances |
| `MAXMEM_TIMEOUT` | `30` | HTTP client timeout in seconds |
| `MAXMEM_MCP_HOST` | `127.0.0.1` | (HTTP transport) bind address |
| `MAXMEM_MCP_PORT` | `8765` | (HTTP transport) TCP port |
| `MAXMEM_MCP_LOG_LEVEL` | `INFO` | Python logging level |

### HTTP-transport authentication

With the HTTP transport each request carries its own API key via header:

```
X-MaxMem-Api-Key: mm_live_xxxxxxxxxxxxxxxx
```

The server forwards the header value to the upstream MaxMem call for that
request only (no caching, no cross-tenant leak).

## Security notes

- API keys are stored only in env vars / HTTP headers — never in tool arguments.
- Scopes on the API key limit what the agent can do: for a read-only research
  agent, mint a key with only `memory:read`.
- `memory_delete_user` is irreversible; gate it behind human confirmation in
  your agent's workflow.
- MaxMem normalizes `external_user_id` internally (lowercase email, strip `+`
  on phone numbers, etc.) so different superficial renderings of the same
  identity land on the same key. See `docs/FIX-144_MEM0_AUDIT.md` in the
  MaxMem repo for details.

## Health check

```bash
curl http://127.0.0.1:8765/healthz
# {"ok":true,"service":"maxmem-mcp","version":"0.1.0"}
```

## License

MIT. See `LICENSE`.
