mcpField
L
LaTeX Look

LaTeX Look

本地服务
github.com生产力01 天前更新

关于 LaTeX Look

LaTeX Look 面向 Agent 和 LaTeX 作者,可查看编译页面并核验编辑效果。它在一次调用中整合页面渲染、源码行定位和构建对比,也提供 CLI 与 MCP 服务。

主要功能

  1. 01编译并渲染 LaTeX 页面
  2. 02将 PDF 坐标映射到源码行
  3. 03对比页面与先前构建
  4. 04审查文档中的编辑变化
  5. 05用于手动检查的 CLI

适用场景

  1. 01发现编译未报错的版式问题
  2. 02定位页面区域对应的源码
  3. 03通过前后差异核验编辑

MCP 相关

MCP 服务向 MCP 客户端提供 `latex_look` 工具。它返回页面图像,并支持选择页面、文本定位、坐标到源码映射、对比和审查选项。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"fangchenghao-latex-look": {
"command": "npx",
"args": [
"-y",
"@fffangchenghao/dsh-latex-look"
]
}
}
}
启动命令npx -y @fffangchenghao/dsh-latex-look

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

安装包
npm@fffangchenghao/dsh-latex-look0.4.0

工具

1

收录的工具列表 · 更新于 3 天前

参数类型必填说明
dpinumber否渲染分辨率,范围为 50-300。默认值为 120。
filestring是主 .tex 文件的路径(绝对路径,或相对于当前目录的路径)。
pagenumber否要渲染的 PDF 页面,从 1 开始计数。使用 `text` 时省略,此时会自动查找页面。
textstring否页面上可见的短字符串(标题文字、标题或独特短语)。解析为其源文件:行号和页码。
auditboolean否审查每一页相对于此文档上一次审查的布局回归:页面内容提前结束、页面内容从较低位置开始、几乎空白的页面,但仅检查由本次编辑引入的问题。对整类页面进行更改(如标题文字、页眉、间距)后运行。
freshboolean否忽略构建缓存,从头开始编译。仅在怀疑缓存已过期时使用。
enginestring否auto | xelatex | lualatex | pdflatex | latexmk | tectonic。默认值为 auto,它会根据文档使用的引擎进行选择。
pointXnumber否页面上某个点的 X 坐标,需与 pointY 一起提供。可传入先前差异结果的 bbox,以检查发生了什么变化。
pointYnumber否同一点的 Y 坐标,单位为 PDF 点,原点为页面左上角。
comparestring否同一文档较早版本的 PDF 路径。系统会将页面与其进行差异比较,并渲染一张修改前图像。
sequencestring否检查以此前缀开头的编号标签的阅读顺序(例如 '图' 或 'Figure')。图形变成浮动体而相邻内容仍保持行内时会导致顺序颠倒:读者翻页后先看到图 3-4,再看到图 3-3。
auditBlankMmnumber否页面底部的空白达到多少毫米时,审查才将其判定为页面空洞。默认值为 30。

详细介绍

latex-look — 教会 Agent 看懂你的 LaTeX

npm tests license

English · 简体中文

一页文档编译成功但看起来仍有问题,经过五次修改后修复完成

左图:编译时零错误。右图:只需五句话,读者就能大声指出问题——“删掉标题周围的横线”“这张表是网格表,改成 booktabs 表”“这个链接超出页面了”“这张图太宽了”。在 examples/broken-layout 中亲自试试。

一个 DeepSeek Harness 插件,只添加一个工具:latex_look。

只读取 .tex 源码的 Agent 就像盲人:文档可以零错误地编译成功,但外观仍然有问题。latex_look 会编译文档、将页面渲染为图像、把页面上的任意位置映射回确切的源代码行,并对比上次编辑所造成的变化——一次调用即可完成。

        ┌─────────────┐   latex_look   ┌──────────────┐
        │   agent     │ ─────────────► │  pdf → png   │
        │ (edits .tex)│                │  synctex     │
        └─────────────┘ ◄───────────── │  pixel diff  │
              ▲          image + line  └──────────────┘
              └─────────────── verification ───────────┘

