# @engramx/mcp

MCP server for [EngramX](https://engramx.ai) — persistent, decentralized agent memory on the Internet Computer.

## Prerequisites

- Node.js >= 22.12
- An engram with operator access (session key from `engramx pair`)

## Quick Start

```bash
ENGRAM_CANISTER_ID=xxxxx-xxxxx-xxxxx-xxxxx-xxx npx @engramx/mcp
```

## Configuration

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `ENGRAM_CANISTER_ID` | Yes | — | Your engram canister ID |
| `ENGRAM_SESSION_KEY_PATH` | No | `~/.engramx/session.key` | Path to Ed25519 session key |
| `ENGRAM_HOST` | No | `https://ic0.app` | ICP host URL |

## Setup: Claude Desktop

Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):

```json
{
  "mcpServers": {
    "engramx": {
      "command": "npx",
      "args": ["@engramx/mcp"],
      "env": {
        "ENGRAM_CANISTER_ID": "xxxxx-xxxxx-xxxxx-xxxxx-xxx",
        "ENGRAM_SESSION_KEY_PATH": "/Users/you/.engramx/session.key"
      }
    }
  }
}
```

## Setup: Cursor

Add to `.cursor/mcp.json` in your project root:

```json
{
  "mcpServers": {
    "engramx": {
      "command": "npx",
      "args": ["@engramx/mcp"],
      "env": {
        "ENGRAM_CANISTER_ID": "xxxxx-xxxxx-xxxxx-xxxxx-xxx",
        "ENGRAM_SESSION_KEY_PATH": "/Users/you/.engramx/session.key"
      }
    }
  }
}
```

## Setup: Python Agent

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

server = StdioServerParameters(
    command="npx",
    args=["@engramx/mcp"],
    env={
        "ENGRAM_CANISTER_ID": "xxxxx-xxxxx-xxxxx-xxxxx-xxx",
        "ENGRAM_SESSION_KEY_PATH": "/path/to/session.key",
    },
)
async with stdio_client(server) as (read, write):
    async with ClientSession(read, write) as session:
        await session.initialize()
        result = await session.call_tool("engram_list_memory_files", {})
```

## Setup: Generic MCP Client

Any MCP-compatible client can spawn the server over stdio:

```bash
ENGRAM_CANISTER_ID=xxxxx-xxxxx-xxxxx-xxxxx-xxx \
ENGRAM_SESSION_KEY_PATH=/path/to/session.key \
npx @engramx/mcp
```

The server communicates over stdin/stdout using the MCP protocol. Set environment variables for authentication.

## Available Tools

| Tool | Parameters | Description |
|------|-----------|-------------|
| `engram_read_memory` | `path: string` | Read a memory file (content, version, timestamp) |
| `engram_append_memory` | `path: string, content: string` | Append to a memory file (creates if missing) |
| `engram_list_memory_files` | _(none)_ | List all memory files |
| `engram_read_memory_batch` | `paths: string[]` | Read multiple files in one call |
| `engram_memory_history` | `path: string` | Version history of a file — commitments and eviction disclosures, not content |
| `engram_read_audit_log` | `fromIndex?: number, limit?: number` | Read audit-log entries (timestamped operations) |
| `engram_wallet_balance` | _(none)_ | Engram canister cycles balance (fuel) |
| `engram_status` | _(none)_ | Canister health and stats |
| `engram_list_services` | _(none)_ | List paid services registered on this engram |
| `engram_submit_service_request` | `serviceId: string, params: string` | Submit a paid service request; returns a job ID |
| `engram_get_job_result` | `jobId: string, maxAttempts?: number` | Poll a job to terminal status; returns the job |
| `engram_dispute_job` | `jobId: string, reason: string` | Dispute a completed job (BuyerConfirm verification) |

> **Append-only by design.** This server intentionally exposes **no** `write`, `delete`,
> `rollback`, `transfer`, or `sign` tools. Operators get read + append only; full
> overwrite/delete/rollback, fund movement, and signing are owner-only and not reachable
> over MCP.

## Available Resources

| URI | Description |
|-----|-------------|
| `engram://status` | Canister status as JSON |

## Getting an Operator Session Key

1. Create an engram at [engramx.ai](https://engramx.ai) or via the CLI
2. Generate an operator invite in the engram dashboard
3. Pair your machine:
   ```bash
   engramx pair <invite-code> --engram <canister-id>
   ```
4. The session key is saved to `~/.engramx/session.key`

See the [EngramX documentation](https://github.com/engramx/engramx) for full instructions.

## Local Development

```bash
git clone https://github.com/engramx/engramx.git
cd engramx/integrations/mcp
pnpm install
pnpm build
```

Test with a local ICP replica:

```bash
ENGRAM_CANISTER_ID=<local-canister-id> \
ENGRAM_HOST=http://localhost:4943 \
node dist/index.js
```

Inspect with the MCP Inspector:

```bash
npx @modelcontextprotocol/inspector -- npx @engramx/mcp
```

## Troubleshooting

**Missing `ENGRAM_CANISTER_ID`**
The server exits with a clear error. Set the environment variable to your engram canister ID.

**Session key not found**
Generate one with `engramx pair`. The default path is `~/.engramx/session.key`. Override with `ENGRAM_SESSION_KEY_PATH`.

**Canister unreachable**
Check that `ENGRAM_HOST` is correct (default: `https://ic0.app` for mainnet). For local development, use `http://localhost:4943`. Verify network connectivity.
