mcpField
L
LogiSheets

LogiSheets

本地服务
docs.logisheets.com数据与分析414 周前更新

关于 LogiSheets

LogiSheets 是 Rust 编写的电子表格引擎的 MCP 服务,面向需要可靠计算和生成 .xlsx 文件的 AI Agent。它以命名表格(block)代替单元格坐标组织数据,并把结构与含义写入文件,便于之后的会话继续读取。

主要功能

  1. 01兼容 Excel 公式的确定性计算
  2. 02以字段名和主键寻址的命名表格
  3. 03保存真实 .xlsx 文件并保留结构说明
  4. 04引用 BLOCKREF 与 #FIELD 的规则描述
  5. 05预览修改、目标求解与依赖追踪
  6. 06随数据更新的原生 Excel 图表

适用场景

  1. 01构建多年期收入或现金流预测模型
  2. 02对假设参数做敏感性分析与反向求解
  3. 03在新会话中接手并解释已有的电子表格

MCP 相关

作为 MCP 服务,向客户端提供约 32 个默认工具,用于创建表格、计算公式、保存 .xlsx 与生成图表。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"logisky-logisheets": {
"command": "npx",
"args": [
"-y",
"logisheets-mcp"
],
"env": {
"LOGISHEETS_MCP_TOOLS": "<LOGISHEETS_MCP_TOOLS>"
}
}
}
}
启动命令npx -y logisheets-mcp
需要配置的环境变量
LOGISHEETS_MCP_TOOLSTool surface: 'core' (default, 32 tools) or 'full', which adds formatting, comments, links, undo/redo and raw structure operations.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmlogisheets-mcp0.6.0

工具

32

收录的工具列表 · 更新于 2 周前

参数类型必填说明
namestring否从 base64 加载时向引擎报告的文件名。
pathstring否要加载的现有 .xlsx 文件路径。省略则创建空白工作簿。
xlsx_base64string否用于没有共享文件系统时传入的 Base64 编码 .xlsx。条件允许时请使用 `path`。

详细介绍

logisheets-mcp

logsky/logisheets-mcp

一个 Agent 可以借助其思考的真实电子表格引擎。 它能处理 Excel 兼容公式,无需在脑中计算;它通过名称而非坐标定位表格;最终生成真正的 .xlsx 文件,供人打开、审计并继续使用。

一个基于 LogiSheets 的 MCP 服务。LogiSheets 是用 Rust 编写的电子表格引擎。采用 MIT 许可证,可在你的机器上运行,不会打开任何网络套接字。

网格的问题

让模型做一份五年预测,它就会写出二十个公式,还要手动调整每个公式的行号。静默错误就藏在这里:其中一个公式读取了它本该读取 B8 却读成 B7 的单元格,合计看起来似乎合理,也不会触发任何错误。

接着,工作表发生了变化。有人在顶部插入一行、删除一年或添加一列。模型持有的每个坐标都会偏移一位,而且它无从察觉;于是接下来的几轮,它都在重新读取单元格、确认内容的位置,而不是回答你提出的问题。

而每次“假设”分析都要往返一轮——写入输入、重新计算、读取输出、再还原。十六种情景就要往返十六次;如果扫描到一半失败,还会把某个情景遗留在模型里。

数据块

数据块是工作表上的一个命名表格。行有键,列有名称,所有内容都通过它们而非位置来定位。

  • 一个字段的公式只需声明一次,适用于整列,而不是逐个单元格设置。添加一行就会自动计算,无需担心第二十个公式出错。
  • 引用会标明其含义:键为 Y3 的行中的 pv 字段。即使在其上方插入一行,该引用仍然指向同一内容,因为它从未使用过“第 8 行”这样的说法。
  • 计算值由引擎管理。 公式字段不能被模型自行算出的数字覆盖。
create_block     proj    fields: year, fcf, df, pv
set_field_rule   proj.pv = fcf × df          ← once, for the column
add_block_rows   Y1 … Y5
describe_block   proj
  →  Y1 147.2727   Y2 144.5950   Y3 141.9660   Y4 139.3848   Y5 136.8506

… the sheet is then reshaped: two rows inserted at the top, a column at the left …

describe_block   proj
  →  Y3 141.9660               ← same answer, same address, nothing re-derived

Agent 会在工作过程中创建数据块,无需提前准备。你可以将它用于空白工作簿,也可以用于别人发给你的电子表格——convert_to_block 会接管普通单元格中已有的表格,读取标题行中的字段名称,并确定哪一列是键。

第二个会话

构建电子表格的对话,几乎从来不是需要回答相关问题的对话。一周后开启了一个新会话,没有任何上下文,手里只有文件——文件记录的内容,就是该会话能够知道的内容。