阅读案例研究:一本 215 页的 LaTeX 书籍,按读者的方式阅读——163 张图、129 个公式,以及六类能顺利编译通过的问题。

为什么只用一个工具,而不是三个

渲染、定位和对比是实现细节。Agent 需要一个连贯的动词——“看看这一页”——就像人一样。latex_look 会在一次调用中完成编译、渲染、解析和对比,因此工作循环是:

look → diagnose → edit .tex → look again → confirm the change → report

安装

需要 Node ≥ 18、TeX 引擎(xelatex/lualatex/pdflatex/latexmk 或 tectonic)、synctex 和 ghostscript。

本仓库就是这个程序包:package.json 声明了 dsh.bundle.patch,而 cordis.patch.yml 会插入一行。

git clone https://github.com/fangchenghao/latex-look

然后将其安装到当前配置中(在 Harness 中通过插件管理器安装):

plugin_manager  action: install_bundle  target: /absolute/path/to/latex-look

这会添加 latex-look 这一行并注册 latex_look 工具。替换已安装程序包的源代码后,需要重启 Harness 才能加载新一代模块。

该程序包已发布到 npm,名称为 @fffangchenghao/dsh-latex-look,因此也可以直接从注册表安装同一行:

plugin_manager  action: install_bundle  target: @fffangchenghao/dsh-latex-look
更新

插件会在后台每天检查一次注册表;如果有较新版本,只会在工具回复中追加一行——不会反复提醒,离线机器也不会收到任何提示。要升级,只需再次安装同一程序包:

plugin_manager  action: install_bundle  target: @fffangchenghao/dsh-latex-look

在运行中的配置中,升级会立即生效;Harness 会在下次启动时重新加载新一代模块,因为 core.mjs(与 index.js 不同)不会热重载。

在检出目录中,也可以直接执行检查:

npx latex-look --version
npx latex-look --check-update
发布

打上 v* 标签后,会在安装了 TeX 和 Ghostscript 的 Ubuntu 上运行测试套件,验证标签与 package.json 相符,并发布到 npm。令牌来自仓库密钥 NPM_TOKEN。

可选:知识技能

这个工具让 Agent 拥有双眼。SKILL.md 为其提供 LaTeX 知识,帮助它根据所见采取行动——其中包含“症状 → 原因 → 修复”操作手册(你想去掉的横线通常来自 \pagestyle/fancyhdr,而不是多余的 \hline)。将它复制或符号链接到技能根目录:

mkdir -p ~/.dsh/skills/latex-look
ln -sf "$PWD/SKILL.md" ~/.dsh/skills/latex-look/SKILL.md
CLI,供人类使用和测试
node bin/latex-look.mjs book.tex --page 37
node bin/latex-look.mjs book.tex --text "表3.1"
node bin/latex-look.mjs book.tex --page 12 --compare previous --json
node bin/latex-look.mjs book.tex --page 1 --audit   # what did the last edit break, anywhere?

CLI 与插件使用相同的引擎,且不需要 Harness,因此无需重新加载任何内容,就能快速检查修改。

面向 Claude Desktop、Cursor 和 Codex 的 MCP 服务

同一引擎也以 Model Context Protocol 服务的形式提供,因此不了解 DSH 的客户端也能使用它。它使用相同的 look(),回复中的文字也相同——插件采用 Harness 形式,而这是通用形式。

{
  "mcpServers": {
    "latex-look": {
      "command": "npx",
      "args": ["-y", "@fffangchenghao/dsh-latex-look", "mcp"]
    }
  }
}

将其放入 claude_desktop_config.json(Claude Desktop)、~/.cursor/mcp.json (Cursor),或作为 TOML 代码块放入 ~/.codex/config.toml:

[mcp_servers.latex-look]
command = "npx"
args = ["-y", "@fffangchenghao/dsh-latex-look", "mcp"]

