Skip to Content
Claude Code (MCP)

Claude Code (MCP)

Give Claude Code durable memory that survives the session — over MCP . Khwan never runs a model; in a Claude Code session, Claude itself is the model. Khwan is the memory it’s missing.

Install

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 .

Connect to Claude Code

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.

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:

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:

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  — the same key as the SDKs (see Quickstart). It authenticates you to Khwan; it is not your model provider’s key.

Configuration

VariableRequiredPurpose
KHWAN_API_KEYyesYour key from the dashboard (kwk_live_…) — from the environment, not the config file.
KHWAN_COREnoSelect a named core. Paid plans only — free has just default.
KHWAN_USERnoA separate brain inside the core — 3 on free, unlimited on paid.
KHWAN_BASE_URLnoOverride 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:

# 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:

- 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

ToolWhen
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:

{ "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 or TypeScript SDK and the same prepare → your model → record loop.

Last updated on