Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mcp-publisher.exe

# DevFlow engine
.progress/
.npm-cache-review/

# Agent registry & profiles
.agents/
Expand Down
30 changes: 16 additions & 14 deletions MCP-README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ XMemo MCP 服务器提供以下 20 个工具,每个工具都有清晰的名称

获取 Token:访问 [https://xmemo.dev](https://xmemo.dev) 注册并获取 API Key。

### 方式二:OAuth 客户端(部分客户端支持
### 方式二:MCP OAuth 客户端(仅部分客户端

Cursor、Gemini CLI、Antigravity、OpenCode 等客户端支持 MCP OAuth 流程,无需手动配置 `XMEMO_KEY`:
当前 CLI 将 Gemini CLI、Antigravity 系列、OpenCode 和 Qwen 生成为 MCP OAuth 配置;这些客户端无需在 MCP 配置中手动配置 `XMEMO_KEY`:

```json
{
Expand Down Expand Up @@ -138,7 +138,7 @@ xmemo-mcp
`xmemo-mcp` 是专用的 stdio MCP 入口;`xmemo mcp serve` 与它等价。
能力发现(Tools、Prompts、Resources)不需要 Token,实际工具执行仍需认证。

支持的客户端:`codex`、`cursor`、`copilot`、`gemini`、`antigravity`、`grok`、`kiro`、`claude-desktop`、`windsurf`、`cline`、`kimi`、`qwen`、`trae`
支持的 `xmemo setup` 客户端包括:`codex`、`cursor`、`copilot`、`gemini`、`antigravity`、`grok`、`kiro`、`claude-desktop`、`windsurf`、`cline`、`kimi-code`、`qwen`、`trae`、`zed` 和 `opencode`。底层 `xmemo mcp add` 使用注册表 ID(例如 `gemini-cli`、`copilot-cli`);Copilot CLI 的推荐入口仍是 `xmemo setup copilot`

---

Expand Down Expand Up @@ -187,8 +187,8 @@ xmemo-mcp
```json
{
"tool": "create_memory_todo",
"title": "重构 auth 模块:将 JWT 改为 Session + Redis",
"due": "next-week"
"content": "重构 auth 模块:将 JWT 改为 Session + Redis",
"due_at": "<ISO-8601 时间>"
}
```

Expand All @@ -210,26 +210,28 @@ xmemo-mcp

| 客户端 | 支持方式 | 配置命令 |
|--------|----------|----------|
| **Kimi Code** | Streamable HTTP + Bearer Token | `xmemo setup kiro` |
| **Claude Desktop** | Streamable HTTP + OAuth | `xmemo setup claude-desktop` |
| **Cursor** | Streamable HTTP + OAuth | `xmemo setup cursor` |
| **Kimi Code** | Streamable HTTP + Bearer Token(`XMEMO_KEY`) | `xmemo setup kimi-code` |
| **Kiro** | `mcp-remote` + Bearer Token(`XMEMO_KEY`) | `xmemo setup kiro` |
| **Claude Desktop** | `mcp-remote` + Bearer Token(`XMEMO_KEY`) | `xmemo setup claude-desktop` |
| **Cursor** | Streamable HTTP + Bearer Token(`XMEMO_KEY`) | `xmemo setup cursor` |
| **Copilot CLI** | Local Proxy + Bearer Token | `xmemo setup copilot` |
| **Gemini CLI** | Streamable HTTP + OAuth | `xmemo setup gemini` |
| **Gemini CLI** | Streamable HTTP + MCP OAuth | `xmemo setup gemini` |
| **Grok (xAI)** | Streamable HTTP + Bearer Token | `xmemo setup grok` |
| **Antigravity** | Streamable HTTP + OAuth | `xmemo setup antigravity` |
| **Antigravity 系列** | Streamable HTTP + MCP OAuth | `xmemo setup antigravity` |
| **Windsurf** | Streamable HTTP + Bearer Token | `xmemo setup windsurf` |
| **Cline** | Streamable HTTP + Bearer Token | `xmemo setup cline` |
| **Trae** | Streamable HTTP + Bearer Token | `xmemo setup trae` |
| **Qwen CLI** | Streamable HTTP + OAuth | `xmemo setup qwen` |
| **Zed** | Streamable HTTP + Bearer Token | `xmemo setup zed` |
| **Trae / Trae Solo** | `mcp-remote` + Bearer Token(`XMEMO_KEY`) | `xmemo setup trae` |
| **Qwen CLI** | Streamable HTTP + MCP OAuth | `xmemo setup qwen` |
| **Zed** | `mcp-remote` + Bearer Token(`XMEMO_KEY`) | `xmemo setup zed` |
| **OpenCode** | Remote MCP + MCP OAuth | `xmemo setup opencode` |

---

## 隐私与安全

- **无遥测**:CLI 和 MCP 服务均不发送任何遥测或分析数据
- **Token 安全**:生成的配置文件仅引用环境变量(如 `${XMEMO_KEY}`),从不嵌入真实 token 值
- **OAuth 优先**:支持的客户端优先使用 OAuth 流程,避免手动管理密钥
- **认证方式以表格为准**:只有标记为 MCP OAuth 的客户端走 OAuth;其余远程客户端从 `XMEMO_KEY` 环境变量读取 Bearer Token
- **设备级标识**:`XMEMO_AGENT_INSTANCE_ID` 为设备级非敏感标识符,用于归因分析,不暴露个人信息
- **数据归属**:用户完全拥有记忆数据,支持随时导出、删除或脱敏

Expand Down
120 changes: 95 additions & 25 deletions MCP-SETUP-GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,46 +40,73 @@ set XMEMO_AGENT_INSTANCE_ID=random-guid-here

## 各客户端配置详情

### Kimi Code / Kiro
### Kimi Code

配置文件:`~/.kiro/settings/mcp.json`
配置文件:`~/.kimi-code/mcp.json`

```json
{
"mcpServers": {
"XMemo": {
"type": "streamable-http",
"url": "https://xmemo.dev/mcp",
"bearerTokenEnvVar": "XMEMO_KEY",
"headers": {
"Authorization": "Bearer ${XMEMO_KEY}",
"X-Memory-OS-Agent-ID": "${XMEMO_AGENT_ID}",
"X-Memory-OS-Agent-ID": "kimi-code",
"X-Memory-OS-Agent-Instance-ID": "${XMEMO_AGENT_INSTANCE_ID}"
}
}
}
}
```

> ⚠️ **重要**:Kimi Code 通过 `bearerTokenEnvVar` 读取环境变量。确保 `XMEMO_KEY` 在启动 Kimi Code 的**同一环境**中已导出。
> ⚠️ **重要**:Kimi Code 通过 `bearerTokenEnvVar` 读取环境变量。确保 `XMEMO_KEY` 在启动 Kimi Code 的**同一环境**中已导出。推荐直接运行 `xmemo setup kimi-code`。

---

### Kiro

配置文件:`~/.kiro/settings/mcp.json`

Kiro 使用 `mcp-remote` 连接 Hosted MCP,并从 `XMEMO_KEY` 读取 Bearer Token。推荐运行:

```bash
xmemo setup kiro
```

不要把 Kiro 与 MCP OAuth 客户端混为一谈:`xmemo login` 可以通过浏览器获取 CLI 凭据,但 Kiro 的 MCP 请求仍由环境变量认证。

---

### Claude Desktop

配置文件:`%APPDATA%\Claude\settings.json` (Windows) 或 `~/Library/Application Support/Claude/settings.json` (macOS)
配置文件:`%APPDATA%\Claude\claude_desktop_config.json` (Windows) 或 `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)