它提供一个工具 latex_look,参数与其他地方相同: file、page、text、pointX/pointY、compare、audit、sequence、dpi。 页面会以图像内容块的形式返回,因此模型能看到页面本身。

要求与通常一样——需要一个 TeX 引擎,并且 ghostscript 位于 PATH 中:

brew install --cask mactex-no-gui ghostscript     # macOS
sudo apt install texlive-xetex ghostscript        # Debian/Ubuntu
winget install MiKTeX.MiKTeX ArtifexSoftware.GhostScript   # Windows

在 Windows 上无需将任何内容添加到 PATH:插件会查找 gswin64c (这是 Ghostscript 在 Windows 上的实际名称);找不到时,会在 C:\Program Files\gs\gs*\bin 以及 TeX Live、MiKTeX 和 TinyTeX 的安装目录中查找。 如果你更希望明确指定,可以将 PATH 指向 C:\Program Files\gs\gs10.05.1\bin,它会优先使用该路径。

不会上传任何内容:每次调用都会编译你磁盘上已有的文档。

它已列入官方 MCP Registry,名称为 io.github.fangchenghao/latex-look,因此搜索 Registry 的客户端可以按名称安装;它也收录于 awesome-mcp-servers。

测试

在干净的检出环境中会运行三个测试套件——它们会创建自己的测试文件并编译真实文档,因此需要几分钟:

node test/smoke.mjs           # unit level: problem parsing, PPM, raster diff, aux detection
node test/scenarios.mjs       # 52 end-to-end cases driven through index.js
node test/scenarios-deep.mjs  # 29 cases: multi-file papers, beamer, twocolumn, images,
                              #   engine switching, the build cache, hostile inputs
node test/book-scenarios.mjs  # 15 cases against a real 208-page book (164 .tex files)
node test/book-tasks.mjs      # 18 real editing tasks on the same book (see below)
LATEX_LOOK_BOOK=/pristine/copy node test/book-tasks.mjs   # point it at an unedited copy

书籍测试套件需要一本真实的书,除非你指定一本,否则会跳过:

LATEX_LOOK_BOOK=/path/to/book node test/book-scenarios.mjs

这两个测试套件最重要,因为真实书籍的结构是根文件 → \input{main} → \input{chap1},并使用自定义的 .sty、181 张插图、术语表和 fancyhdr 页面装饰。

book-scenarios 会在这本书上检查相关机制。book-tasks 会检查 请求:每个案例都是用户可能说的一句话,会应用到副本上,然后按 Agent 验证的方式进行验证——查看、与上一次构建进行差异比较,并确认改动出现在编辑所影响的位置:

用户提出的要求测量结果
把页眉那条横线去掉0.09%,bbox y=52 h=1(顶部的一条细带)
页眉的线太细,加粗到 2pt0.27%,bbox y=52 h=3
链接的蓝色去掉0.29%,bbox 位于目录页
行距调大一点10.53%,208 → 248 页
表格行距加大9.07%
chap2 那个总结框太窄,放宽7.39%
chap1 那个图太小,放大10.57%
chap4 那组图对齐时右边空着8.81%
段落首行不要缩进14.07%
页边距太窄13.32%,208 → 226 页
正文字号改成 12pt11.63%,208 → 226 页
目录只显示到章2.19%,208 → 207 页

这些案例都不会断言改动看起来如何——这要看图像。断言检查的是:构建成功、存在差异,并且差异的边界框位于编辑所影响的区域。

两个端到端测试套件只对 @deepseek-ai/dsh-tools 进行模拟(它仅存在于 Harness 内部),并使用真实参数调用真实的 execute,因此它们会测试参数处理以及模型实际读取的确切文本,而不只是 lib/core.mjs。这很重要:通过这种方式发现的几个错误只存在于格式处理层。

SyncTeX 指定的页面不一定是它所在的页面

