- name
- wps-note
- description
- 通过 MCP 工具读取、编辑和管理 WPS 笔记,基于 block 文档模型,所有内容以 XML 格式交换。当用户说"帮我看看笔记"、"搜索笔记"、"创建一篇笔记"、"编辑笔记内容"、 "整理标签",或提到 WPS 笔记、WPS Note、云笔记时使用。也适用于排查 MCP 工具调用错误 (BLOCK_NOT_FOUND、EDITOR_NOT_READY 等)。
- metadata
- {"mcp-server":"wps-note","version":"1.0.0","category":"productivity","tags":["note-taking","document-editing","wps"]}
# WPS Note MCP Skill
核心操作模式:**先定位(outline / search)→ 再读取(read)→ 最后编辑(write)**。所有内容以语义 XML 格式交换,所有定位基于 `block_id`(10 位字母数字)。
## 何时使用
- 用户提到 WPS 笔记、WPS Note、云笔记、金山笔记
- 用户要求读取、编辑、搜索、总结、翻译笔记内容
- 用户需要创建笔记、管理标签、整理笔记库
- 需要排查 MCP 工具调用失败(`BLOCK_NOT_FOUND`、`EDITOR_NOT_READY` 等错误)
**不适用于**:本地 Markdown 文件操作、WPS 文档/表格/演示等其他产品、纯概念讨论。
## 核心概念
### Block 模型
- 笔记由 block 组成,每个 block 有唯一的 `block_id`。
- block 类型:`paragraph`、`heading`、`blockquote`、`code_block`、`list`、`table`、`image`(单图/图片分栏)、`horizontal_rule`、`highlight_block`、`columns`、`embed`、`note_audio_card`。
- `embed` block(电子表格、视频、LaTeX、倒计时等)为**只读占位符**,不可编辑。
- `note_audio_card` block 为语音录音卡片(**只读**),在 XML 中显示为 `<NoteAudioCard/>`,使用 `get_audio_transcript` 工具获取转写内容。
- 表格必须**整表替换**,无法编辑单个单元格。表格单元格仅支持简单块(段落、标题、引用、代码块、分隔线、图片),**不可在单元格内嵌套高亮块、分栏、表格**等容器类块。
- **容器嵌套限制**:`<highlightBlock>` 内仅支持简单块(段落、标题、引用、代码块、分隔线、图片),**不可嵌套** `<highlightBlock>`、`<columns>`、`<table>`。`<columns>` 的每个 `<column>` 内支持简单块和 `<highlightBlock>`,**不可嵌套** `<table>` 或 `<columns>`。
### note_id
- 大部分工具需要 `note_id` 来指定操作的笔记。
- 通过 `list_notes` 或 `search_notes` 获取 `note_id`;若用户要操作当前打开的笔记,可直接调用 `get_current_note` 获取。
- `get_note_info` 可获取笔记元数据(含标签),支持三种模式:单个 `note_id` 查询、批量 `note_ids` 查询(最多 100 个)、全量分页浏览(`page`/`page_size`/`limit`),无需读取全文内容。
### XML 输入输出
- 所有内容以语义 XML 格式收发,使用标签如 `<p>`、`<h1>`-`<h6>`、`<blockquote>`、`<codeblock>`、`<table>`、`<highlightBlock>`、`<columns>` 等。
- 每个块级标签通过 `id` 属性标识 block_id,如 `<p id="aB3kLm9xZq">内容</p>`。
- **重要**:写入操作(`edit_block` 等)的 `block_id` / `anchor_id` 只接受顶层 block ID(由 `get_note_outline` 返回)。`read_note` XML 中容器(`<highlightBlock>`、`<columns>`、`<table>`)内部段落的 `id` 仅供阅读参考,不可用于写入操作。
- 写入时提供 XML 格式内容,系统自动转换为内部 block 模型。`replace` 的目标 block 由工具参数 `block_id` 指定,`content` 建议不写 `id`;若显式写了根块 `id`,必须与目标 `block_id` 一致。`insert` 时新内容中的块级标签应省略 `id`,系统自动分配新的 `block_id`。
- 行内 mark 使用语义标签:`<strong>粗体</strong>`、`<em>斜体</em>`、`<s>删除线</s>`、`<u>下划线</u>`、`<a href="url">链接</a>`。
- **标签管理**:使用 `manage_note_tags` 工具管理笔记标签——直接添加/移除文件级标签,无需编辑文档内容。创建笔记后应调用 `manage_note_tags({ note_id, add: ["标签名"] })` 分配标签;多级标签用 `/`,调用参数不要带 `#` 前缀;编辑已有笔记完成后若无标签也应补充。
- 行内自闭合元素:`<emoji value="😀"/>`(表情)、`<latex formula="E=mc^2"/>`(行内公式)、`<br/>`(硬换行)。
- 样式属性通过 `<span>` 传递:`<span fontColor="#C21C13">红色文字</span>`、`<span fontHighlightColor="#FBF5B3">高亮文字</span>`、`<span fontSize="16">大号文字</span>`。
- **颜色受预设色板约束**,任意 hex 色值会被编辑器静默丢弃。各类颜色预设值:
- `fontColor`(12 色):`#080F17` `#C21C13` `#DB7800` `#078654` `#0E52D4` `#0080A0` `#757575` `#DA326B` `#D1A300` `#58A401` `#116AF0` `#A639D7`
- `fontHighlightColor`(9 色):`#FBF5B3` `#F8D7B7` `#F7C7D3` `#DFF0C4` `#C6EADD` `#D9EEFB` `#D5DCF7` `#E6D6F0` `#E6E6E6`
- `highlightBlock` 颜色(6 对 bg→border):`#FAF1E6`→`#FEC794`、`#FAE6E6`→`#F2A7A7`、`#E6FAEB`→`#AFE3BB`、`#E6EEFA`→`#98C1FF`、`#F5EBFA`→`#E5B5FD`、`#EBEBEB`→`#C5C5C5`
- `columnBackgroundColor`(42 色,含纯色和渐变):
- 6 基础色:`#FFF5EB` `#FFECEB` `#E8FCEF` `#EBF2FF` `#FAF0FF` `#F2F2F2`
- 18 扩展纯色:`#FCFAE1` `#FEF6E7` `#FFF5ED` `#FFF2F0` `#FFF2F4` `#FFF0F7` `#EEFFEB` `#EBFFF5` `#E8FCFC` `#EBF8FF` `#EBF1FF` `#F0EDFF` `#F2E7E4` `#F0E6DA` `#F5EEDA` `#EDF0EB` `#EDEEF0` `#F0E4DD`
- 6 饱和色:`#FEF49C` `#BCFAAF` `#ADF4FF` `#C2D3FF` `#FFC7C7` `#E0E0E0`
- 12 渐变色:使用 CSS `linear-gradient()` 语法,如 `linear-gradient(133deg,#FFFAF7 2.14%,#FFEDFE 96.88%)`
- 完整 XML 格式参考已集成到 MCP Server Instructions 中自动注入(视客户端支持情况)。未注入时可调用 `get_xml_reference` 工具按需获取。
### 只读 Token
- 部分笔记 token 为只读,写入工具会返回 `DOCUMENT_READ_ONLY`。
- 此时 `retryable: false`——不要重试,应告知用户。读取操作不受影响。
### 响应格式
所有工具返回统一的标准信封:
```json
{ "ok": true, "code": "OK", "message": "...", "retryable": false, "data": { ... }, "hints": [] }
```
- `ok`——调用是否成功。
- `code`——机器可读状态码(参见错误恢复)。
- `retryable`——为 `true` 时可直接重试。
- `hints`——建议的后续工具或操作。
## 工作流
### 1. 读取与理解笔记
```
get_current_note() → 获取 note_id + word_count + size_category(决定后续策略)
list_notes / search_notes → 按条件查找 note_id
get_note_outline(note_id) → 查看结构和 block ID(超大文档自动分页)
get_cursor_block() → 获取当前光标所在顶层 block_id
read_section(note_id, heading_id) → 读取某个章节
read_blocks(note_id, block_ids) → 批量读取指定 block
read_blocks(note_id, block_id, before, after) → 读取单个 block 及上下文
search_note_content(note_id, q) → 在笔记内搜索文本
read_image(note_id, block_id) → 读取图片 block 的实际内容(base64)
get_audio_transcript(shorthand_id) → 获取语音录音的转写内容
get_xml_reference() → 获取 XML 格式完整参考文档
```
**对于长笔记**,优先使用 `get_note_outline` → `read_section`,而非 `read_note`,以减少 token 开销。
### 分页读取大文档
当笔记超过 200 blocks 时,**read_note** 和 **get_note_outline** 的返回会自动分页——需通过 `offset` 和 `block_limit` 参数切换分页查看不同部分。笔记本身无 block 数量上限,这些参数仅控制单次读取返回量。
`read_note` 示例:
```
read_note({ note_id })
→ pagination: { total_blocks: 350, has_more: true, next_offset: 100 }
read_note({ note_id, offset: 100 })
→ pagination: { has_more: true, next_offset: 200 }
read_note({ note_id, offset: 200 })
→ pagination: { has_more: false } ← 读完
```
也可手动控制每页大小:`read_note({ note_id, offset: 0, block_limit: 50 })`
`get_note_outline` 同理——`has_more: true` 时用 `next_offset` 续读:`get_note_outline({ note_id, offset: next_offset })`
`read_section` 同理——截断时返回 `next_block_offset`,传入 `block_offset` 续读:
```
read_section({ note_id, heading_block_id, max_blocks: 50 })
→ truncated: true, next_block_offset: 50
read_section({ note_id, heading_block_id, block_offset: 50 })
→ truncated: false ← 读完
```
### 文档大小策略
`get_current_note` 和 `get_note_outline` 都返回 `word_count`、`size_category` 和 `estimated_xml_chars`,据此选择读取策略:
| size_category | 字数范围 | 策略 |
|--------------|---------|------|
| `small` | <5K 字 | `read_note` 直接读取全文 |
| `medium` | 5K-20K 字 | `get_note_outline` → `read_section` 按章节读取 |
| `large` | 20K-80K 字 | `search_note_content` 精准定位 → `read_blocks` 读取目标 + 上下文 → 编辑 |
| `very_large` | >80K 字 | 同 large,精准定位优先 `search_note_content`;`get_note_outline` 支持分页读取(offset/block_limit)可按需获取结构 |
**原则**:文档越大,越应该用搜索定位而非顺序读取。对于 large/very_large 文档,优先使用 search_note_content 找到目标 block,再用 read_blocks 读取其上下文。**操作当前笔记时,先调 `get_current_note` 获取 `size_category`,再决定路径**。
### 2. 编辑笔记内容
```
get_note_outline(note_id) → 获取最新 block ID
get_cursor_block() → 当前围绕光标位置编辑时,获取锚点 block
read_blocks(note_id, [target_id]) → 确认当前内容
insert_image(note_id, anchor_id, pos, src) → 插入图片(独立工具,不走 XML,当前需联网)
generate_image(prompt, width?, height?) → AI 文生图,返回图片 URL(配合 insert_image 插入笔记)
edit_block(note_id, op, ...) → 单个编辑操作(替换、插入、删除、更新属性、移动)
batch_edit(note_id, operations) → 多个操作合并为一次原子事务
```
**关键**:编辑后 block ID 可能变化。连续 insert 可直接使用返回的 `last_block_id` 做锚点;操作其他 block 前通过 `get_note_outline` 刷新。
**参数约束**:`edit_block` / `batch_edit` 只传当前 `op` 需要的字段。`replace` / `insert` 的 `content` 必须直接填写完整 XML 字符串,不能传纯文本、Markdown,或 `"把第二段改成……"` 这类自然语言编辑指令。
**连续插入的正确做法**(避免乱序):
- **优先**:在一次 `insert` 中将所有内容拼成完整 XML(如 `"<h2>A</h2><p>...</p><h2>B</h2><p>...</p>"`),按 XML 顺序依次插入,无需分多次调用。
- **链式**:如果必须分多次 `insert`,每次使用上一次返回的 `last_block_id` 作为下一次的 `anchor_id`,或在每次写入后调用 `get_note_outline` 刷新 ID。
### 3. 批量编辑(原子事务)
单个操作使用 `edit_block`,多个操作使用 `batch_edit` 合并为原子事务:
```
# 单个操作
edit_block(note_id, op: "replace", block_id: "id1", content: "<p>...</p>")
edit_block(note_id, op: "insert", anchor_id: "id2", position: "after", content: "<h2>...</h2><p>...</p>")
# 多个操作(原子事务)
batch_edit(note_id, operations: [
{ op: "delete", block_ids: ["id1"] },
{ op: "replace", block_id: "id2", content: "<p>...</p>" },
{ op: "update_attrs", block_id: "id3", attrs: { level: 2 } },
{ op: "move", block_id: "id5", anchor_id: "id2", position: "after" },
{ op: "insert", anchor_id: "id4", position: "after", content: "<h2>...</h2><p>...</p>" }
])
```
**执行顺序固定**(`batch_edit`):delete → replace → update_attrs → move → insert(与数组顺序无关)。
### 4. 管理笔记与标签
```
get_note_info(note_id) → 获取单个笔记元数据(含标签)
get_note_info(note_ids: [...]) → 批量获取多个笔记元数据(最多 100 个)
get_note_info(page, page_size) → 分页浏览所有笔记元数据
search_notes(keyword, tags, since, before) → 搜索笔记(也可按标签筛选笔记)
create_note(title) → 创建空白笔记(需用 edit_block 添加内容)
import_web_page(url) → 从白名单域名导入网页为笔记(微信公众号、知乎、豆瓣等)
delete_note(note_id) → 不可恢复——必须与用户确认
sync_note(note_id) → 触发同步
find_tags() → 列出所有标签
find_tags(keyword) → 搜索标签
manage_note_tags(note_id, add, remove) → 添加/移除笔记的文件级标签
get_note_stats(detailed) → 使用统计
```
## 工具速查表
### 读取/定位工具
| 工具 | 用途 | 关键参数 |
|------|------|----------|
| `get_note_outline` | 获取结构大纲(含 title、word_count、block_count、size_category、estimated_xml_chars、blocks 列表、pagination)——获取 block_id 和文档规模的主要方式,超大文档自动分页 | `note_id`、`max_depth?`、`include_preview?`、`offset?`、`block_limit?` |
| `get_cursor_block` | 获取当前光标所在顶层 block 的 `block_id`、`block_type` 和 `note_id`;光标位于高亮块或分栏内部时不支持 | *(无参数)* |
| `read_blocks` | 按 ID 批量读取 block 的 XML 内容和属性,或读取单个 block 及前后上下文 | `note_id`、`block_ids`(批量)或 `block_id`+`before?`+`after?`(上下文) |
| `read_note` | 读取全文或分页读取(XML),超大文档自动分页并返回 pagination(含 has_more + next_offset) | `note_id`、`max_length?`、`offset?`、`block_limit?` |
| `search_note_content` | 在笔记内搜索文本,返回匹配 block 的 block_id/type/preview,用于编辑前定位 | `note_id`、`query`、`max_results?` |
| `read_section` | 按标题读取完整章节(到下一同级标题),截断时返回 next_block_offset 用于续读 | `note_id`、`heading_block_id`、`max_blocks?`、`block_offset?` |
| `read_image` | 读取图片 block 的实际内容(base64),可供视觉理解 | `note_id`、`block_id` |
| `get_audio_transcript` | 获取语音录音(NoteAudioCard)的转写文本,返回句子列表(含说话人、时间戳) | `shorthand_id`(从 outline 的 `note_audio_card` block attrs 获取) |
| `get_xml_reference` | 获取 XML 格式完整参考文档(所有标签、属性、写入示例) | *(无参数)* |
**示例:**
```
get_note_outline({ note_id: "abc123" })
Auf GitHub ansehen