```json
{
"mcpServers": {
"XMemo": {
"type": "streamable-http",
"url": "https://xmemo.dev/mcp"
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://xmemo.dev/mcp",
"--header",
"Authorization:Bearer ${XMEMO_KEY}",
"--header",
"X-Memory-OS-Agent-ID:claude-desktop",
"--header",
"X-Memory-OS-Agent-Instance-ID:${XMEMO_AGENT_INSTANCE_ID}"
],
"env": {
"XMEMO_KEY": "${env:XMEMO_KEY}",
"XMEMO_AGENT_INSTANCE_ID": "${XMEMO_AGENT_INSTANCE_ID}"
}
}
}
}
```

Claude Desktop 支持 MCP OAuth,首次使用 XMemo 工具时会自动弹出浏览器授权窗口
Claude Desktop 的 CLI 配置路径使用 `mcp-remote` + `XMEMO_KEY`;它不属于本仓库 CLI 标记的 MCP OAuth 客户端。推荐运行 `xmemo setup claude-desktop` 生成配置

---

Expand All @@ -91,14 +118,18 @@ Claude Desktop 支持 MCP OAuth,首次使用 XMemo 工具时会自动弹出浏
{
"mcpServers": {
"XMemo": {
"type": "streamable-http",
"url": "https://xmemo.dev/mcp"
"url": "https://xmemo.dev/mcp",
"headers": {
"Authorization": "Bearer ${env:XMEMO_KEY}",
"X-Memory-OS-Agent-ID": "cursor",
"X-Memory-OS-Agent-Instance-ID": "${XMEMO_AGENT_INSTANCE_ID}"
}
}
}
}
```

Cursor 同样支持 OAuth,无需手动配置 `Authorization`
Cursor 的 CLI 配置使用 `XMEMO_KEY` Bearer Token;只有 Cursor marketplace 插件是 OAuth-first,两者不要混用。推荐运行 `xmemo setup cursor` 生成配置

---

Expand Down Expand Up @@ -130,8 +161,11 @@ xmemo mcp proxy
{
"mcpServers": {
"XMemo": {
"type": "http",
"httpUrl": "https://xmemo.dev/mcp"
"httpUrl": "https://xmemo.dev/mcp",
"headers": {
"X-Memory-OS-Agent-ID": "gemini-cli",
"X-Memory-OS-Agent-Instance-ID": "${XMEMO_AGENT_INSTANCE_ID}"
}
}
}
}
Expand Down Expand Up @@ -165,8 +199,11 @@ bearer_token_env_var = "XMEMO_KEY"
{
"mcpServers": {
"XMemo": {
"type": "http",
"url": "https://xmemo.dev/mcp"
"serverUrl": "https://xmemo.dev/mcp",
"headers": {
"X-Memory-OS-Agent-ID": "antigravity",
"X-Memory-OS-Agent-Instance-ID": "${XMEMO_AGENT_INSTANCE_ID}"
}
}
}
}
Expand All @@ -176,9 +213,9 @@ Antigravity 2.0 支持 OAuth,首次使用时会自动打开浏览器完成授

---

### Windsurf / Cline / Trae / Zed / Qwen
### Windsurf / Cline

这些客户端通常使用标准的 `mcp.json` 格式:
这些客户端使用 Bearer Token。不同版本的配置键可能不同,推荐用对应的 CLI ID 生成配置:`xmemo setup windsurf` 或 `xmemo setup cline`。

```json
{
Expand All @@ -187,13 +224,39 @@ Antigravity 2.0 支持 OAuth,首次使用时会自动打开浏览器完成授
"type": "streamable-http",
"url": "https://xmemo.dev/mcp",
"headers": {
"Authorization": "Bearer ${XMEMO_KEY}"
"Authorization": "Bearer ${env:XMEMO_KEY}",
"X-Memory-OS-Agent-ID": "your-client-id",
"X-Memory-OS-Agent-Instance-ID": "${XMEMO_AGENT_INSTANCE_ID}"
}
}
}
}
```

### Trae / Trae Solo / Zed

这些客户端由 CLI 配置为 `mcp-remote` + `XMEMO_KEY`,不要复制上面的直连 HTTP 示例。运行 `xmemo setup trae`、`xmemo setup trae-solo` 或 `xmemo setup zed`,并在启动客户端的同一环境中设置 `XMEMO_KEY`。

### Qwen

Qwen 使用 MCP OAuth,无需在 MCP 配置中写入 `XMEMO_KEY`:

```json
{
"mcpServers": {
"XMemo": {
"httpUrl": "https://xmemo.dev/mcp",
"headers": {
"X-Memory-OS-Agent-ID": "qwen",
"X-Memory-OS-Agent-Instance-ID": "${XMEMO_AGENT_INSTANCE_ID}"
}
}
}
}
```

首次连接时按客户端提示完成浏览器授权。

---

## 验证配置
Expand All @@ -217,11 +280,18 @@ xmemo smoke --client <your-client>

| 问题 | 可能原因 | 解决方案 |
|------|----------|----------|
| "无法连接到 XMemo" | Token 未设置 | 确认 `XMEMO_KEY` 环境变量已导出 |
| "401 Unauthorized" | Token 无效或过期 | 访问 xmemo.dev 重新获取 token |
| "OAuth 窗口未弹出" | 客户端不支持 MCP OAuth | 改用 Bearer Token 方式 |
| "工具未显示" | 客户端未重新加载 MCP 配置 | 重启客户端或执行 `/mcp reload` |
| "代理连接失败" | Copilot CLI 代理未运行 | 保持 `xmemo mcp proxy` 运行 |
| "无法连接到 XMemo" | 网络、地址或客户端传输配置错误 | 运行 `xmemo doctor`,确认地址为 `https://xmemo.dev/mcp`,再检查客户端日志 |
| "401 Unauthorized" | Token 缺失、无效或过期 | 运行 `xmemo auth status --verify`;按输出重新登录或更新 `XMEMO_KEY` |
| "403 Forbidden" | Token 有效,但缺少所需 scope 或当前资源不在授权范围 | 重新授权包含所需 scope 的正式凭据,并确认使用的是已授权的项目/团队范围;不要仅为绕过错误而扩大 scope |
| "OAuth 窗口未弹出" | 当前客户端不是 CLI 标记的 MCP OAuth 客户端,或客户端未重载配置 | 先运行 `xmemo mcp add <client-id> --write` 并重启客户端;对于 Bearer 客户端改为在同一启动环境设置 `XMEMO_KEY` |
| "工具未显示" | MCP 配置未加载、服务名重复或客户端缓存旧配置 | 检查生成配置中的 `XMemo`、重启/Reload MCP,再运行 `xmemo doctor` |
| `XMEMO_KEY` 未检测到 | 环境变量没有传给启动客户端的那个进程 | 在启动客户端的同一终端运行 `xmemo auth status` 或 `xmemo token status --verify`,设置变量后重新启动客户端;不要把 token 写入项目文件 |
| 召回结果为空 | 查询词、path、scope 或项目范围不匹配 | 先确认认证成功,再使用明确的查询词和正确的授权 scope;项目上下文必须传入准确的 `project_id`,不能只传项目名 |
| 项目范围错误 | 使用了错误的 scope、team 或 project ID | 使用当前账号已授权的精确 `project_id`;不要通过扩大范围来掩盖 ID 错误 |
| `XMEMO_AGENT_INSTANCE_ID` 每次变化 | 每次启动都重新生成实例 ID | 使用稳定的用户环境变量,或运行 `xmemo mcp add <client-id> --write` 让 CLI 保存用户级实例 ID;不要将其提交到 git |
| 出现重复记忆 | 同一事实被重复保存,或重复安装了 Native 与 MCP 两个集成 | 保存前先 `recall`;OpenClaw/Hermes 使用 Native 集成时不要再安装同一能力的 MCP fallback,除非明确需要 |
| forget/delete 不生效 | 误用了不存在的 `delete` 工具、目标不是精确 ID,或客户端没有刷新 | MCP 使用 `forget` 并传入 `current` 或精确 memory ID;删除后刷新并用 `recall` 验证,必要时用 `restore_memory` 恢复可恢复删除 |
| "代理连接失败" | Copilot CLI 本地代理未运行 | 保持 `xmemo mcp proxy` 运行,并检查代理端口配置 |