SyncTeX 记录的是框构建时所在的页面。TeX 将浮动体移到下一页时,它会保留上一页的页码,因此 text: "Version 0.5" 过去会为实际位于第 206 页的表格返回“第 205 页”——而第 205 页属于另一个章节。现在,工具会检查 PDF 自带的文本层(gs -sDEVICE=txtwrite,每页约 0.12 秒),并向前后各查找一页和两页;如果结果与 SyncTeX 不同,它会说明这一点。

一张图,而不是两张

一次 compare 调用会写入三张图片,但要展示给用户的是 images.sideBySide:左侧是修改前的页面,右侧是修改后的页面,合成一张 PNG。对于无法阅读源文件的人来说,最难的部分就是对照两个独立文件,凭肉眼找出差异。

写入 PNG 不需要依赖项——文件签名、IHDR、一个 zlib IDAT,再加上 node:zlib 提供的压缩功能即可。在 140 dpi 下,合成一张 A4 页面约需 0.3 秒,而且只有在有内容可供比较时才会运行。

性能

验证编辑始终需要实际编译,这无法绕开。但浏览同一构建的页面不应如此:

操作208 页的书
首次查看(3 次编译 + 词汇表)~17 s
此后每次查看,源文件未变~0.2 s

当文档、它 \input/\include 的所有文件(三层)、它的 \includegraphics 文件以及 aux 文件均未变化(mtime 和大小)时,就会复用构建。失败的构建绝不会被复用。传入 fresh: true 可跳过复用。

有两点值得了解:

  • 修改前的快照属于构建,而不是调用。 编辑后,第一次查看会记录页面修改前的样子;之后查看同一构建时都会复用同一份快照,因此 Agent 检查自己修改的三个页面时,第二和第三个页面仍能看到差异。(以前快照会在第一次调用时被消耗掉,恰好完全反了。)
  • 每个文档同一时间只进行一次构建。 对同一文件进行两次编译会共用其 .aux/.toc 文件并互相破坏——在 208 页的书上同时运行两个进程时,其中一个进程直接退出,连错误消息都没有。现在,进程内通过 promise 队列串行化构建,跨进程则通过包含所有者 PID 的锁文件串行化,因此被终止的运行不会让文档一直卡住。

经测试后,我们决定不在中间编译阶段使用 -draftmode:它只能节省约 2%,因为耗时在排版,而不在写入 PDF。约 16 秒都花在 TeX 本身。

工具

latex_look({
  "file": "book.tex",       // main .tex (required)
  "page": 37,               // optional, defaults to 1
  "text": "表3.1",          // optional: locate this string, show its page
  "pointX": 240,            // optional, with pointY: PDF points → source line
  "pointY": 610,
  "compare": "previous.pdf",// optional: diff against an earlier PDF
  "dpi": 200,               // optional, 50-300
  "engine": "xelatex",      // optional
  "maxPasses": 3,           // optional
  "timeoutSeconds": 300,    // optional
  "fresh": false,           // optional: ignore the build cache
  "audit": false,           // optional: whole-document layout audit vs the last run
  "auditBlankMm": 30        // optional: how deep a bottom hole must be to count,
  "sequence": "图"            // optional: check that numbered labels stay in reading order
})

