Skip to main content
Glama
ArchChuan

yinxiang-mcp

by ArchChuan
README.md
# yinxiang-mcp

非官方印象笔记(Yinxiang / Evernote China)MCP Server。通过 stdio 暴露笔记本、原生超级笔记、原始 ENML 和资源附件相关操作。

> 本项目不是印象笔记或 Evernote 官方项目,也不代表官方背书。

## 安装

```bash
npx -y @yanghechuan/yinxiang-mcp
```

建议锁定版本:

```bash
npx -y @yanghechuan/yinxiang-mcp@0.7.0
```

## 认证

当前版本使用 Direct Token 认证,暂未实现 OAuth。

需要配置两个环境变量:

- `YINXIANG_DEV_TOKEN`:在 <https://dev.yinxiang.com> 申请的 Developer Token
- `YINXIANG_NOTESTORE_URL`:NoteStore URL,例如 `https://app.yinxiang.com/shard/sXX/notestore`

## MCP 配置

```json
{
  "mcpServers": {
    "yinxiang": {
      "command": "npx",
      "args": ["-y", "@yanghechuan/yinxiang-mcp@0.7.0"],
      "env": {
        "YINXIANG_DEV_TOKEN": "<your-token>",
        "YINXIANG_NOTESTORE_URL": "https://app.yinxiang.com/shard/sXX/notestore"
      }
    }
  }
}
```

## 工具列表

### 笔记本与笔记本组

- `list-notebooks`:列出笔记本,包含 `guid`、`stack`、默认笔记本标记和更新元数据。
- `get-notebook`:按 `guid` 读取单个笔记本元数据。
- `create-notebook`:创建笔记本,可选加入笔记本组。
- `update-notebook`:重命名笔记本或更新所属笔记本组,需要 `confirm=true`。
- `delete-notebook`:删除笔记本,需要 `confirm=true` 且 `confirmGuid === guid`;非空笔记本还需要 `force=true`。
- `list-stacks`:从笔记本的 `stack` 字段反推笔记本组列表。
- `create-stack`:通过把一个已有笔记本放入 stack 来创建笔记本组,需要 `confirm=true`。
- `rename-stack`:批量更新组内笔记本的 `stack` 字段来重命名笔记本组,需要 `confirm=true`。
- `delete-stack`:清空组内笔记本的 `stack` 字段来删除笔记本组,不删除笔记本,需要 `confirm=true`。
- `move-notebook-to-stack`:将单个笔记本移入指定笔记本组,需要 `confirm=true`。
- `remove-notebook-from-stack`:将单个笔记本移出当前笔记本组,需要 `confirm=true`。

### 笔记

- `find-notes`:按 Evernote 搜索语法和/或笔记本 GUID 搜索笔记元数据。
- `get-note-raw`:读取原始 ENML、笔记本 GUID、标签和属性,不经过 Markdown 转换。
- `create-super-note`:使用原生块模型创建印象笔记超级笔记。
- `update-super-note`:使用原生块模型覆盖笔记正文,需要 `confirm=true`。
- `append-super-note-blocks`:保留已有 ENML,在末尾追加原生块,需要 `confirm=true`。
- `replace-super-note-block`:按 `blockId` 替换一个原生块,需要 `confirm=true`。
- `delete-super-note-block`:按 `blockId` 删除一个原生块,需要 `confirm=true`。
- `replace-note-enml`:用完整 ENML 或 `en-note` 内部 body 直接覆盖正文,需要 `confirm=true`。
- `clone-note`:原样克隆 ENML 正文和笔记元数据,不经过 Markdown 转换。
- `attach-file`:将本地文件追加为 Evernote Resource,并在正文追加匹配的 `<en-media>`,需要 `confirm=true`。
- `export-note-resource`:按 `resourceGuid` 或 MD5 `hash` 导出单个资源。
- `delete-note-resource`:按 `resourceGuid` 或 MD5 `hash` 删除单个资源和匹配的 `<en-media>`,需要 `confirm=true`。
- `move-note`:移动笔记到另一个笔记本,不修改标题和正文,需要 `confirm=true`。
- `clear-note-content`:清空笔记正文,保留标题和所在笔记本,需要 `confirm=true`。
- `delete-note`:将笔记移入废纸篓,需要 `confirm=true`。
- `expunge-note`:永久删除笔记,需要 `confirm=true` 且 `confirmGuid === guid`。

## 原生块模型