---

Expand Down
56 changes: 54 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,13 @@ xmemo setup cursor --dry-run
| Client | Recommended command | Connection |
| --- | --- | --- |
| **Codex** | `xmemo setup codex` | Hosted MCP + behavior profile |
| **Cursor** | `xmemo setup cursor` | Hosted MCP + behavior profile |
| **Cursor** | `xmemo setup cursor` | Hosted MCP + Bearer Token + behavior profile |
| **Copilot CLI** | `xmemo setup copilot` | Local authenticated proxy |
| **Gemini CLI** | `xmemo setup gemini` | Hosted MCP + OAuth |
| **Antigravity** | `xmemo setup antigravity` | Hosted MCP + OAuth |
| **OpenClaw** | `xmemo setup openclaw` | Native memory plugin + Skill |
| **Hermes** | `xmemo setup hermes` | Native memory provider |
| **Kiro** | `xmemo setup kiro` | Hosted MCP |
| **Kiro** | `xmemo setup kiro` | Hosted MCP + Bearer Token |
| **Grok** | `xmemo setup grok` | Hosted MCP |
| **Other MCP clients** | `xmemo mcp config --client generic` | Generated template |

Expand Down Expand Up @@ -299,6 +299,58 @@ xmemo setup hermes [--with-mcp|--mcp-only]