返回:

  • 编译状态、编译次数、页数,以及结构化的 problems——每项包含 file、line、message
  • warnings:LaTeX/Package/Class 警告,以及 Overfull/Underfull 盒子(页面难看的常见原因)
  • toc:文档是否声明了 \tableofcontents,以及实际生成了多少个条目(空目录会报告为问题,而非成功)。声明会在 \input/\include 的文件中查找,因此用一行根文件包装 \input{main} 的情况也能正常处理
  • aux:运行过的外部工具——makeglossaries、makeindex、biber、bibtex——根据第一次编译生成的产物选择,而非根据根文件的文本选择,因此也能处理把 \makeglossaries 放在所包含的前言中的多文件项目
  • 渲染页面的 PNG 路径——将这些路径交给图像读取器
  • located:文本锚点或所询问点的位置 { file, line, page }
  • diff:changedRatio 以及变化的边界框,单位为 PDF 点,可直接反馈到 pointX/pointY
  • sequence:以行首标签开头的内容的阅读顺序(“图 1-1”、“Figure 3.2”等)。浮动体的放置位置晚于源码中跟在它后面的行内对象,因此,将编号序列中的一个元素设为浮动体会让编号倒退——这是逐页差异永远无法显示的唯一缺陷
  • audit:页面级布局问题——正文底部未达到全书最深位置的页面、起始位置偏低的页面、几乎空白的页面——与上次审计留下的基线进行比较,因此 newFindings 正好表示最新构建破坏的内容。系统会先检测并排除页眉、横线和页码;否则页码就会成为“全书中墨迹最靠下的位置”,导致每一页看起来都有问题

定位原理

latex_look 使用 -synctex=1 编译,因此每个字形都会带有指向其源代码行的链接。然后:

  • 点 → 源代码:synctex edit -o page:x:y:file.pdf
  • 文本 → 源代码:在 .tex 源文件中搜索字符串,然后对每个匹配项运行 synctex view,以获取其页码和坐标
  • 差异边界框 → 源代码:将边界框中心作为 pointX/pointY 传入

坐标以 PDF 点为单位(72 点/英寸),原点位于页面的左上角。

需要注意的限制

  • page 是 PDF 页索引,不是页面上印刷的页码。 在测试书籍中,两者相差 10(印刷页码 130 = 索引 140);罗马数字编号的前置部分偏移量又不同。PDF 页面标签可以让工具进行转换,但 LaTeX 只有在明确要求时才会写入这些标签,因此,Agent 使用用户提供的页码时,必须先对照渲染后的页面进行确认。
  • SyncTeX 会定位到最近的文本位置。页面样式绘制的装饰线条(如 \pagestyle{headings}、fancyhdr)本身没有字形,因此会定位到附近的文本。请结合坐标和 LaTeX 知识进行判断——这正是 SKILL.md 的用途。
  • 系统会通过对 .aux/.toc/.out/… 文件进行哈希来检查多轮编译是否收敛——包含 \tableofcontents 的文档至少需要编译 2 轮;如果目录为空,latex_look 会报告问题。
  • 多文件检测会向下追踪三层 \input/\include。工具无法识别 \import/\subfile、特殊的自定义 .latexmkrc 构建规则,以及 \includeonly。
  • 不可能保证跨引擎的像素一致性:TeX 与 Word,或两个不同的 TeX 引擎,都有不同的断行引擎。此工具验证的是当前引擎的输出,而非其他格式的输出。
  • 文件名中包含 % 会导致 TeX 引擎本身出错(! Emergency stop.),因此任何工具都无法提供帮助。目录名中包含 % 则没有问题。
  • 如果编译失败且没有写入新 PDF,磁盘上的旧 PDF 不会被渲染,也不会报告差异——工具会明确说明这一点。否则,未更改的文件会显示为“更改了 0%”,也就是“你的编辑没有效果”。
  • engine 仅接受此工具列表中的引擎(auto 或已知名称);未经检查的值绝不会传给 spawn。
  • 渲染后的 PNG 会保留在 TMPDIR/latex-look-<pid>/ 中,因为 Agent 会在调用返回后打开这些文件。没有任何机制会清理该目录。
  • 构建缓存会跟踪文档、其 \input/\include 目标、 \includegraphics 文件及其辅助文件。缓存不会跟踪发生更改的 .sty 文件,也不会跟踪通过宏而非字面量 \input{...} 引入的文件——如果怀疑构建缓存过期,请传入 fresh: true。
  • 对包含 \tableofcontents 的文档设置 maxPasses: 1 时,如果之前不存在 .toc 文件,会报告错误;否则会报告警告:.toc 文件是在目录页排版之后写入的,因此只编译一轮必定会生成空白目录页。

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

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

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