关于 oxml-mcp
oxml-mcp 是基于 Rust 的 MCP 服务,为 Agent 提供 XML 查询与处理工具。它通过 XPath 精确提取结果,并且不访问文件系统或网络。
主要功能
- 01XPath 1.0 查询 XML
- 02检查文档结构与格式良好性
- 03按 XSD 验证并报告错误
- 04格式化或压缩 XML
- 05支持 stdio、HTTP 与 SSE 传输
适用场景
- 01从大型 XML 中筛选指定节点
- 02确认 XML 文档结构与有效性
- 03按 XML Schema 查找不符合项
MCP 相关
它通过 MCP 向客户端提供五种 XML 工具:查询、检查、验证、格式化和结构检查。支持 stdio、Streamable HTTP 与 SSE。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm ghcr.io/sebastienrousseau/oxml-mcp:0.0.11本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/sebastienrousseau/oxml-mcp:0.0.11stdio工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
oxml-mcp
一个模型上下文协议服务,让模型能够查询 XML,而不是阅读 XML——由
oxml 提供支持,不含任何
unsafe 代码。
目录
开始使用
- 模型为何需要它 — XML 工具为大模型解决的问题
- 安装 — Cargo、从源码安装
- 传输方式 — stdio、可流式传输的 HTTP、SSE
- 快速开始 — 三行代码,无需客户端
- 配置 — Claude Desktop 和任何 MCP 客户端
oxml 生态系统
- oxml 生态系统 — 七个 crate,一个版本
参考
- 工具 —
xml_query、xml_validate、xml_check、xml_inspect、xml_format - 协议 — MCP
2025-11-25和2026-07-28,以及两种失败类型 - 错误 — 两种错误,以及如何区分
- 设计 — 为何有五种工具,以及为何文档采用字符串
- 0.0.11 中的功能 — 版本功能清单
- 生态系统对比 — 与其他方案的比较
- 基准测试 — 每次请求的延迟,成对测量
实用信息
模型为何需要它
客户端可以直接将 XML 作为工具参数提供,并仅将选定的结果放入模型提示词中。count(//record) 返回解析器计算出的计数,而非根据粘贴的片段估算的结果。
服务接受长度不超过严格 8 MiB 源码限制的 XML 字符串;它不会打开路径或获取 URL。若由模型自行构造完整的工具参数,仍然需要 XML 文本。HTTP 传输方式还有自身更严格的 SDK 请求正文限制。
另一个原因是算术。让模型对它能看到的文档中的元素计数,它会给出近似值。使用 count(//record) 的 xml_query 则不会。
安装
cargo install oxml-mcp --version 0.0.11 --locked
如果没有 Rust 工具链,也可以从 GHCR 获取同一二进制文件的镜像(MCP 注册表中的条目指向该镜像):
docker run --rm -i ghcr.io/sebastienrousseau/oxml-mcp:0.0.11
传输方式
一个二进制文件,三种访问方式。套件中的每个服务都使用 相同的标志。
| 命令 | 传输方式 | 端点 | 协议修订版本 |
|---|---|---|---|
oxml-mcp | stdio | stdin 和 stdout | 2024-11-05 至 2026-07-28 |
oxml-mcp --transport streamable-http --host 127.0.0.1 --port 8000 | Streamable HTTP | http://127.0.0.1:8000/mcp | 2025-11-25 和 2026-07-28 |
oxml-mcp --transport sse --port 8001 | HTTP+SSE(旧版) | http://127.0.0.1:8001/sse、/messages/ | 2024-11-05 |
Streamable HTTP 在同一个端点上提供两个当前修订版本:发送
initialize 的客户端会获得一个会话和一个 Mcp-Session-Id;
在每个请求的 _meta 中指定 2026-07-28 的客户端则以无状态方式提供服务,
并使用 server/discover 代替握手。
响应以服务器发送事件的形式流式传输,GET /mcp 会打开
服务器到客户端的流。SSE 传输方式较旧,适用于仍然需要
endpoint 事件和消息 URL 的宿主。
除非通过 --host 指定其他地址,否则 HTTP 传输方式会绑定到环回接口,
且不进行身份验证。在绑定到可路由地址之前,请将服务置于
可信的网关之后。--version 和 --help 的功能顾名思义。
快速开始
该服务通过 stdio 使用 JSON-RPC 2.0,因此只需三行就能看到它运行—— 先握手,再调用——且无需客户端:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"me","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"xml_query","arguments":{"xml":"<library><book><title>Dune</title></book></library>","xpath":"//title"}}}' \
| oxml-mcp | tail -n 1
{"jsonrpc":"2.0","id":2,"result":{"resultType":"complete","content":[{"type":"text","text":"Dune"}],"structuredContent":{"count":1,"values":["Dune"]},"isError":false}}
日常使用时,你会希望客户端替你完成这些操作——请参阅 配置。
配置
将其添加到 MCP 客户端的服务列表中。对于 Claude Desktop,请在
claude_desktop_config.json 中配置:
{
"mcpServers": {
"oxml": {
"command": "oxml-mcp"
}
}
}
对于 Claude Code:
claude mcp add oxml -- oxml-mcp
不带参数时,该服务通过 stdin 和
stdout 使用 JSON-RPC 2.0,每行一条消息,这正是这些客户端的预期方式。
通过 HTTP 连接的客户端则应指向使用
--transport streamable-http 启动的服务——请参阅传输方式。这里没有
配置文件。
oxml 生态系统
| Crate | 说明 |
|---|---|
oxml | 库:解析器、树、XPath 1.0 |
xmlschema | XSD 验证 |
oxml-cli | 命令行工具 |
oxml-wasm | WebAssembly 绑定 |
oxml-mcp | 此 crate — MCP 服务 |
oxml-lsp | Language Server Protocol 服务 |
oxml-json | 语言服务的 JSON 支持 |
这七个项目使用同一个版本号,按 0.0.1 递增。
工具
xml_query
计算 XPath 1.0 表达式,并返回匹配的值。
| 参数 | 类型 | |
|---|---|---|
xml | string | 文档 |
xpath | string | XPath 1.0 表达式 |
namespaces | object | 可选。表达式的前缀到 URI 的绑定 |
{"name":"xml_query","arguments":{"xml":"<r><t>Dune</t><t>Germinal</t></r>","xpath":"//t"}}
Dune
Germinal
每行一个值。返回数字、字符串或布尔值的表达式会直接返回该值,
因此 count(//t) 会得到 2。每个工具还会按照其声明的
outputSchema,将答案作为 structuredContent 返回——此处为 {"count": 2, "values": ["Dune", "Germinal"]}。
xml_inspect
概述文档的结构:根元素、最大深度、每个元素名称及其计数,以及文档使用的 命名空间。
{"name":"xml_inspect","arguments":{"xml":"<r><t>x</t></r>"}}
Root element: r
Maximum depth: 3
Elements:
r: 1
t: 1
请先调用此工具。 了解元素名称的模型可以编写出有效的查询;靠猜测的模型则会对元素名为
record 的文档编写 //item。
xml_check
报告文档是否格式良好;如果格式不正确,则提供行号和列号。
{"name":"xml_check","arguments":{"xml":"<a/>"}}
The document is well-formed (2 nodes).
xml_validate
根据 XML Schema 验证文档,并返回每个违规项及其所涉及元素的路径。
| 参数 | 类型 | |
|---|---|---|
xml | string | 文档 |
xsd | string | 架构 |
xml_format
使用可配置的缩进(空格)和空元素样式格式化 XML 文档,或将其压缩。
{"name":"xml_format","arguments":{"xml":"<root><item/></root>","indent":2}}
| 参数 | 类型 | 默认值 | |
|---|---|---|---|
xml | string | (必填) | 文档 |
indent | integer | 0 | 每级缩进的空格数(0 表示压缩) |
empty_elements | string | "self-closing" | "self-closing"(<a/>)、"spaced"(<a />)或 "expanded"(<a></a>) |
协议
MCP over JSON-RPC 2.0,由官方 Rust SDK rmcp
实现。目前有两个版本,均受支持:2025-11-25,带有 initialize 握手;以及
2026-07-28,无需握手——每个请求都会在 _meta 中指定其版本,
而 server/discover 会描述此服务。客户端请求时,也接受早至
2024-11-05 的旧版本。
| 方法 | |
|---|---|
initialize | 能力、服务信息、协商后的版本 |
server/discover | 无状态版本对应的相同信息 |
tools/list | 五个工具:输入架构、输出架构、注解 |
tools/call | 调用一个工具 |
ping | 返回应答 |
每个工具都标注为只读、幂等且封闭世界,因此客户端可以直接调用,无需询问。
两种失败会分别处理,因为 MCP 会区分它们,而模型每次只会看到其中一种。
工具已运行,但无法完成任务——例如文档格式错误或表达式无效——会返回携带
isError: true 的成功 JSON-RPC 响应。模型会看到文本并自行修正。
协议拒绝的请求——例如 JSON 格式错误、方法未知,或请求带有 id 但没有
method——会返回带标准错误代码的 JSON-RPC 错误,或通过 HTTP 返回状态码。请求未执行,由客户端处理,而不是由模型处理。
| 情况 | 响应 |
|---|---|
| 文档格式错误 | result,isError: true |
| XPath 表达式无效 | result,isError: true |
| 架构违反 | result,isError: true,并将违反项作为 structuredContent |
| 缺少参数或参数类型错误 | result,isError: true,指出字段名称 |
| 工具未知 | result,isError: true,列出五个现有工具 |
| 方法未知 | error,-32601 |
有 id 但没有 method | error |
| JSON 格式错误 | 通过 HTTP 返回 415;通过 stdio 时跳过该请求,会话继续 |
错误
文档格式错误既不会导致崩溃,也不是协议错误:
{"name":"xml_check","arguments":{"xml":"<a>"}}
{"content":[{"text":"…not well-formed…","type":"text"}],"isError":true}
模型会读取这段文本,并可修正文档或告知用户。
设计
五个工具,而不是十四个。 每次请求中,模型的上下文都会包含所有工具的描述。拥有二十个狭窄工具的服务,在描述自身上耗费的上下文比文档本身还多。
文档以字符串传递,而非路径。 服务绝不会打开文件。模型可以读取什么由客户端决定,这正是应该由客户端做出的决定——如果服务接收路径,就可能读取计算机上的任意文件。
使用一个协议实现,而不是自行实现。 JSON-RPC 和 MCP 层由官方 SDK 提供。三个协议版本和三种传输方式本身就是一个协议项目;要确保手写实现始终符合这些标准并非易事,而 XML 服务的价值并不在此。这个 crate 自己实现的是五个函数,以及模型读取的文本。
0.0.11 中的功能
- 五个工具:查询、检查、校验、验证、格式化
- XPath 1.0:十个轴、25 个函数、全部四种值类型
- XSD 验证
- XML 格式化和压缩(
xml_format) - 通过 stdio 使用 JSON-RPC 2.0,支持 MCP
2024-11-05、2025-11-25和2026-07-28 - 通过可流式 HTTP 和 SSE 传输流式 JSON-RPC 响应
- 支持 JSON 输入中的转义代理对,因此 Python 客户端可以处理包含表情符号的文档
- 无文件系统访问,无网络访问
**尚未支持:**资源、提示词、通过路径或 URI 传入文档。
生态对比
这些方案都是将 XML 提供给模型的方式,而不是相互竞争的服务端:
| 方案 | 文档大小 | 精确度 | 是否会访问网络 |
|---|---|---|---|
oxml-mcp | 受工具调用限制,不受上下文窗口限制 | 通过 XPath 表达式获得精确答案 | 绝不会 |
| 粘贴到上下文中 | 必须能放进上下文,而且每轮都会消耗 token | 模型通过目测匹配模式 | 否 |
| 文件系统或 shell 服务 | 不受限 | grep 能给出什么就是什么 | 取决于服务端 |
| 通用 HTTP 获取服务 | 不受限 | 无 | 会,这是其设计用途 |
最后一行值得停下来想一想。能够获取内容的服务端,可能会被它受命读取的文档引向你的内部网络。这里的工具没有打开套接字的代码;唯一的监听器是你通过 --transport 启动的那个,而且它只会响应请求。
基准测试
cargo bench --bench protocol
每个请求的延迟,因为 MCP 客户端发送一个请求后会等待响应。在 200 KB 负载下,JSON-RPC 层的开销约为纯解析的 10–25%;对于较小的负载,则只有几微秒。请参阅 doc/BENCHMARKS.md,其中也解释了为什么必须成对进行比较。
示例
examples/ 会通过 stdio 调用实际二进制文件并断言响应,因此当 README 中的调用不再有效时,CI 会失败。
| 示例 | 展示内容 |
|---|---|
session.sh | 完整会话:初始化、列出工具、调用每个工具 |
errors.sh | 格式错误的文档、错误的表达式、协议错误 |
何时不应使用 oxml-mcp
- 文档能放进上下文。 直接粘贴;工具往返更慢,也没有额外收益。
- 你需要编辑 XML 结构。
xml_format会序列化并格式化文档;它不会插入、删除或更改其中的数据。 - 你需要 XSLT 或 XPath 2.0。 这两者都不可用。
- 文档大于可用内存。 文档会被完整解析。
- 你希望服务端获取文档。 它绝不会这样做;这正是设计目的。
常见问题
为什么模型每次都必须传入整个文档?
因为服务端不会在调用之间保留状态。这样可以确保多个客户端共享同一个二进制文件时仍能正确运行,也意味着无需使缓存失效,或担心会话间发生信息泄漏。
对于大型文档,这确实很浪费;未来版本可能会加入基于句柄的流程。在此之前,调用一次 xml_inspect,再进行一次精准的 xml_query,胜过多次探索性查询。
它能读取磁盘上的文件吗?
不能,也不会支持。服务端接收的是文档内容。如果服务端接收路径,任何有权访问它的模型都可以读取服务端进程有权读取的任意文件——是否允许读取,应由客户端决定。
将不可信 XML 交给它安全吗?
安全。它绝不会解析外部实体,因此,包含 <!ENTITY xxe SYSTEM "file:///etc/passwd"> 的文档无法让服务端读取该文件。实体展开和嵌套深度都有上限。
为什么只有五个工具?
每个工具的描述都会占用每次请求的上下文。五个覆盖面广的工具比二十个范围狭窄的工具开销更小,而且能覆盖相同的需求,因为 XPath 本身就是查询语言。
它能否与 Claude 以外的客户端配合使用?
它通过 stdio 和两种 HTTP 传输方式实现了 MCP,且不包含针对特定客户端的行为,因此任何兼容的客户端都应能正常使用。它已通过 Python SDK 客户端在两种 HTTP 传输方式下的测试,并在当前两个协议阶段中都获得独立 MCP 审计工具 100/100 的评分。
我的文档包含 emoji,调用失败了。
这是一个已在 0.0.3 中修复的错误。Python 的 json.dumps 默认会转义非 ASCII 字符,因此 emoji 会以代理项对的形式传入——😀——而 JSON 解析器拒绝了转义后的代理项对。任何发送 emoji 的 Python 客户端都会遇到这个问题。
如何使用命名空间查询文档?
在查询中传入:
{"name":"xml_query","arguments":{
"xml":"…","xpath":"//m:item","namespaces":{"m":"urn:example"}}}
前缀会根据这些绑定解析,而不是根据文档解析,因此即使不同文档使用的前缀不同,同一个表达式也能正常工作——只需 URI 匹配即可。未绑定的前缀会导致错误,错误会指出要传入的参数,并提示使用 xml_inspect。
xml_inspect 会报告文档使用的命名空间,这正是该参数可用的原因:模型无法绑定自己看不到的 URI。
Namespaces (pass these to xml_query as `namespaces`):
urn:example: 12 element(s)
未加前缀的名称测试仅匹配不属于任何命名空间的节点,符合 XPath 1.0 规范。namespace-uri() 仍然可用,而且不需要绑定。
如果模型发送了无效 JSON,会发生什么?
SDK 会拒绝格式错误的 HTTP JSON,并返回状态码 415。通过 stdio 传输时,它会跳过格式错误的行,不作回复,并继续处理下一行。参见协议。
为什么未知工具会返回 isError,而不是 JSON-RPC 错误?
在 0.0.8 之前,它返回的是 -32602。在无状态 HTTP 修订版中,SDK 会将该代码作为 HTTP 400 返回,客户端会将其报告为传输故障,而模型永远不会读取到它。对于拼错工具名称的模型,返回说明现有五个工具的文本更有帮助。参见协议。
开发
./scripts/gate.sh
这会按最快失败的顺序运行 CI 中的所有检查:格式检查、clippy、测试、rustdoc、#![forbid(unsafe_code)] 检查、示例、95% 覆盖率底线,以及 MSRV 构建。它会固定工具链,而不是依赖 rust-toolchain.toml,因为环境中的 RUSTUP_TOOLCHAIN 会静默覆盖该文件,而某个 lint 在一个版本中存在、在另一个版本中不存在,就会导致本地运行通过而 CI 失败。
如果你想逐项运行,以下是各个步骤:
cargo test --all-features
cargo clippy --all-targets --all-features -- -D warnings
cargo fmt --all --check
cargo bench --bench protocol
OXML_MCP="$PWD/target/release/oxml-mcp" ./examples/run-all.sh
CI 会在 Linux、macOS 和 Windows 上运行同一组检查。
安全
Scorecard 扫描使用按摘要固定的上游镜像。结果会作为 CI 构建产物和 GitHub 代码扫描中的仓库安全状况发现项保留,不会发布到 Scorecard 的公共服务。徽章显示的是工作流状态,而不是安全评分;即使扫描成功,也仍可能报告发现项。
这些工具不会打开文件或套接字,也不会解引用外部实体。工具 XML 解析使用 Limits::strict(),模式源文件大小上限为 8 MiB。XPath 编译和每次调用的求值都使用明确的资源预算。SDK 和部署必须分别限制传输载荷、并发请求和会话。#![forbid(unsafe_code)]。HTTP 监听器仅在通过命令行请求时才会启用,默认绑定到 loopback 地址,且不进行身份验证——参见传输。
威胁模型假设文档及其周围的 JSON 都是恶意的:文档可能有害,因为模型被要求查看来自互联网的内容;JSON 可能有害,因为它是程序的全部输入。参见 https://github.com/sebastienrousseau/oxml/blob/main/doc/SECURITY-MODEL.md。
文档
- API 文档
- BENCHMARKS.md
- PROTOCOL.md
- 架构决策记录
- TOOL-DESIGN.md
- SECURITY-MODEL.md
- TESTING.md
- CHANGELOG.md
- CONTRIBUTING.md
- SECURITY.md
致谢
oxml-mcp 的诞生离不开此前的工作:
- Anthropic — 感谢其制定了本服务所实现的模型上下文协议规范。
- lxml 和 libxml2 — 为 XML 工具包应具备的功能树立了标杆,并积累了数十年来对正确性的持续打磨。
- W3C — 感谢其制定了
xml_query所遵循的 XPath 1.0 规范。
许可证
可根据你的选择,采用 Apache License, Version 2.0 或 MIT License 进行双重许可。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。