</details>

<details>
<summary><strong>Direct XMemo service client</strong></summary>

```bash
xmemo memory add --content "Remember this" --path notes/example --json
xmemo memory search "example" --json
xmemo context recall "resume this task" --include-knowledge --json
xmemo state save --current-task "ship the client" --next-action "run tests" --json
xmemo state restore --json
xmemo restart snapshot --json
xmemo restart restore --snapshot-id <snapshot-id> --json

xmemo knowledge add --base <base-id> --file ./guide.pdf --title "Guide" --json
xmemo knowledge search "setup" --base <base-id> --json
xmemo knowledge read <item-id> --json > knowledge-view.json
xmemo knowledge update <item-id> --text "Updated" --from knowledge-view.json --publish --yes --json

xmemo dream preview --wait --json
xmemo dream show <run-id> --json > dream-view.json
xmemo dream apply <run-id> --item <candidate-id> --from dream-view.json --yes --json

xmemo cloud-skill list --json
xmemo cloud-skill add --file ./SKILL.md --json
xmemo cloud-skill show <skill-id> --json > skill-view.json
xmemo cloud-skill update <skill-id> --from skill-view.json --file ./SKILL.md --json
xmemo cloud-skill run <skill-id> --input ./args.json --from skill-view.json --yes --json
```

