<!-- Source: https://docs.khwan.ai/claude-code -->
<!-- The whole documentation in one file: https://docs.khwan.ai/llms-full.txt -->

# Claude Code (MCP)

Give Claude Code durable memory that survives the session — over
[MCP](https://modelcontextprotocol.io). Khwan never runs a model; in a Claude Code
session, **Claude itself is the model**. Khwan is the memory it's missing.

## Install

```bash
uvx khwan-mcp
```

Or `pip install khwan-mcp`. The server runs locally over stdio and talks to the
hosted Khwan API at `https://api.khwan.ai`.

It runs on your machine, holds your key, and sees what you type — so it is worth
reading before you install it:
[github.com/khwanlabs/khwan-mcp](https://github.com/khwanlabs/khwan-mcp).

## Connect to Claude Code

```bash
claude mcp add khwan --scope project \
  -e KHWAN_CORE=default \
  -- khwan-mcp
```

`--scope project` writes `.mcp.json` into the repo, so the setting travels with the
project. Note what is **not** in that command: the key.

  Don't pass the key with `-e KHWAN_API_KEY=…`. That writes the literal value into
  `.mcp.json` — a file whose whole point is being committed — so the key ends up in
  the repository, and in every clone of it. Supply it from the environment instead.

### Keeping the key out of the repo

Two ways, and the second is the one that works everywhere.

**Shell environment.** Leave `KHWAN_API_KEY` out of the config entirely and export
it in the shell that launches `claude`. The server inherits it.

```bash
export KHWAN_API_KEY=kwk_live_xxx
```

**A launcher (works in the desktop app too).** A desktop app is started from a dock
or a menu, not a login shell, so it inherits none of your shell exports and the
approach above silently yields no key. Read the key from a file instead:

```bash
mkdir -p ~/.khwan && chmod 700 ~/.khwan
printf 'KHWAN_API_KEY=kwk_live_xxx\n' > ~/.khwan/env && chmod 600 ~/.khwan/env

cat > ~/.khwan/khwan-mcp <<'SH'
#!/bin/sh
set -a
[ -f "$HOME/.khwan/env" ] && . "$HOME/.khwan/env"
set +a
exec khwan-mcp "$@"
SH
chmod 700 ~/.khwan/khwan-mcp
```

Then point the config at the launcher and keep only non-secret settings inline:

```bash
claude mcp add khwan --scope project \
  -e KHWAN_CORE=acme -e KHWAN_USER=Web \
  -- ~/.khwan/khwan-mcp
```

`.mcp.json` is now safe to commit, and every new repo costs two lines instead of a
pasted key. Anyone else on the team writes their own `~/.khwan/env`.

  Get your `KHWAN_API_KEY` from the [dashboard](https://app.khwan.ai) — the same key
  as the SDKs (see [Quickstart](/quickstart)). It authenticates you to Khwan; it is
  **not** your model provider's key.

### Configuration

| Variable         | Required | Purpose                                                     |
| ---------------- | -------- | ----------------------------------------------------------- |
| `KHWAN_API_KEY`  | yes      | Your key from the dashboard (`kwk_live_…`) — from the environment, not the config file. |
| `KHWAN_CORE`     | no       | Select a named core. Paid plans only — free has just `default`. |
| `KHWAN_USER`     | no       | A separate brain inside the core — 3 on free, unlimited on paid. |
| `KHWAN_BASE_URL` | no       | Override the API base — e.g. a self-hosted engine.          |

### One brain per project

`KHWAN_USER` is not a filter — it is a whole separate brain. `account::@web`
shares nothing with `account::@api`, so the two axes multiply and **a free
account already holds four isolated brains**: the core on its own, plus three
sub-brains.

That means one-brain-per-project works on the free plan, for up to four
projects, and it needs no `KHWAN_CORE` at all:

```bash
# in ~/code/web
claude mcp add khwan --scope project -e KHWAN_USER=web -- ~/.khwan/khwan-mcp
# in ~/code/api
claude mcp add khwan --scope project -e KHWAN_USER=api -- ~/.khwan/khwan-mcp
```

  Named cores are the paid axis, and pointing at one you do not have fails in two
  different ways. A core must exist before you select it — an unknown slug answers
  `404`, not "created it for you" — and on the free plan there is nothing to point
  at, because the cap of one is spent on `default`, so creating a named core answers
  `402`. Leave `KHWAN_CORE` unset on free. Sub-brains need no such step: they are
  created on first write.

## How to use it — seed, don't re-inject

A caching host like Claude Code already makes within-session history cheap. Khwan's
value is **across sessions**: it persists distilled facts so a *later* session can be
seeded with a compact, relevant set — instead of cold-replaying an old transcript.

### Seed a session

At the start of a session — or when you spawn a subagent, or need a fact that
scrolled out of context — call `khwan_recall(query)` once to pull a compact set of
relevant memories, and ground your work in the returned `seed_text`.

### Remember durable facts

When a durable decision, preference, or fact emerges that should outlive this
session's context window, call `khwan_remember(fact)` — a future `khwan_recall` will
surface it.

Reinforce the habit in your project's `CLAUDE.md`:

```md
- At the start of a task, call khwan_recall to seed relevant memory.
- When a durable decision, preference, or fact emerges, call khwan_remember.
```

  On a caching host, don't run the full loop on **every** turn — injecting memory each
  turn adds tokens without saving them. Prefer `khwan_recall` at the start plus
  `khwan_remember` for durable facts. Khwan's token win is across cold sessions, not
  within one hot session.

## Tools

| Tool                                    | When                                                          |
| --------------------------------------- | ------------------------------------------------------------ |
| `khwan_recall(query, limit=3)`          | **seed** a session/subagent — synthesised `lessons` + up to 3 relevant facts, as `seed_text`. |
| `khwan_remember(fact)`                  | **persist** a durable fact/preference for future sessions.   |
| `khwan_prepare(input)` → `khwan_record(turn_token, answer)` | the full loop, for custom agents on non-caching hosts. |
| `khwan_memory(limit=20)`                | inspect what the brain currently remembers.                  |
| `khwan_cores()`                         | list the isolated cores on the account.                      |

**Three facts is the ceiling.** The server ranks a wider candidate pool and keeps its
top three, so `limit` can narrow that further but never widen it. Alongside them come
any `lessons` synthesis has distilled from many past turns, and those lead the
`seed_text`: a rule earned over months outranks a single turn that happens to sit
nearby in the index.

Retrieval also applies a relevance floor, so **an empty `facts` is an answer** — the
brain has nothing close to this question. Read it as "not known here" rather than as
a failure.

## Claude Desktop

Claude Desktop and Claude Code keep **separate** MCP configuration. A server added
to one is invisible to the other, and `claude mcp add` does not touch this file —
so this is a second setup, not a second way of describing the first. Add to
`claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "khwan": {
      "command": "/Users/you/.khwan/khwan-mcp",
      "env": {
        "KHWAN_CORE": "acme",
        "KHWAN_USER": "Web"
      }
    }
  }
}
```

Two things differ from the Claude Code setup, and both catch people out:

  **Use an absolute path.** A desktop app is launched from a dock or a menu, so it
  does not inherit your shell's `PATH` — a bare `khwan-mcp` may simply not resolve,
  and the failure looks like the server crashing rather than like a missing binary.
  This is the same reason the launcher above exists: a desktop app inherits none of
  your shell exports, so `export KHWAN_API_KEY=…` silently yields no key here.

**One core for the whole app.** There is no per-project switch in Claude Desktop —
it has no notion of the directory you are working in — so `KHWAN_CORE` selects a
single brain for every conversation. Choose a broad one, and keep the narrow,
per-project cores for Claude Code where `--scope project` can pick them per repo.

## Beyond Claude Code

The server works with any MCP client. To use Khwan with any model directly —
OpenAI, open weights, anything you can call — use the [Python](/sdk-python) or
[TypeScript](/sdk-ts) SDK and the same
[prepare → your model → record](/byom) loop.
