Metadata-Version: 2.4
Name: aleth-mcp
Version: 0.1.0
Summary: MCP face for the memory engine: the 9 memory verbs as MCP tools over the thin wire client (ALB-2, go/no-go Step 1). Any MCP-speaking agent gets persistent memory with one config entry.
Author: Aleth Authors
License: Apache-2.0
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: aleth-client>=1.1
Requires-Dist: mcp>=1.0
Dynamic: license-file

# aleth-mcp

The MCP face for the memory engine: the ten memory verbs, `remember`,
`recall`, `show`, `search`, `retract`, `forget`, `supersede`, `connect`,
`status`, `nodes`: exposed as MCP tools, as a thin shell over the
`aleth-client` wire core.

Three of those correct a belief and they are NOT interchangeable:
`retract` says it was wrong, `supersede` says it was true and something
newer replaced it, `forget` destroys it.

Any MCP-speaking agent gets persistent, associative, erasable memory with
one config entry:

```json
{
  "mcpServers": {
    "memory": { "command": "aleth-mcp" }
  }
}
```

## What it is (and is not)

- **Thin.** Every tool is one client call; results are the frozen wire
  models as plain dicts. No state of its own, no extra verbs.
- **Lazy.** The server starts and lists tools even before the engine is up;
  the first call connects. Connection problems come back in-band
  (`{"error": ...}`), so the agent sees them instead of a dead server.
- **Engine-agnostic on the wire.** It speaks the frozen memory wire, so it
  works against the standalone memory server and the full daemon alike --
  set `MEMORY_DISCOVERY_DIR` if the engine's discovery file lives somewhere
  non-default.
- **`forget` really forgets.** Permanent erasure (graph + storage + vacuum),
  distinct from `retract` (kept but flagged). That split is the product's
  thesis, not a convenience.

## Install / run

```bash
pip install aleth-mcp
aleth-mcp          # stdio MCP server (bare invocation -- how hosts launch it)
```

## Register with an AI host

The `install` subcommand writes the server entry into a host's own config file
(merge-only, backed up, idempotent). The bare `aleth-mcp` invocation is
unchanged, only the `install` / `uninstall` / `hosts` subcommands trigger the
writer.

```bash
aleth-mcp hosts                 # list hosts + which are detected here
aleth-mcp install claude-code   # add "memory" to ./.mcp.json
aleth-mcp install --all         # install into every detected host
aleth-mcp install cursor --project --instructions   # config + rules file
aleth-mcp install codex --dry-run                   # show the diff, write nothing
aleth-mcp uninstall claude-code                     # remove exactly our entry
```

Flags: `--all` (detected hosts only), `--project` / `--user` (scope, where the
host supports both), `--dry-run` (unified diff, no write), `--instructions`
(also inject the memory instruction block).

Behaviour: existing config is parsed and only our `memory` entry is
added/replaced (unknown keys preserved); a timestamped `.bak` is written next
to the file before every change; re-running with identical content writes
nothing. JSON hosts are reserialized (2-space indent; all other keys survive).
TOML and comment-bearing files are edited by surgical text splice. If a
JSONC-capable file (VS Code, Zed) actually contains comments, the writer
**fails soft**: it refuses to touch the file and prints the exact snippet to
paste, rather than dropping your comments.

### What gets written where

| Host | Config file (default scope) | Container key | Source |
|------|-----------------------------|---------------|--------|
| `claude-code` | `./.mcp.json` (project) or `~/.claude.json` (`--user`) | `mcpServers` | own-knowledge |
| `claude-desktop` | `%APPDATA%\Claude\claude_desktop_config.json` / `~/Library/Application Support/Claude/...` / `~/.config/Claude/...` | `mcpServers` | own-knowledge |
| `cursor` | `~/.cursor/mcp.json` (global) or `./.cursor/mcp.json` (`--project`) | `mcpServers` | own-knowledge |
| `codex` | `~/.codex/config.toml` | `[mcp_servers.memory]` (TOML) | [OpenAI docs](https://developers.openai.com/codex/config-reference) |
| `vscode` | `./.vscode/mcp.json` | `servers` (note: not `mcpServers`; stdio `type` required) | [VS Code docs](https://code.visualstudio.com/docs/agents/reference/mcp-configuration) |
| `gemini-cli` | `~/.gemini/settings.json` | `mcpServers` | own-knowledge |
| `windsurf` | `~/.codeium/windsurf/mcp_config.json` | `mcpServers` | own-knowledge |
| `zed` | `~/.config/zed/settings.json` / `%APPDATA%\Zed\settings.json` | `context_servers` (`{command:{...}}` shape) | [Zed docs](https://zed.dev/docs/ai/mcp) |
| `cline` | `<VS Code User>/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json` | `mcpServers` | own-knowledge + [cline/cline](https://github.com/cline/cline) |

Instruction-line injection (`--instructions`) writes a short, marker-fenced
memory usage block into the host's instruction file where one exists:
`CLAUDE.md` (claude-code), `AGENTS.md` (codex), `.cursor/rules/memory.mdc`
(cursor), `GEMINI.md` (gemini-cli).

## Testing

`tests/test_install.py` drives the host-config writers against real temp
dirs (HOME / APPDATA redirected to `tmp_path`, no mocked file IO, no test
touches a real config dir). The handler layer is exercised end-to-end
against a real in-process engine + RPC server + wire client, no mocks,
the stdio transport the only layer not under test.

```bash
python -m pytest tests/ -q
```