All direct service commands support a single machine-readable JSON envelope.
Knowledge update, Dream apply, and Cloud Skill run use the `readReceipt` from a
saved read/show result so the CLI never silently substitutes a newer revision.
Set `XMEMO_KNOWLEDGE_BASE_ID` for a non-interactive default knowledge base.
For a long knowledge item, continue the same fixed revision with
`xmemo knowledge read <item-id> --from knowledge-view.json --offset <n>`.
Run `xmemo doctor --services --json` for read-only Knowledge, Dream, and Cloud
Skill diagnostics; it deliberately does not claim write or production readiness.

Cloud Skill add/update already target the safe create-only and content-CAS
contracts. They fail with `SERVER_CONTRACT_REQUIRED` on older services and do
not fall back to legacy upsert routes. Binary Knowledge item updates similarly
require a new version of the same server Document; use `--document` and
`--document-version` after that version has been uploaded.

The normal login scopes remain unchanged. Request additional service scopes
explicitly when needed, for example:

```bash
xmemo login --scopes memory:read,memory:write,memory:restore,knowledge:read,knowledge:write
```

</details>

<details>
<summary><strong>MCP and behavior profiles</strong></summary>

Expand Down
9 changes: 8 additions & 1 deletion bin/memory-os.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
#!/usr/bin/env node
import { run } from '../src/cli.js';

const interruptController = new AbortController();
const serviceCommand = ['memory', 'context', 'state', 'restart', 'knowledge', 'dream', 'cloud-skill'].includes(process.argv[2]) || (process.argv[2] === 'doctor' && process.argv.includes('--services'));
const interrupt = () => interruptController.abort();
if (serviceCommand) process.once('SIGINT', interrupt);

const exitCode = await run(process.argv.slice(2), {
env: process.env,
stdin: process.stdin,
stdout: process.stdout,
stderr: process.stderr,
fetch: globalThis.fetch
fetch: globalThis.fetch,
signal: interruptController.signal
});

process.exitCode = exitCode;
if (serviceCommand) process.removeListener('SIGINT', interrupt);
Loading
Loading