网格记录的是坐标。=B11*$B$3*(1-$B$4) 虽然正确,却毫无意义,除非 Agent 获取标签列并推断出 A3 描述的是 B3。不如把含义写进架构,再存入 .xlsx:字段名称、键列、引擎会计算哪些字段,以及每个字段背后的规则。调用一次 list_blocks,工作簿就能介绍自己;调用一次 describe_block,规则就会以 #FIELD("revenue")*BLOCKREF("assum","margin","v") 的形式返回——这是直接的解释,而不是又一个查找问题。

架构仍然只能说明记录的结构。记录的含义需要用文字描述,因此区块会带有描述:调用 create_block 时写上一两句话,或者对后来采用的表格使用 set_block_description,说明每一行代表什么、不明显的字段存放什么,以及后来的读者不得改动什么。描述保存在文件中,并会通过 describe_block 返回。这样,下一个会话就能读懂其意图,而不必根据列名推断。

src/cold-read.test.ts 对此作了明确验证,而非仅仅断言。它在一个会话中构建模型并保存,然后在第二个会话中重新打开文件;两个会话互不共享任何内容——各自使用自己的服务、工作簿,且没有记忆。接着:一次 list_blocks 调用就能恢复每个区块的字段、键字段、计算字段和行数;每条返回的规则都会经过检查,确认其中包含 #FIELD 或 BLOCKREF,且完全没有 A1 坐标;新会话仅凭对结构的了解写出一个 BLOCKREF 公式,引擎计算的结果与测试中独立进行的算术计算一致;而且 trace 会指出某项假设被哪些内容读取,以便在有人编辑之前了解影响。传输成本按线路上实际发送的数据计量,也就是宿主展示给模型的同一段文本:五行模型为 540 B,105 行模型为 545 B,各调用一次。读取架构的复杂度是 O(columns);读取网格以理解内容的复杂度则是 O(cells)。获取数据仍然要付出数据本身的成本——这 105 行数据为 11 kB——而关键在于,第二个会话可以自行选择。

更详细的版本及其理由:docs/the-second-session.md。

可重新计算的图表

Agent 被要求制作图表时,通常会生成一张图片。图片在生成时是准确的,但之后人类更改了某项假设,它就成了一张展示错误数字的图片。

chart_from_block 会将图表写入工作簿,而工作簿中的图表存储的是引用,绝不是值:

chart_from_block   rev   value_fields: q1, q2   category_field: region
  →  <c:val><c:numRef><c:f>Rev!$B$1:$B$3</c:f></c:numRef>

这是保存后的 .xlsx 中原生的 Excel c:chartSpace——与 Excel 自行写入的对象相同。编辑源单元格后,图表也会随之更新,无论是在 Excel 中还是在这里。向区块添加一个区域,它也会自动出现在图表中,因为数据系列绑定的是字段,而不是创建图表时该字段恰好占据的单元格:插入行或列不会导致图表指向错误的位置。对于从未成为区块的数据,chart_insert 也能对任意 A1 范围执行同样的操作。

src/agent-loop.test.ts 根据文件的字节内容而非工具的返回值来验证这一点:构建一个区块,为其创建图表,保存后解压 .xlsx,检查图表部件是否存在,以及其数据系列是否为指向工作表的 <c:f> 引用。

基准测试

用数据衡量,而非空口断言。与另外两个可处理本地 .xlsx 的 MCP 服务进行对比:spreadsheet-kit 0.11.1,它自带 Rust 重算引擎;以及基于 openpyxl 的安装量最高的 excel-mcp-server 0.1.8:

本项目spreadsheet-kitexcel-mcp-server
写入公式并读取其值3030"=SUM(A1:A2)"
五年 DCF,每股价值20.803603 · 15 次调用20.803603 · 6 次调用公式文本
4×4 敏感性分析,16 个答案1 次调用,950 B16 次调用,1245 B不支持
反向求解输入值1 次调用,202 B18 次调用,1399 B不支持
稍后重新打开并解释4 次调用,2.4 kB5 次调用,21 kB2 次调用,24 kB
结构变更后再次回答19.383943#VALUE!公式文本
保留接手文件的功能8 项中的 8 项8 项中的 8 项8 项中的 8 项

复现方式——每项任务使用一个文件,每个文件都会运行全部三个服务:

npm run build                     # ours is driven as dist/cli.js
python3 bench/t1_compute.py       # bench/t*.py

另外两个参测服务必须先能访问:spreadsheet-kit 使用 amd64 Docker 镜像,excel-mcp-server 使用 $BENCH_WORK/.venv 中的虚拟环境(默认路径为 /tmp/bench-work)。具体启动方式见 bench/contestants.py。

这些任务在读取其他任何服务的工具列表之前就已提交(bench/TASKS.md),每个预期值都由 Python 独立推导,而非读取服务的输出;我们预期会失败的任务也特意列在其中。