`create-super-note`、`update-super-note` 和 `append-super-note-blocks` 接收 `blocks` 数组。字符串会被当作普通段落;对象示例:

```json
[
  {
    "type": "heading",
    "level": 2,
    "id": "stable-block-id",
    "runs": [
      { "text": "蓝色加粗标题", "bold": true, "color": "#1677ff" }
    ]
  },
  {
    "type": "paragraph",
    "runs": [
      { "text": "普通文字 " },
      { "text": "红色加粗", "bold": true, "color": "#d4380d" },
      { "text": " 大号文字", "fontSize": 22 },
      { "text": " 链接", "href": "https://example.com?a=1&b=2" }
    ]
  },
  {
    "type": "todo",
    "checked": false,
    "runs": [{ "text": "待办事项" }]
  },
  {
    "type": "table",
    "id": "table-1",
    "header": true,
    "rows": [
      [{ "text": "名称" }, { "text": "状态" }],
      [{ "text": "任务 A" }, { "text": "完成", "color": "#52c41a" }]
    ]
  }
]
```

支持的块类型:`heading`、`paragraph`、`blockquote`、`code`、`divider`、`todo`、`bulleted_list`、`numbered_list`、`table`。

支持的文字样式:`bold`、`italic`、`underline`、`strike`、`code`、`color`、`backgroundColor`、`fontSize`、`href`。

颜色必须使用 `#RRGGBB`;`fontSize` 必须是 8 到 72 的整数。正文默认字号为 16px。标题默认使用客户端标题层级,只有显式传入 `fontSize` 时才覆盖标题内部文字。

表格块必须提供稳定 `id`,便于后续用 `replace-super-note-block` 或 `delete-super-note-block` 编辑/删除整张表。

## 文件资源

`attach-file` 会读取本地文件、计算 MD5、创建 Evernote Resource,并在正文中追加匹配的 `<en-media>`。MIME 会根据扩展名自动推断,也可以显式传入。

```json
{
  "guid": "note-guid",
  "filePath": "/tmp/demo.png",
  "fileName": "demo.png",
  "confirm": true
}
```

资源可以通过 `resourceGuid` 或 MD5 `hash` 导出和删除。

## 本地开发

```bash
npm install
cp .env.example .env
npm test
npm run verify
npm start
```

`npm run verify` 是只读验证:它会通过列出笔记本来验证 token 和 NoteStore URL 是否可用。

## 发布

```bash
npm test
npm pack --dry-run
npm publish --access public
```

发布前必须确认 npm tarball 中不包含 `.env`、真实 token、日志或私人笔记内容。

## 限制

- 使用 `evernote@2.0.5`,底层是较旧的 EDAM API。
- Evernote/印象笔记的笔记本组不是独立实体,本项目通过笔记本的 `stack` 字段实现组管理。
- 原生超级笔记工具不经过 Markdown 中转,适合保留加粗、颜色、链接、待办、表格等富文本样式。
- Markdown 兼容函数仍保留在内部,但不作为 MCP 工具暴露,避免误用导致富文本样式丢失。
- 资源工具支持本地图片、音频和通用附件,可按单资源导出和删除。
- 可折叠标题依赖印象笔记超级笔记的 `other-props.blockId`、`yinxiang.superNote` 与 `yinxiang.noteLayout` 标记;旧客户端可能只显示普通标题样式。

## 安全

不要提交真实 Developer Token、绑定私人账号的 NoteStore URL、请求日志或导出的笔记内容。更多说明见 [SECURITY.md](SECURITY.md)。

## 开源协议

本项目使用 MIT License。完整协议内容见 [LICENSE](LICENSE)。

TDQS

C2/5.0

Scored across 27 tools

Disambiguation4/5

Most tools have distinct purposes, but some overlap exists (e.g., delete-note vs expunge-note, append-super-note-blocks vs replace-super-note-block). Overall, agents can distinguish with care.

Naming Consistency4/5

Tools follow snake_case with verb-noun pattern (e.g., create-notebook, delete-note). Minor inconsistencies like 'get-notebook' vs 'get-note-raw' and some verbs (expunge) are unusual but acceptable.

Tool Count3/5

27 tools is on the higher side for a note-taking server. While each tool seems purposeful, the count feels heavy and could be streamlined (e.g., merge expunge-note into delete-note).

Completeness4/5

Covers core CRUD for notebooks, stacks, notes, super notes, and resources. Missing operations like rename notebook or search notebooks, but main workflows are present.

Maintenance

ActivityStale
ResponsivenessNo issues