笔记本电脑工具mcp
用于Jupyter笔记本导航和编辑的MCP服务器。读取 .ipynb 直接将文件转换为JSON格式——无需Jupyter服务器,无需内核,无开销。
问题
在VS代码开发容器中工作的AI CLI代理(Claude Code、Gemini CLI、Codex)没有与Jupyter笔记本交互的好方法。笔记本是JSON文件,其中90%以上的字节是base64编码的图像输出和执行元数据。使用标准文件读取工具读取1MB笔记本电脑会在噪声上浪费约294K个令牌。代理在每个会话中都会重新发明笔记本解析逻辑,重复燃烧同一问题上的令牌。
建筑
6个文件,约700行,零依赖 mcp>=1.10.1:
notebook_tools_mcp/
__init__.py (35L) FastMCP instance + server instructions
_helpers.py (182L) Shared utilities: load/save, cell formatting, parsing
read_tools.py (251L) 6 read tools
search_tools.py (126L) 2 search tools
write_tools.py (104L) 3 write tools
server.py (16L) Entry point每个文件\<260行。单一责任。共享助手避免重复。没有循环进口。
设计决策
没有Jupyter服务器。 通过SSH在远程VS代码开发容器(Docker)中工作。添加Jupyter服务器意味着额外的内存、额外的复杂性,当VS Code已经以本机方式呈现笔记本时,则为零。
除此之外没有依赖关系 mcp. 笔记本是JSON格式的。Python的stdlib json 模块能够完美地读取它们。 nbformat (及其50多个可传递的Jupyter生态系统deps)是不必要的权重。
没有处决。 运行代码需要一个内核,而内核需要一个服务器。这就是这个工具要避免的复杂性。
仅限stdio传输。 MCP客户端按需启动,通过stdin/stdout通信,完成后退出。没有HTTP端点,没有WebSocket连接,没有持久进程。
基于索引的一致寻址。 所有11个工具都使用整数单元格索引。 nb_overview 显示索引→ nb_read_cell(15) 读取→ nb_write_cell(15, ...) 编辑。一个地址方案贯穿始终。
sort_keys=True 在拯救。 匹配Jupyter/nbformat约定以获得确定性输出。防止加载/保存周期之间的键重新排序产生嘈杂的git差异。
书写工具与笔记本编辑
Claude Code有一个内置的 NotebookEdit 工具(通过以下方式寻址单元格 cell_id 或 cell_number).此服务器还提供写入工具。两者都是有意保留的:
| MCP写入工具 | NotebookEdit(内置) | |
|---|---|---|
| 寻址 | 整数索引(匹配项 nb_overview) | cell_id 字符串或 cell_number (0索引) |
| 最适合 | 在 nb_overview → read → 编辑流 | 当VS Code或其他工具提供cell_id时 |
| 占地面积 | 102行 | 内置 |
MCP写入工具用于 工作流内聚性 --代理人使用 nb_overview 找到一个单元格已经有了索引。需要查找以获取 cell_id NotebookEdit将添加一个毫无意义的额外步骤。
我们故意没有构建的工具
这些被考虑并拒绝了,因为 nb_search / nb_search_dir 已经涵盖了它们:
| 被拒绝的工具 | 为什么 nb_search 足够了 | |
|---|---|---|
nb_dependencies(var) | nb_search(path, "var_name") 返回定义和用法;LLMs很容易区分 x = ... 从 ...x... | |
nb_function_map | nb_search_dir(dir, "^def\\s+\\w+", cell_type="code") | |
nb_imports_all | `nb_search_dir(dir, "^import\ | ^from\\s+\\w+\\s+import")` |
nb_compare_cells | 客服电话 nb_read_cell 两次 |
构建基于AST的依赖跟踪将增加约200行脆弱的代码,这些代码会跨越Python/R/Julia/bash单元格。当正则表达式搜索+LLM推理达到相同的结果时,这是不值得的。
代理如何发现何时使用这些工具
Claude Code(和类似的代理)根据三个渠道按优先级顺序决定使用哪个工具:
- MCP服务器
instructions--通过设置FastMCP(instructions=...)在__init__.py.注入服务器连接的每个对话的系统提示中。这就是“使用nb_search代替Grep for.ipynb”指南的所在。在调用任何工具之前,代理都会看到这一点。
- 工具文档字符串 --the
"""..."""在每一个@mcp.tool()功能。当代理发现工具时显示(例如通过工具搜索)。每个文档字符串都说明了该工具的功能以及何时更喜欢它而不是替代品。
- CLAUDE.md --项目级指令总是加载到上下文中。包含将任务映射到工具的决策表(例如“阅读笔记本”→ nb_overview,NOT Read工具”)。
这三个渠道都强化了同样的信息:使用 nb_* 工具 .ipynb,从来没有 Read/Grep.
安装
# pip
pip install git+https://github.com/tony-zhelonkin/notebook-tools-mcp.git
# uv
uv pip install git+https://github.com/tony-zhelonkin/notebook-tools-mcp.git对于开发(从本地克隆可编辑安装):
git clone https://github.com/tony-zhelonkin/notebook-tools-mcp.git
pip install -e notebook-tools-mcp/配置
添加 .mcp.json:
{
"mcpServers": {
"notebook-tools": {
"type": "stdio",
"command": "python",
"args": ["-m", "notebook_tools_mcp.server"]
}
}
}或通过切换 SciAgent工具包 插件系统:
./scripts/manage-addon.sh enable notebook-tools --project-dir /path/to/project
./scripts/manage-addon.sh disable notebook-tools --project-dir /path/to/project工具
所有工具 notebook_path (绝对路径)作为第一个参数,除非另有说明。
阅读工具
| 工具 | 参数 | 功能 |
|---|---|---|
nb_metadata | notebook_path | 内核信息、格式版本、单元格计数、文件大小、输出大小 |
nb_overview | notebook_path, include_output_sizes=true | 单元格索引、类型、行/字符计数、一线预览、输出大小 |
nb_read_cell | notebook_path, cell_index, include_outputs=false, max_output_chars=2000 | 按索引显示一个单元格的完整源代码,可选截断输出 |
nb_read_cells | notebook_path, cell_indices (例如。 "0,1,5-8"), cell_type=null, include_outputs=false | 使用范围语法批量读取,可选类型过滤器 |
nb_read_section | notebook_path, header, max_cells=50, include_outputs=false | 从标记标题到下一个相同或更高级别标题的所有单元格 |
nb_headings | notebook_path | 所有带有单元格索引和级别的降价标题 |
搜索工具
| 工具 | 参数 | 功能 |
|---|---|---|
nb_search | notebook_path, pattern (正则表达式), cell_type=null, context_lines=1 | 使用上下文在单元格中搜索正则表达式,可选类型过滤器 |
nb_search_dir | directory, pattern (正则表达式), cell_type=null, context_lines=0 | 搜索全部 .ipynb 按笔记本分组的目录中的文件 |
编写工具
| 工具 | 参数 | 功能 |
|---|---|---|
nb_write_cell | notebook_path, cell_index, source | 覆盖现有单元格的源内容 |
nb_insert_cell | notebook_path, cell_index (-1 附加), cell_type, source | 在指定位置插入新单元格 |
nb_delete_cell | notebook_path, cell_index | 删除单元格 |
典型的代理工作流程
1. nb_metadata(path) → Is this notebook big? What kernel?
2. nb_overview(path) → See all cells at a glance (index, type, preview)
3. nb_headings(path) → Understand section structure
4. nb_search(path, "pattern") → Find cells containing a variable/function/import
5. nb_read_cell(path, 15) → Read the specific cell you need
6. nb_read_cells(path, "15-20") → Read a range of related cells
7. nb_read_section(path, "Results") → Read everything under a heading
8. nb_write_cell(path, 15, src) → Edit the cell in-place关键见解: 从...开始 nb_overview,然后向下钻切勿通读整本笔记本。
代币经济学
针对真实项目笔记本进行测试:
| 笔记本 | 文件大小 | 单元格 | 已满 Read 工具 | nb_overview | nb_read_cell | nb_search |
|---|---|---|---|---|---|---|
| NB00(最小) | 51 KB | 30 | ~13K令牌 | ~500令牌 | ~50-200令牌 | ~100令牌 |
| NB01(最大) | 1.15 MB | 41 | ~294K代币 | ~690代币 | ~100-400代币 | ~50-200代币 |
对于1.15MB笔记本电脑, nb_overview 实现 约425倍代币减少 vs读取完整文件。单个单元格读取成功 减少约700-2900倍.
CLAUDE.md代码段
将此添加到您的项目 CLAUDE.md 引导Claude Code使用笔记本工具而不是内置工具 .ipynb 文件夹。服务器也自带 instructions (自动注入系统提示),但 CLAUDE.md 强化确保了行为的一致性,尤其是在代理在多种工具之间进行选择时。
### Working with .ipynb files
**ALWAYS use `notebook-tools` MCP tools instead of built-in tools for `.ipynb` files:**
| Task | Use this | NOT this | Why |
|------|----------|----------|-----|
| Read notebook | `nb_overview` then `nb_read_cell` | `Read` tool | Read loads raw JSON with base64 images, wastes 100K+ tokens |
| Search notebook | `nb_search` / `nb_search_dir` | `Grep` tool | Grep sees JSON structure, nb_search sees cell source code |
| Edit notebook cell | `nb_write_cell` (by index from nb_overview) | — | Consistent index-based workflow |
| Edit notebook cell | `NotebookEdit` (by cell_id) | — | Use when cell_id is known from another source |
| Insert/delete cells | `nb_insert_cell` / `nb_delete_cell` | — | Index-based, consistent with nb_overview |
**Workflow:** `nb_overview` (get cell indices) → `nb_read_cell` or `nb_search` → `nb_write_cell`.
All 11 tools are in the `notebook-tools` MCP server. Start with `nb_overview` for any notebook interaction.当NotebookEdit是更好的选择时
MCP编写工具和Claude Code的内置 NotebookEdit 用不同的地址解决相同的问题(编辑笔记本单元格):
- 主控程序
nb_write_cell:按整数索引的地址。最好是当你已经在nb_overview→nb_read_cell→ 编辑流,因为您已经有了索引。 - 笔记本编辑:地址按
cell_id(一个类似的字符串"abc123")或cell_number(0索引整数)。最好是当其他东西给你cell_id时——例如,VS Code的笔记本渲染器,或id字段显示在nb_read_cell输出。
在实践中,MCP写入工具的使用频率更高,因为典型的代理工作流程始于 nb_overview,其中显示了指数。 NotebookEdit 当代理已经拥有 cell_id 来自非MCP来源,或在需要时 NotebookEdits edit_mode: "insert" 语义(插入 *之后* 一个特定的cell_id,而不是 *在* 索引位置)。
这两种工具可以安全共存。服务器的 instructions 字段告诉代理在 nb_overview 工作流程。只要代理在同一回合中不在同一个单元格上同时使用这两个元素,就没有冲突。
更新日志
v0.3.0(2026-02-25)
- 修复: 添加
sort_keys=True到save_notebook用于符合Jupyter/nbformat约定的确定性JSON输出 - 代理商指导: 添加
FastMCP(instructions=...)使用工具选择决策树(注入代理系统提示符) - 代理商指导: 重写所有11个工具文档字符串,以指定何时使用每个工具与内置替代工具
- 文件: 记录写入工具与Claude Code内置NotebookEdit的关系
- 文件: 添加了“代理如何发现何时使用这些工具”一节,解释了3通道指导模式
v0.2.0(2026-02-25)
- 添加了写入工具:
nb_write_cell,nb_insert_cell,nb_delete_cell - 模块化为6文件架构
- 添加
nb_headings,nb_read_section,nb_search_dir
v0.1.0
- 初始版本:
nb_metadata,nb_overview,nb_read_cell,nb_read_cells,nb_search