有三点需要说明,避免过度解读表格。"=SUM(A1:A2)" 并非错误:openpyxl 会存储公式但不计算,因此该服务能写出正确的模型,却无法回答有关模型的问题。spreadsheet-kit 是真正的同类产品,能正确处理所有可尝试的任务,而且构建模型所需调用次数比我们更少——我们额外的调用用于声明架构,这种取舍带来了下文各行所示的收益。至于读取这一行,每个服务读取的都是自己写入的文件,因此这一差距只有一半能应用到由用户创建的电子表格上。最后一行的起点是 8 项中 0 项;正是编写这项任务时,我们才发现保存操作会丢弃引擎无法识别的所有内容。

安装

需要 Node 20+。

npm install -g logisheets-mcp

对于 Claude Desktop,将以下内容添加到 claude_desktop_config.json(macOS: ~/Library/Application Support/Claude/claude_desktop_config.json;Windows: %APPDATA%\Claude\claude_desktop_config.json),然后重启:

{
    "mcpServers": {
        "logisheets": {
            "command": "npx",
            "args": ["-y", "logisheets-mcp"]
        }
    }
}

任何能启动 stdio 服务的 MCP 宿主都可以采用相同方式配置——Cursor 会从 ~/.cursor/mcp.json 读取相同的配置块。

试用

为我构建一个三年期收入模型:100 件产品,每件售价 $9.50,年增长率为 40%,销售成本为 30%。然后将其保存到 ~/model.xlsx。

返回的数字来自引擎,而非模型的猜测;.xlsx 文件中包含实时公式——在 Excel 中更改一项假设,就能看到它重新计算。要在不涉及 LLM 的情况下体验同样的功能,可以运行 npm run build && npm run demo,它会通过 stdio 驱动真实服务,并在运行过程中检查每项结果。

工具

默认有 32 个工具。工具选择准确率会随着列表增长而下降,而且每轮对话中每个工具描述都会占用上下文。

工具功能
open_workbook新建工作簿,或加载现有的 .xlsx。可选——首次使用时会自动创建一个。
save_workbook写入一个真正的 .xlsx 文件。这是交还工作的方式。
export_xlsx以 base64 格式导出文件,适用于没有共享文件系统的宿主。
list_blocks列出每个工作表和区块,以及下一个区块应放置的位置。
describe_block查看区块的架构、键、字段规则、描述,以及可选的字段值。
eval_formula计算公式并返回结果。不保存任何内容。
create_block创建一个命名表格。第一个字段是行键。
convert_to_block将已存在于普通单元格中的表格就地转换为区块。
set_block_description用文字说明区块的用途,并写入文件。
add_block_rows添加记录——添加到末尾,或添加到 after_key / before_key 指定的位置。
delete_block_rows删除记录。
move_block_row按键重新排列行。仅改变呈现顺序,不改变任何值。
set_block_cells按 (block, row_key, field) 写入单元格。支持批量操作,且具有原子性。
set_field_rule为字段设置公式、验证规则或可编辑性规则。
create_analysis_block在表格下方创建汇总行,根据配方生成,而非直接写入。
edit_analysis_block更改要汇总的字段及汇总方式,同时保留引用名称。
create_pivot对区块进行交叉汇总:每组一行、每个值一列,并保持实时更新。
edit_pivot就地调整数据透视表的结构——也是修复损坏的数据透视表的唯一方法。
refresh_pivot使数据透视表的行列与其来源重新一致。
list_violations列出违反字段验证规则的单元格及原因。
list_names列出工作簿中定义的名称,以及每个名称的引用对象。
preview_changes查看编辑将会产生的效果,但不实际执行——可以预览单个假设,也可以在一次调用中预览整组情景。
trace通过依赖关系图查看单元格读取了什么,以及有哪些单元格读取了它。
goal_seek找出能使输出达到目标值的输入。在引擎内部搜索。
create_sheet添加工作表。
chart_from_block按字段名称为区块创建图表。之后新增的行也会纳入图表。
chart_insert为任意 A1 范围创建图表——对应原始单元格的操作。
chart_list列出工作表中的图表:类型、标题,以及每个数据系列读取的范围。
chart_update就地重新配置图表——包括类型、数据系列、坐标轴和标签。
chart_delete移除图表。
get_cells / set_cells用于处理没有结构的数据的原始单元格备用接口。

公式兼容 Excel,另外还支持 BLOCKREF(block, key, field),用于按名称读取区块单元格。在字段规则中,#FIELD("name") 表示同一行中的同级字段,#FIELD("name", "key") 表示同一区块中的另一行——即携带该键的行,而非按位置偏移的行。

preview_changes 和 goal_seek 是两个能改变模型探索方式的工具:每个情景都在自己的临时分支上运行,随后丢弃。因此,只需一次调用就能生成 4×4 敏感性网格并返回 16 个数字,而工作簿不会写入任何内容;逆向求解也只需一次调用,而不是每次二分迭代都调用一次。trace 能回答公式文本无法回答的问题——单元格读取了什么并不是重点,关键是哪些单元格读取了它。在修改假设前,你需要了解的正是这一点。

分析区块和数据透视表是由引擎推导出的汇总。Agent 声明配方——指定区块、字段和函数——引擎便据此生成所有公式。因此,重命名来源字段时,汇总会自动重建,而不会失效;之后新增的行也会自动计入。两者都存储在普通区块中,因此 BLOCKREF("by_region", "East", "Q2") 可以引用交叉汇总中的一个单元格,并用于后续计算。否则,Agent 通常会读取表格内容到上下文中,计算总和,再写下答案;这样得到的是一个常量,从下一行起就会出错。 list_names 属于核心功能集,而用于写入已定义名称的三个工具不属于,这是有意为之。已定义名称是带有标签的坐标范围:Sales = Sheet1!$B$2:$B$20 不会在添加行时扩展,而这正是区块要消除的脆弱性。不过,别人构建的工作簿可能充斥着这类名称,而且如果不知道 Sales 覆盖的范围,就无法理解 =SUM(Sales)——因此,读取它们有助于了解情况,而用它们构建则是在绕过更好的工具。

在信任数据透视表之前,有一点值得了解:其中的数字是实时的,但形状不是。公式无法添加行,因此,数据透视表创建后才首次出现在源数据中的分组会直接缺失——所有数字都正确,表格却不完整,而且看不出任何异常。describe_block 会指出缺失的分组,refresh_pivot 会将其恢复,这就是这两个工具属于核心功能集、而不是藏在标志后面的原因。

将 LOGISHEETS_MCP_TOOLS=full 设为 full,即可使用 73 个工具:撤销/重做、格式设置、合并、批注、检查点、区块移动/调整大小、跨区块链接、区块权限、chart_suggest、定义和重命名名称、原始行/列结构。修改工具带有 MCP 的 readOnlyHint / destructiveHint 注释,因此宿主可以要求先审批再执行。

图表工具保留了命名空间前缀,而其他所有工具都省略了前缀。在图表命名空间中,它们称为 list、insert、update 和 delete。当一个裸 delete 与 delete_rows 和 delete_block_rows 并列时,模型只能碰运气——本节存在的目的,就是避免这种情况。

返回的文件

save_workbook 会写出一个真实的 .xlsx 文件,并返回一个 MCP 资源链接——包含 uri、媒体类型和大小——而不是文件字节;对于一个 200 KB 的工作簿,字节数据会占用约 280 KB 的上下文,却不会让模型学到任何东西。需要读取文件的宿主可以从 workbook://current.xlsx 读取;对于完全不实现资源的宿主,export_xlsx 会返回 base64。

公式可以写成 BLOCKREF("proj","Y3","pv"),供人阅读;也可以解析为纯坐标,供 Excel 处理。

一个 MCP 会话持有一个活动工作簿,并在多次工具调用间保持其状态——正是这种持久性让它成为记忆,而不是计算器。

读写操作可以访问服务器进程能够触及的任何位置;这对于本地 stdio 服务来说很正常,也与官方文件系统服务的权限模式相同。请以仅拥有你打算授予权限的用户身份运行它。

无网络

没有套接字、没有端口、没有遥测。宿主会将其作为子进程启动,双方通过 stdin 和 stdout 上的换行分隔 JSON-RPC 进行通信;引擎也是同一进程中的 WASM,因此公式是函数调用,而不是请求。隔离网络的机器也支持运行此工具。经过检查,而非仅仅声称:完成一个完整会话——创建区块、附加字段规则、计算公式、保存 .xlsx——之后,进程持有六个管道,没有套接字,也没有监听端口。

开发

这是一个精简封装,基于三个 LogiSheets 包: logisheets-runtime(无头引擎)、logisheets-logician(工具定义)以及 Rust/WASM 核心。

npm install && npm test

若要同时开发引擎,请将 LogiSheets 检出到同级目录,构建其包,然后运行 npm run link:local——该命令会将这三个包符号链接到 node_modules,这样本地引擎的更改就会立即生效,无需重新安装。每次运行 npm install 后都要重新运行该命令。

若要将其用作库,createServer 会返回 MCP Server、WorkbookSession 和工具映射,因此你可以通过任意传输方式托管它:

import {createServer} from 'logisheets-mcp'
const {server, session, tools} = createServer({mode: 'full'})

许可证

MIT。属于 LogiSheets 项目。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。