关于 zipnative MCP — ZIP creation, inspection, secure extraction & verification
zipnative-mcp 是用于创建、检查、验证、解压和修改 ZIP 归档的 MCP 服务。它提供默认启用安全防护的解压、可复现归档处理及免解压读取,适合需要离线处理 ZIP 的 MCP 客户端。
主要功能
- 01创建可复现的 ZIP 归档
- 02检查归档并分页列出条目
- 03读取条目和指定字节范围
- 04验证归档结构与 CRC
- 05带路径和大小防护地解压
- 06规范化、合并和修改归档
适用场景
- 01在 CI 门禁中检查归档完整性
- 02读取 ZIP 内文件而不解压
- 03将归档安全解压到沙盒
- 04合并归档且不重新压缩条目
MCP 相关
向 MCP 客户端提供 15 个 ZIP 工具和 7 个提示词。归档输入与输出可使用配置的本地沙盒;服务不访问网络。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y zipnative-mcpZIPNATIVE_MCP_OUTPUT_DIRAbsolute path of the one sandbox directory: zipPath / sourcePath inputs are read from it and outputMode='file' / outputDir outputs are written under it (never overwritten; the real path of every file read and of every parent written must stay inside — a planted symlink or junction is SECURITY_VIOLATION). Unset: every tool works on base64 only (no file I/O beyond the opt-in cache).ZIPNATIVE_MCP_CACHE_DIROpt-in content-addressed response cache directory (absolute path) (SHA-256 keyed, 1h TTL, 256 MiB, oldest-written evicted first, plaintext at rest). Never caches zipPath / sourcePath inputs, file output, defaultDate='now', parallel, describe_engine or draft_governance_issue.ZIPNATIVE_MCP_PORTServe Streamable HTTP on this loopback port (POST /mcp) instead of stdio (MCP 2026-07-28, stateless, legacy fallback). Unauthenticated unless ZIPNATIVE_MCP_HTTP_TOKEN is set.ZIPNATIVE_MCP_HTTP_TOKEN密钥Opt-in bearer token for the HTTP transport (>= 16 chars, no whitespace; a weaker value refuses to start). When set, /mcp requires 'Authorization: Bearer <token>' or answers 401. Compared constant-time, never logged.ZIPNATIVE_MCP_MAX_UNCOMPRESSED_BYTESOperator ceiling for limits.maxEntryUncompressedSize, limits.maxTotalUncompressedSize and limits.maxEntryCompressedSize in bytes (default 8589934592 = 8 GiB, the engine default). Integer >= 1024, read once at startup; an invalid value refuses to start. A per-call value above it is refused with LIMIT_CEILING_EXCEEDED.ZIPNATIVE_MCP_MAX_ENTRIESOperator ceiling for limits.maxEntries and scan_zip_forward maxEntries (default 100000, the engine default; the scanner's default budget of 10000 is clamped to it, only an explicit value above it is refused). Integer >= 1, read once at startup; an invalid value refuses to start.ZIPNATIVE_MCP_WORKERSOperator ceiling for create_zip parallel.workers (default 8; with no explicit workers the engine default max(1, min(cores - 1, 8)) applies, bounded by this ceiling; 0 disables worker threads and keeps compression on the calling thread). Integer >= 0, read once at startup; an invalid value refuses to start.ZIPNATIVE_MCP_MAX_FILE_OUTPUT_BYTESOperator ceiling for every file written in outputMode='file' (create_zip, modify_zip, canonicalize_zip, merge_zip, extract_zip, inflate_raw), enforced while streaming (default 4294967296 = 4 GiB, the 1.0.0 behaviour). Integer >= 1048576, read once at startup; an invalid value refuses to start. Raise it to write Zip64 archives above 4 GiB into the sandbox (create_zip stream entries with zip64: true).本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
13收录的工具列表 · 更新于 1 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| check | array | 否 | 针对报告评估的 CI 断言:deterministic、epoch-timestamps、canonical-order、utf8-names、no-data-descriptor、canonical-layout、no-zip64、zip64、no-encryption、no-symlinks、safe-names、no-duplicates、no-diagnostics、store-only、deflate-only。结果:`checks[]` + `checksPassed`。 |
| assert | object | 否 | 参数化断言(每项都会生成一行 `checks[]`)。 |
| assert.has | array | 否 | 必须存在的条目名称(精确匹配)。 |
| assert.method | enum | 否 | 每个条目都必须使用此方法。store | deflate |
| assert.maxRatio | number | 否 | 允许的单个条目最高未压缩/压缩比。 |
| assert.maxEntries | integer | 否 | 归档最多可包含此数量的条目。 |
| assert.minEntries | integer | 否 | 归档至少必须包含此数量的条目。 |
| assert.maxUncompressedBytes | integer | 否 | 声明的未压缩大小总和不得超过此值。 |
| fields | array | 否 | 在 verbosity 处理后应用的点路径投影(例如 ['entryCount', 'entries.name']);数组段会映射到各元素;未匹配的路径会在 _meta.unmatchedFields 中报告。 |
| limits | object | 否 | 为此次调用覆盖 zipnative 的命名安全边界(CWE-400 / CWE-409 防护)。所有键均为可选;未提供的键保留引擎默认值(maxEntries 100000、maxEntryUncompressedSize 1 GiB、maxTotalUncompressedSize 8 GiB、maxCompressionRatio 1024、maxNameBytes 4096、maxExtraFieldBytes 65535、maxCommentBytes 65535、maxCentralDirectoryBytes 256 MiB)。超过操作员上限(ZIPNATIVE_MCP_MAX_UNCOMPRESSED_BYTES、ZIPNATIVE_MCP_MAX_ENTRIES)的值将被拒绝,并返回 LIMIT_CEILING_EXCEEDED。仅对可信输入提高边界。 |
| limits.maxEntries | integer | 否 | 中央目录条目数上限。 |
| limits.maxNameBytes | integer | 否 | 条目名称的最大字节长度。 |
| limits.maxCommentBytes | integer | 否 | 注释的最大字节长度。 |
| limits.maxExtraFieldBytes | integer | 否 | 额外字段块的最大字节长度。 |
| limits.maxCompressionRatio | number | 否 | 压缩大小 ≥ 1 KiB 的条目所允许的最大声明解压/压缩比(ZIP 炸弹防护)。 |
| limits.maxCentralDirectoryBytes | integer | 否 | 中央目录的最大字节数。 |
| limits.maxEntryUncompressedSize | integer | 否 | 单个条目的最大解压后大小,单位为字节。 |
| limits.maxTotalUncompressedSize | integer | 否 | 一次解压操作中所有条目的最大解压后总大小,单位为字节。 |
| strict | boolean | 否 | 将引擎的首个诊断信息(前置数据、重复名称、名称不匹配等)升级为 ZIP_STRICT_DIAGNOSTIC 错误,而不是报告该信息。 |
| zipPath | string | 否 | ZIPNATIVE_MCP_OUTPUT_DIR 沙箱内归档的相对路径(不得使用绝对路径或 '..';仅限容器扩展名:.zip .jar .docx .epub …)。与 zipBase64 互斥。可在创建/修改 → 验证/提取链中避免重复发送字节。 |
| validate | enum | 否 | 'eager'(默认)会预先交叉检查每个本地文件头和重叠表,并在此处拒绝有害结构;'lazy' 会延迟到首次读取时检查(处理大型归档时开销更低)。eager | lazy |
| verbosity | enum | 否 | 'summary' 仅返回标量判定字段(省略数组和载荷),是节省令牌的形式。full | summary |
| zipBase64 | string | 否 | 归档字节的 base64 编码(恰好一次;允许带 data: URI 前缀)。与 zipPath 互斥。解码后大小 ≤ 128 MiB。 |
详细介绍
zipnative-mcp
ZIP 归档文件的 MCP 服务——无需解压即可确定性地创建、检查和列出内容,随机读取条目(在内存中读取,或按字节范围读取大于内存容量的沙箱归档文件),默认安全地解压,一次调用即可验证,向前扫描截断的流,增量修改,无需重新压缩即可规范化和合并,支持 CRC-32 和原始 DEFLATE 解压——基于 zipnative 引擎(零依赖,在 CI 中验证符合 ISO/IEC 21320-1),提供 15 个工具和 7 个提示词,适用于 Claude Desktop、Cursor、ChatGPT 和任何 MCP 客户端。绝不联网。
✨ 功能
zipnative-mcp 1.1.0(基于 zipnative 1.1.0)向任何 MCP 宿主提供 15 个工具,以下按 tools/list 中的顺序列出。面向使用者的契约——目录、决策树、令牌用量、操作方案和完整错误表——见 docs/AGENT_CONTRACT.md。
| 工具 | 功能 | 只读 |
|---|---|---|
inspect_zip | 一次调用生成归档报告:大小、条目/文件/目录计数、Zip64、注释、压缩与未压缩总大小、各方法计数、加密/符号链接/数据描述符/Zip64/cp437/重复项/不安全名称计数、日期范围、确定性判定(取自引擎的 analyzeDeterminism();默认判定采用 1.0.0 公式:epoch 时间戳 + 规范顺序 + UTF-8 标志)以及所有引擎诊断信息。会立即打开归档:重叠条目、延伸至中央目录或 EOF 之后的条目,以及 Zip64 欺骗都会被拒绝,并返回其 ZIP_* 代码。check: […] + assert: {…} 可将其用作 CI 门禁;determinismReport: true 会添加引擎更严格的规范形式判定及所有违规条目。 | ✓ |
list_zip_entries | 分页列出中央目录清单,不解压任何内容——每个条目均作为完整行展示(大小、CRC-32、方法、时间戳、标志、Unix 模式、符号链接、Zip64、偏移量、额外字段、提取时会使用的净化路径、原始名称字节;可选择包含扩展时间戳和 Unix 所有者 ID)。可按名称/前缀/glob 使用 filter 筛选;使用 offset + limit 指定范围(默认 200,最多 2000)。 | ✓ |
read_zip_entry | 按 name 或 index 读取一个条目,不进行提取:解压后的内容以 base64 或 UTF-8 文本形式返回(已验证 CRC),通过分块流读取字节 range、原始压缩载荷(mode: 'raw'),或不抛出异常的完整性检查(mode: 'verify',附带引擎的 skipped 原因)。 | ✓ |
verify_zip | 一次调用执行深度验证——原样返回引擎的 verifyZip 报告:结构、每个条目的 CRC-32/大小/本地标头一致性,以及每个无法验证的条目及其 skipped 原因('encrypted'、'stream-only-codec'、'unsupported-method')。归档问题绝不会导致 isError:请根据 ok 和 error.code 分支处理。 | ✓ |
extract_zip | 默认安全:拒绝 zip-slip/设备名称、符号链接、重复路径、声明大小和压缩比炸弹、重叠条目及中央目录/本地目录不一致,并返回固定的 ZIP_* 代码;显式指定具名输入才能放宽限制,这些输入只会跳过条目,不会输出条目。可内联返回文件(includeData: false = dry run——会立即打开归档,并在返回任何计划前拒绝重叠、偏移量指向 CD 内部或 Zip64 欺骗的归档),或将文件流式写入沙箱并附带资源链接。 | |
scan_zip_forward | 按流顺序遍历本地标头,内存占用有界——这是唯一适用于已截断的下载文件,或从本地标头开始的截断/不可寻址流的工具,也是唯一结果不具权威性的工具(trust: 'local-headers-only')。tolerateTruncation: true 会连同错误一起返回部分清单。它无法跳过 SFX/前置前缀,并会拒绝此类归档(ZIP_SIGNATURE_MISMATCH):inspect_zip 会报告该前缀(prependedData、ZIP_PREPENDED_DATA),而 modify_zip mode: 'compact' 会将其移除。 | ✓ |
sanitize_entry_paths | 引擎对名称列表执行的唯一遍历安全检查:返回每个名称映射到的安全 / 相对路径形式,或 null 及触发的规则(遍历、绝对路径、驱动器、UNC、NUL、ADS、设备名称)。无需归档。 | ✓ |
create_zip | 从内联文本/base64/沙箱文件创建 ZIP(最多 100 000 个条目——超过 65 535 个条目时自动升级为 Zip64)。默认可复现(规范顺序、以 UTC 写入 DOS epoch 时间戳、UTF-8 名称);设置 compression.deterministic: true 可确保每个运行时生成的字节完全相同——仅此时 summary.deterministic 才为 true;可在归档或条目级别选择 store/deflate;order: 'insertion' 适用于 EPUB/JAR;支持注释、Unix 模式、额外字段;支持流式源(zip64: true 可让流式条目超过 4 GiB);支持工作线程池(生成的字节完全相同);includeSha256 可返回 base64 和文件模式的证明。 | |
modify_zip | 添加/替换/移除/重命名/设置注释,不重新压缩任何内容。mode: 'append' 会原样保留原始字节(已移除的内容仍可恢复——数据残留问题,特此着重说明);mode: 'compact' 会重写归档,使内容真正消失;canonical: {…} 会将重写结果转换为规范确定性形式。两种模式下都会立即打开输入。 | |
canonicalize_zip | 让任何归档都可复现:引擎的 canonicalizeZip() 会将 Gradle、Maven、zip、Explorer 或 7-Zip 归档重写为规范确定性形式(按原始名称字节排序、统一时间戳、UTF-8 标志、仅含 Zip64 额外字段、固定的 version-made-by、不含数据描述符),且不重新压缩载荷。操作具有幂等性;summary.canonicalForm 是引擎对输出执行 analyzeDeterminism() 得出的判定。 | |
merge_zip | 将 1 到 32 个源归档合并为一个,不重新压缩任何内容(ZipWriter.addFromReader):启用 verify: true(默认值)时,每个条目都会先解压一次并检查 CRC 和大小,然后才复制;无法检查的条目(方法不是 store/deflate)会被拒绝(ZIP_UNSUPPORTED_METHOD);可按源使用 filter 筛选;名称冲突可设置 onConflict: 'error'(默认值,ZIP_DUPLICATE_ENTRY_NAME)| 'first' | 'last',并报告被丢弃的条目。拒绝加密条目。 | |
compute_crc32 | 计算文本、base64 或沙箱文件的 ZIP 校验和(IEEE 802.3 CRC-32,使用引擎的 slice-by-8),以 1 MiB 分块流式处理;seed 可串联多个分块的计算结果,expect 用于比较。 | ✓ |
inflate_raw | 使用引擎可恢复的解压器解压原始 DEFLATE(RFC 1951),必须设置 maxOutput 上限:精确返回 bytesConsumed,并将尾随字节作为 leftover 返回。将 read_zip_entry mode: 'raw' 的结果传入此工具。 | |
describe_engine | 离线预检:版本、deflate 等级、运行时编解码器(含 incremental)和工作线程、引擎默认限制、四项操作员上限、所有服务端上限、沙箱/缓存状态、39 个错误代码和 12 个诊断代码,以及刻意不公开的引擎导出项。network 始终为 'none'。 | ✓ |
draft_governance_issue | 在本地起草符合治理要求的 GitHub 问题,供人工审核和提交——绝不会提交,无网络,也无 GitHub 写入路径。 | |
| 每个工具都能保证: |
- 🔐 默认安全——所有引擎防护均已启用;放宽防护必须通过明确命名的输入项(
rejectTraversal、rejectSymlinks、onDuplicate、limits)指定,这些设置只会跳过处理,绝不会输出不安全路径或实体化链接。重叠、中央目录与本地目录不一致以及 Zip64 欺骗均完全不允许关闭防护。 - 🌐 绝不联网——服务没有任何联网代码路径:没有遥测、没有 GitHub、不会使用任何参数中的 URL、没有远程字节范围来源,也没有供操作员配置的端点。唯一的文件系统边界是
ZIPNATIVE_MCP_OUTPUT_DIR。 - 🔁 默认可复现,按需确定性——
create_zip会输出规范顺序、DOS 纪元时间戳和 UTF-8 名称,除非你选择关闭这些设置;所有 DOS 日期均以 UTC 写入和读取(dosTimeMode: 'utc'),因此固定日期在巴黎和 UTC runner 上都会产生相同字节;compression.deterministic: true会固定使用纯 TypeScript 编码器,确保所有运行时生成相同的 SHA-256,且只有此设置下summary.deterministic才为true;canonicalize_zip会将任何外部归档转换为规范格式;parallel生成的字节完全一致。 - 🧭 冻结的
ZIP_*错误码,原样传递——引擎的 39 个错误码会原样通过_meta.error.code传给你(包含条目名称、触发的限制、两个 CRC 等),另有 17 个包装层错误码,每个都附带解决方法。应根据错误码分支处理,切勿根据消息内容判断。 - 🪙 节省令牌的投影——读取工具接受
verbosity: 'summary'和fields: […];生成的归档以嵌入式resource块返回,绝不会放入structuredContent(该块在blob中携带字节,并在data:URI 中重复这些字节,因此,对于任何较大的内容,outputMode: 'file'——即resource_link——都是节省令牌的选择)。 - ⏹ 可取消,并提供进度——请求的取消信号,以及客户端发送
progressToken时的进度接收器,都会传递给除verify_zip之外的所有输入规模会影响工作量的工具(zipnative 的verifyZip是同步的,不接受信号:验证会运行至完成并返回报告)。已取消的调用绝不会被缓存,部分输出文件也会被删除;通过 MCP 时,SDK 不会对已取消的请求发送响应(CANCELLED是进程内错误码)。 - 📏 符合 ISO/IEC 21320-1 的门禁——工具写入的每个归档都会由与引擎无关的验证器(veraZIP)逐条款验证;Linux 和 Windows 上的 CI 会执行验证,发布前也会再次验证。
所有生成归档的工具(create_zip、modify_zip、canonicalize_zip、merge_zip;原始字节工具 inflate_raw)均支持两种输出模式:
-
base64(默认)——归档以嵌入式resource内容块返回:字节位于resource.blob中,resource.uri会在data:application/zip;base64,…URI 中重复这些字节(自 1.0.0 起保持不变,因此解码该 URI 的客户端仍可继续工作)——所以归档在块中会传输两次;structuredContent携带{ mode, sizeBytes, summary, diagnostics, diagnosticCounts },绝不包含字节。 -
file——归档会被流式写入通过ZIPNATIVE_MCP_OUTPUT_DIR配置的沙箱目录(默认上限为 ≤ 4 GiB,ZIPNATIVE_MCP_MAX_FILE_OUTPUT_BYTES可调整上限;绝不覆盖已有文件),结果会携带resource_link(响应开销最低;structuredContent.filePath和文本行会提供文件的主机绝对路径,与 1.0.0 中一样)。除非设置了此变量,否则文件 I/O 会被禁用;绝对路径、路径遍历、非容器扩展名和 NUL 字节均会被拒绝;每个被读取文件的真实路径以及每个被写入父目录的真实路径都必须位于沙箱内(两侧若存在预先放置的符号链接或 junction,都会触发SECURITY_VIOLATION)。同一沙箱也用于zipPath/sourcePath输入,因此create_zip → modify_zip → verify_zip → extract_zip链无需反复发送字节。 节省令牌的读取。 读取工具(inspect_zip、list_zip_entries、read_zip_entry、verify_zip、scan_zip_forward、sanitize_entry_paths和describe_engine)以及extract_zip接受两个可选输入: -
verbosity: 'summary'— 精简的纯标量判定(省略行和负载)。例如,verify_zip→{ ok, error, entryCount, verifiedCount, failedCount, skippedCount, diagnosticCount };inspect_zip会保留deterministic、canonicalLayout、checksPassed。 -
fields: ['a', 'b.c']— 将结构化结果投影为指定的点路径(≤ 16);在verbosity之后应用。未匹配的路径会被省略,并在_meta.unmatchedFields中报告(同时提供_meta.availableFields);包含__proto__、constructor或prototype片段的路径会触发VALIDATION_ERROR。
要检查“此归档是否完好?”,最精简的探测方式:对 verify_zip 使用 { "zipBase64": "…", "verbosity": "summary", "fields": ["ok", "error", "failedCount"] }。
处理大于内存容量的归档。 inspect_zip、list_zip_entries 和 read_zip_entry 接受 access: 'auto' | 'memory' | 'range'。超过 1 GiB 内存上限的沙箱 zipPath 会通过字节范围打开('auto' 为默认值,也可以始终使用 'range'):引擎的 openZipRange 使用沙箱文件自身的句柄读取结束记录和中央目录,然后仅读取你访问的条目——绝不访问 URL,也绝不读取远程源。参见 docs/guides/LARGE_ARCHIVES.md。
该服务还附带 七个 MCP 提示词——secure_extraction、reproducible_archive、incremental_update、forensic_scan、verify_before_trust、governance_contract、draft_issue_workflow——并将沙箱中的每个文件作为 zipnative://output/{+path} 资源公开。
为什么选择 zipnative?
zipnative-mcp 继承底层引擎的所有保证:
- 引擎零运行时依赖——纯 TypeScript,无原生绑定、无
eval;在 Node ≥ 22、浏览器、Deno、Bun 和 Workers 中使用同一套 API(此服务仅额外依赖 MCP SDK 和 zod:总共三个运行时依赖)。 - 默认安全——路径遍历、符号链接、重复名称、解压炸弹、重叠条目、解析器差异欺骗和 Zip64 欺骗都会被拒绝,而非靠猜测处理;每个解析器循环都在具名、标记 CWE、可由调用方配置的限制下运行(九个
ZipLimits键)。 - 随机访问和流式处理——无需触及多 GB 归档的其余部分,即可读取其中一个条目;可在内存中读取,也可通过字节范围源读取;还可在内存有界的情况下迭代不可寻址流。
- 确定性——有明确的确定性契约:布局始终可复现,默认情况下每个环境内的字节稳定,启用
compression.deterministic: true时所有运行时的 SHA-256 相同,并且任何归档都能转换为规范形式,无需重新压缩。 - 增量修改——替换、删除、添加或重命名条目时,无需重新压缩未改动的 99 %(仅追加);如需真正删除则进行压缩整理;还可在归档之间移植条目。
- 冻结的 39 个错误代码词汇表和
verifyZip()——一次调用即可获得机器可读报告,且归档问题绝不会导致其抛出异常。 - 首个开放的、逐条款验证 ISO/IEC 21320-1:2015 的验证器,可在 CI 中阻止不合规内容。
- **它不会做的事:**不加密或解密(引擎 1.x 不包含 AES——AES 是引擎 2.0 的候选功能;ZipCrypto 已被破解),不处理其他归档格式,不处理多磁盘归档,不修复归档,不在引擎中执行文件系统 I/O,绝不访问网络。
🚀 安装
# Run directly with npx (recommended for MCP clients)
npx -y zipnative-mcp
# Or install globally
npm install -g zipnative-mcp
zipnative-mcp
要求:Node.js ≥ 22。从源码安装:git clone https://github.com/Nizoka/zipnative-mcp.git && cd zipnative-mcp && npm ci --ignore-scripts && npm run build && node dist/cli.js。
⚙️ 配置
Claude Desktop
编辑 ~/Library/Application Support/Claude/claude_desktop_config.json(macOS)或 %APPDATA%\Claude\claude_desktop_config.json(Windows):
{
"mcpServers": {
"zipnative": {
"command": "npx",
"args": ["-y", "zipnative-mcp"],
"env": {
"ZIPNATIVE_MCP_OUTPUT_DIR": "/Users/you/Documents/mcp-archives"
}
}
}
}
Claude Code
在项目根目录下的 .mcp.json(仓库附带的配置会从 dist/cli.js 运行构建后的服务):
{
"mcpServers": {
"zipnative": {
"type": "stdio",
"command": "npx",
"args": ["-y", "zipnative-mcp"],
"env": { "ZIPNATIVE_MCP_OUTPUT_DIR": "${CLAUDE_PROJECT_DIR}/.mcp-archives" }
}
}
}
Cursor / Continue / Zed / Windsurf / Cline / Roo Code
任何支持 stdio 服务的 MCP 兼容客户端都可以使用。请使用相同的 command + args + env 三元组。Cursor 的示例(~/.cursor/mcp.json):
{
"mcpServers": {
"zipnative": {
"command": "npx",
"args": ["-y", "zipnative-mcp"],
"env": { "ZIPNATIVE_MCP_OUTPUT_DIR": "/Users/you/Documents/mcp-archives" }
}
}
}
Windsurf / Cline / Roo Code 在各自的 MCP 配置文件中使用相同的结构。
VS Code
.vscode/mcp.json:
{
"servers": {
"zipnative": {
"type": "stdio",
"command": "npx",
"args": ["-y", "zipnative-mcp"],
"env": { "ZIPNATIVE_MCP_OUTPUT_DIR": "${workspaceFolder}/.mcp-archives" }
}
}
}
🌐 支持的 AI 生态与客户端
zipnative-mcp 专为 MCP 原生环境设计,适用于支持通过 stdio 或 Streamable HTTP 使用 MCP 的客户端:Claude Desktop、Claude Code、Cursor、Continue、Zed、Windsurf、Cline、Roo Code、VS Code、ChatGPT(Streamable HTTP)、MCP Inspector,以及任何基于 MCP TypeScript / Python SDK 构建的客户端。由于服务本身不会打开套接字,因此也可以安全地在隔离网络或限制出站流量的主机上运行。
它属于“原生”服务系列,与 pdfnative-mcp(PDF)和 pkinative-mcp(PKI)并列:采用相同的轻量封装架构、沙箱、缓存、投影和治理惯例。同一引擎也以命令行工具的形式提供:zipnative-cli。
🔌 MCP 协议合规性
该服务基于 MCP TypeScript SDK v2(@modelcontextprotocol/server ^2.3.1)构建,支持 MCP 2026-07-28:
- 无状态服务 —
server/discover取代会话握手;每个结果都带有resultType和_metaserverInfo信封。通过 HTTP 时,2026-07-28 客户端会在每个POST /mcp请求中发送Mcp-Method/Mcp-Name标头和MCP-Protocol-Version标头(不带该标头的 2026-07-28 请求会被 SDK 拒绝,返回 400 /-32020)。 - 缓存提示 —
tools/list和prompts/list的缓存级别为public,ttlMs为 24 h;server/discover的缓存级别为public,有效期为 1 h;resources/list/resources/templates/list/resources/read的缓存级别为private,ttlMs: 0(沙箱文件是按主机隔离的用户数据)。 - 协议错误 — 使用未知工具名称调用
tools/call时,会返回 JSON-RPC 错误(-32602,[UNKNOWN_TOOL] Unknown tool: …),而不是isError结果;未知或格式错误的资源 URI 会返回-32602(Invalid params,UNKNOWN_RESOURCE),符合规范要求;isError: true仅用于执行失败。 - 取消与进度 — 对于所有工作量会随输入规模增长的工具,
notifications/cancelled(或 HTTP 客户端断开连接)都会在数据块之间停止工作:归档工具会停止引擎,compute_crc32和inflate_raw会停止工具自身的数据块循环;不会缓存任何内容,并且会删除部分输出文件。verify_zip是个例外:zipnative 的verifyZip是同步的,且不接受 signal(这是引擎的限制),因此验证会运行至完成并返回结果;sanitize_entry_paths、describe_engine和draft_governance_issue不会执行值得取消的工作。按照 MCP 取消规则,SDK 不会对已取消的请求发送响应;工具在进程内返回CANCELLED(data.remedy: 'retry')(callToolDirect),服务器不会为此向 stderr 写入任何内容。带有_meta.progressToken的请求会收到notifications/progress,其progress值在整个调用过程中严格递增,每 200 ms 至多发送一次,此外还会在已知条目数完成时发送一次;没有令牌时,不会发送通知。 - 自动回退到旧版 — 使用
initialize发起连接的客户端,在 SDK 协商的所有修订版本上,都会通过 SDK 的旧版路径提供服务(stdio 和 HTTP 均适用):2024-10-07、2024-11-05、2025-03-26、2025-06-18 和 2025-11-25(旧版),以及 2026-07-28(新版)。现有主机不会受到任何影响。tests/protocol-revisions.test.ts证明每个旧版修订版本都只会协商到对应的修订版本,并提供 15 个工具;tests/stdio-modern.test.ts和tests/http-modern.test.ts证明 2026-07-28 路径在 stdio 和 HTTP 上均可正常工作。 - HTTP — 仅支持
POST /mcp;GET/DELETE /mcp返回 405(不支持 SSE 恢复;服务器是无状态的)。绑定到127.0.0.1,并设置Host/Origin守卫(外部值 → 403;Origin端口必须与服务器端口一致);设置ZIPNATIVE_MCP_HTTP_TOKEN可启用可选的 bearer token 验证(未提供时返回401+WWW-Authenticate);两项检查都会在读取请求正文前运行;接受不超过 256 MiB 的正文(超过则返回 413);标头超时为 30 s,请求超时为 300 s,keep-alive 超时为 5 s,且请求标头最多为 100 个;每个响应都带有X-Content-Type-Options: nosniff和Cache-Control: no-store。 - stdio — 将 SDK 默认的 10 MiB 帧大小上限提高到 256 MiB,以便多 MiB 的 base64 归档能放入单个
tools/call;与每个 SDK 版本一样,在旧版路径上,initialize前发送的请求会被丢弃且不作回复。 - 输出架构 — 每个
structuredContent都会根据工具的outputSchema进行验证(这是 2026-07-28 的 MUST),包括verbosity: 'summary'和fields投影:读取工具声明了可投影的架构(所有属性均为可选,并保留additionalProperties: false)。按照策略,输入架构不包含$schema关键字,也不包含$ref(某些主机会将inputSchema转发给拒绝未知关键字的函数调用 API)。serverInfo带有websiteUrl;资源模板为zipnative://output/{+path}。 2026-07-28 路径与旧版路径的tools/call负载(content、structuredContent、isError)完全相同;tests/http-modern.test.ts对此进行了断言,tests/schema-conformance.test.ts则使用 SDK 的 JSON Schema 2020-12 验证器校验structuredContent。
| 客户端 | 传输方式 | 协商的协议 |
|---|---|---|
| Claude Desktop、Cursor、Continue、Zed、Windsurf、Cline | stdio | 旧版 initialize(2024-xx / 2025-xx)——不变 |
| ChatGPT 和其他 Streamable HTTP 主机 | HTTP POST /mcp | 旧版无状态 Streamable HTTP——不变 |
MCP 2026-07-28 客户端(SDK v2 Client,当前 MCP Inspector) | stdio / HTTP | server/discover、缓存提示、_meta 信封 |
兼容性矩阵——两种传输方式下的每个协商版本,以及验证它的测试:
| 版本 | 时期 | stdio | HTTP POST /mcp | 证明测试 |
|---|---|---|---|---|
| 2024-10-07 | 旧版 initialize | ✓ | ✓ | tests/protocol-revisions.test.ts |
| 2024-11-05 | 旧版 initialize | ✓ | ✓ | tests/protocol-revisions.test.ts |
| 2025-03-26 | 旧版 initialize(HTTP 接受 JSON-RPC 批处理,stdio 拒绝) | ✓ | ✓ | tests/protocol-revisions.test.ts、tests/cli-stdio.test.ts、tests/http-modern.test.ts |
| 2025-06-18 | 旧版 initialize | ✓ | ✓ | tests/protocol-revisions.test.ts、tests/cli-stdio.test.ts、tests/http-modern.test.ts、tests/http-transport.test.ts |
| 2025-11-25 | 旧版 initialize | ✓ | ✓ | tests/protocol-revisions.test.ts、tests/cli-stdio.test.ts、tests/http-modern.test.ts、tests/autonomy.test.ts |
| 2026-07-28 | 新版(server/discover、_meta 信封、缓存提示) | ✓ | ✓(+ bearer token) | tests/stdio-modern.test.ts、tests/http-modern.test.ts、tests/autonomy.test.ts |
自主运行证明。 tests/autonomy.test.ts 在四种传输方式下,对构建好的 dist/cli.js 重放一个脚本化 Agent 场景(S0 握手 → S1 tools/list → S2 describe_engine → S3 create_zip 文件 / base64 / 并行 → S4 verify_zip → S5 inspect_zip 检查 → S6 list_zip_entries → S7 read_zip_entry / inflate_raw / compute_crc32 → S8 modify_zip 追加后压缩 → S9 extract_zip 先试运行再写入文件 → S10 resources/* → S11 scan_zip_forward → S12 拒绝恶意请求 → S13 上限 → S14 协议错误 → S15 draft_governance_issue → S16 prompts/get → S17 正常关闭)——包括旧版 stdio、新版 stdio、旧版 HTTP,以及配置了 ZIPNATIVE_MCP_HTTP_TOKEN 的新版 HTTP。测试在沙箱和缓存目录下运行,并设置 ZIPNATIVE_MCP_MAX_ENTRIES=5000 和 ZIPNATIVE_MCP_WORKERS=2,断言不会进行交互、不会出现意外的 isError、每次拒绝都有代码和解决办法、缓存命中会通过网络传输、stdout 仅输出 JSON,且进程正常退出。tests/cancellation.test.ts 则通过 MCP 测试取消和进度报告。若要通过 Claude Code、Claude Desktop 或 MCP Inspector 手动重放该场景,请参阅 docs/guides/LOCAL_TESTING.md §“Drive it from Claude Code / Claude Desktop / MCP Inspector”(仓库附带可直接使用的 .mcp.json)。
环境变量
八个环境变量都在 server.json 中声明,并在启动时进行验证;无效值会导致启动被拒绝,不会静默回退(例如,ZIPNATIVE_MCP_PORT 超出 1–65535 范围或不是整数、ZIPNATIVE_MCP_OUTPUT_DIR 或 ZIPNATIVE_MCP_CACHE_DIR 是相对路径、上限格式错误、令牌强度不足)。四项运维上限只在启动时读取一次;更改任何变量都需要重启服务。令牌绝不会写入日志;启动日志会在 stderr 中说明当前启用的 HTTP 模式和生效的上限。
| 变量 | 默认值 | 含义 |
|---|---|---|
ZIPNATIVE_MCP_OUTPUT_DIR | (未设置) | 唯一沙箱目录的绝对路径:从该目录读取 zipPath / sourcePath 输入,并将 outputMode: 'file' / outputDir 输出写入该目录下(独占创建,不会覆盖)。每个被读取文件的真实路径以及每个写入目标父目录的真实路径都必须位于该目录内:即使沙箱中植入了符号链接或 junction,在 zipPath / sourcePath / resources/read 上也会触发 SECURITY_VIOLATION,写入操作同样如此。每次读取都通过一个绑定到文件真实路径的打开句柄进行,并依据设备号和 inode 验证,因此如果文件在检查和读取之间被替换或扩展,就会拒绝读取,绝不会提供该文件。未设置 ⇒ 拒绝所有路径输入和文件输出,工具仅处理 base64。 |
ZIPNATIVE_MCP_CACHE_DIR | (未设置) | 可选的持久化 SHA-256 键控结果缓存的绝对路径(相对路径会导致启动失败;TTL 为 1 小时;容量为 256 MiB,优先淘汰最早写入的条目——命中缓存不会刷新条目;静态明文存储;键名包含工具 API、包、引擎版本和四项操作员上限的命名空间,因此降低上限后绝不会返回超出新上限的旧结果)。绝不会缓存 zipPath / sourcePath 输入(包括通过 zipPath 指定的 merge_zip 来源)、文件输出、defaultDate: 'now'、parallel、describe_engine、draft_governance_issue 或已取消的调用;命中缓存时会附带 _meta.cached: true。 |
ZIPNATIVE_MCP_PORT | (未设置 → stdio) | 设置为有效端口(1–65535)时,通过 http://127.0.0.1:<port>/mcp 提供 Streamable HTTP,而不是 stdio;其他任何值都会导致启动失败。仅限环回地址,并启用 DNS 重绑定防护(外部 Host / Origin → 403);GET / DELETE → 405;请求体最大为 256 MiB。除非设置了 ZIPNATIVE_MCP_HTTP_TOKEN,否则不进行身份验证——其他本地进程可以访问该端点。 |
ZIPNATIVE_MCP_HTTP_TOKEN | (未设置) | (机密) HTTP 传输的可选 bearer token(长度至少为 16 个字符,且不得包含空白字符——值过弱会导致启动中止)。设置后,每个 /mcp 请求都必须携带 Authorization: Bearer <token>;否则返回 401 + WWW-Authenticate: Bearer realm="zipnative-mcp"(仅在发送了凭据时才包含 error="invalid_token"——RFC 6750 §3.1)。使用恒定时间比较,绝不记录日志。 |
ZIPNATIVE_MCP_MAX_UNCOMPRESSED_BYTES | 8589934592(8 GiB) | limits.maxEntryUncompressedSize、limits.maxTotalUncompressedSize 和 limits.maxEntryCompressedSize 的操作员上限。整数,且 ≥ 1024。单次调用的值超过此上限时返回 LIMIT_CEILING_EXCEEDED;如果该上限低于引擎默认值,则会静默收紧默认值。 |
ZIPNATIVE_MCP_MAX_ENTRIES | 100000 | limits.maxEntries 和 scan_zip_forward 的 maxEntries 的操作员上限(其默认值 10 000 会被限制为不超过该上限;只有显式指定的值超过上限时才返回 LIMIT_CEILING_EXCEEDED)。整数,且 ≥ 1。 |
ZIPNATIVE_MCP_WORKERS | 8 | create_zip 的 parallel.workers 操作员上限;未显式指定 workers 时,采用引擎默认值 max(1, min(cores − 1, 8)),并限制为不超过此上限;0 会禁用工作线程(压缩仍在调用线程上执行)。整数,且 ≥ 0。 |
ZIPNATIVE_MCP_MAX_FILE_OUTPUT_BYTES | 4294967296(4 GiB) | outputMode: 'file' 中每个写入文件的操作员上限(适用于 create_zip、modify_zip、canonicalize_zip、merge_zip、extract_zip、inflate_raw),并在流式传输过程中强制执行。整数,且 ≥ 1048576。默认值是 1.0.0 版本的上限;若要在沙箱中写入超过 4 GiB 的归档,请提高此值(create_zip 使用 zip64: true 流式处理条目)。 |
操作员上限。 引擎的 9 个具名 ZipLimits 限值只能针对可信输入,通过 limits 片段按调用调高。其中 4 个键受上述两个上限约束:ZIPNATIVE_MCP_MAX_UNCOMPRESSED_BYTES(maxEntryUncompressedSize、maxEntryCompressedSize、maxTotalUncompressedSize)和 ZIPNATIVE_MCP_MAX_ENTRIES(maxEntries,以及 scan_zip_forward 的 maxEntries 输入);ZIPNATIVE_MCP_WORKERS 则限制 create_zip 的 parallel.workers。超过对应上限的单次调用值会被拒绝,并返回 LIMIT_CEILING_EXCEEDED;data.env 会指出操作员需要调高的变量。第 4 个上限 ZIPNATIVE_MCP_MAX_FILE_OUTPUT_BYTES 不限制任何输入,而是限制以文件模式写入的每个文件(OUTPUT_TOO_LARGE)。不存在“无限制”选项,也没有任何工具参数能调高上限。describe_engine 会报告默认值、上限(ceilings.env 列出 4 个变量)以及所有生效中的限制。 |
🛠 工具参考
每个读取归档的工具都必须且只能传入 zipBase64(原始归档仅进行一次 base64 编码;可接受 data:…;base64, 前缀;解码后 ≤ 128 MiB)或 zipPath(沙盒内的相对路径;仅支持容器扩展名:.zip .jar .war .ear .docx .xlsx .pptx .odt .ods .odp .epub .vsix .nupkg .whl .apk .ipa .xpi .crx .kmz;缓冲大小 ≤ 1 GiB,更大的文件需在 3 个随机访问工具中使用 access: 'range')。每个接触引擎的工具都接受 limits(9 个具名 ZipLimits 限值——maxEntries、maxEntryUncompressedSize、maxEntryCompressedSize、maxTotalUncompressedSize、maxCompressionRatio、maxNameBytes、maxExtraFieldBytes、maxCommentBytes、maxCentralDirectoryBytes;值超过操作员上限时 → LIMIT_CEILING_EXCEEDED)和 strict(将第一条诊断升级为 ZIP_STRICT_DIAGNOSTIC)。读取工具接受 verbosity('full' | 'summary')和 fields(≤ 16 个点分隔路径)。除 verify_zip 外,每个归档工具的结果都包含 diagnostics[],按代码和条目去重,最多 200 行(达到上限时 diagnosticsTruncated: true),并包含每种代码的精确计数 diagnosticCounts;verify_zip 保留其 1.0.0 格式。错误结果:content[0].text = "<tool> failed [CODE]: message"、isError: true、_meta.error = { code, message, data? }。在进程内,已取消的调用会以 CANCELLED 结束(通过 MCP 取消的请求不会收到响应);verify_zip 一旦开始验证便无法中断。完整的输入/输出架构由 tools/list 提供;完整的错误表见 docs/AGENT_CONTRACT.md。
日期均为 UTC。 每次引擎调用都使用 dosTimeMode: 'utc'。带有 Z 或时区偏移的日期输入会转换为 UTC;不带时区偏移的日期时间则按 UTC 壁钟时间读取(即 1.0.0 在 UTC 主机上写入的 DOS 字段);读回的 lastModified 和 earliestDate / latestDate 均为 UTC 时刻。因此,固定日期在任何主机上都会生成相同的字节,无论其时区如何(tests/reproducible-build.test.ts 会在两个时区下运行构建后的服务)。在非 UTC 主机上,这对读写两端而言都与 1.0.0 不同:带 Z / 偏移量的日期会写入不同于 1.0.0 的 DOS 字段(包括 compression.deterministic: true 时生成的字节;在 UTC 主机上这些字节与 1.0.0 一致),并且每个归档读回的日期都会按时区偏移量发生偏移(DOS 纪元读作 1980-01-01T00:00:00.000Z,而 1.0.0 在巴黎报告为 1979-12-31T23:00:00.000Z);由其他工具按本地时间写入的归档,读回时会按其生成工具的偏移量发生偏移。
inspect_zip
通过一次调用生成只读归档报告,采用 zipnative inspect --json 的结构:大小、条目数 / 文件数 / 目录数、Zip64、注释(以及 commentHex)、压缩与未压缩总量及比率、各方法的计数、加密 / 符号链接 / 数据描述符 / Zip64 / cp437 / 重复 / 不安全名称的计数、最早 / 最晚日期、prependedData / multipleEocd、determinism 判定(epochTimestamps、canonicalOrder、utf8Flags、noDataDescriptors、canonicalLayout、deterministic),以及全部诊断信息。各子检查来自引擎的 analyzeDeterminism();默认的 deterministic 沿用 1.0.0 的公式(纪元时间戳 + 规范顺序 + UTF-8 标志——流式归档可复现但不规范;固定为非纪元日期时也可复现,但此处会报告 deterministic: false——这是结构判定,与 create_zip.summary.deterministic 不同),因此不会改变现有 CI 门禁。determinismReport: true 会加入引擎更严格的规范格式判定(还会检查仅包含 Zip64 的扩展字段和固定的 version-made-by),并列出每个违规条目及其违反的规则(≤ 200 行,计数准确)。默认会立即打开归档:如果条目重叠、越界延伸至中央目录或 EOF 之后,或存在 Zip64 欺骗,将拒绝处理并返回相应的 ZIP_* 代码,而非生成摘要。中央目录与本地文件头之间的方法 / CRC / 大小不一致不属于范围问题:verify_zip(localHeaderMatch)是检查此问题的一步门禁;读取条目时,read_zip_entry / extract_zip 会抛出 ZIP_CD_LFH_MISMATCH / ZIP_SIZE_MISMATCH。check / assert 可将其设为 CI 门禁。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
zipBase64 / zipPath | string | — | 必须且只能提供其中一项 |
access | 'auto' | 'memory' | 'range' | 'auto' | 'range'(或 'auto' 模式下大于 1 GiB 的 zipPath):按字节范围读取——此时不提供 determinism,确定性检查会因该原因失败,且 determinismReport / canonicalDate 会返回 VALIDATION_ERROR(data.remedy: "access:'memory'") |
validate | 'eager' | 'lazy' | 'eager' | lazy 会将本地文件头交叉检查推迟到首次读取时进行(适用于超大归档,可降低开销) |
check | string[] ≤ 18 | — | deterministic、epoch-timestamps、canonical-order、utf8-names、no-data-descriptor、canonical-layout、no-zip64、zip64、no-encryption、no-symlinks、safe-names、no-duplicates、no-diagnostics、store-only、deflate-only,以及引擎的规范格式检查:canonical-form、canonical-extras、canonical-version-made-by |
determinismReport | boolean | false | 添加 determinismReport(deterministic、七项子判定、pinnedDate、offenderCount、offenders[]) |
canonicalDate | string | — | 归档规范化时使用的日期(canonicalize_zip 的 date、modify_zip 的 canonical.date):规范格式判定会改为期望该时间戳,而非 DOS 纪元时间戳;按 UTC 读取 |
assert | object | — | maxEntries、minEntries、maxUncompressedBytes(≥ 0 的整数)、maxRatio(≥ 1 的数字,按最差的单条目比率计算)、has(≤ 100 个精确名称)、method('store' | 'deflate') |
strict、limits、verbosity、fields | 通用片段 |
输出:上述报告,以及在提供 check / assert 时包含的 checks[]({ check, ok, detail })和 checksPassed;按需提供 determinismReport;如果本次调用由按字节范围读取器处理,则提供 access: 'range';以及 diagnostics[]。摘要:archiveBytes、entryCount、isZip64、compressedBytes、uncompressedBytes、encryptedCount、unsafeNameCount、duplicateNameCount、deterministic、canonicalLayout、diagnosticCount、checksPassed。
{
"zipBase64": "<base64 ZIP>",
"check": ["deterministic", "no-encryption", "safe-names", "no-symlinks"],
"assert": { "maxEntries": 5000, "maxRatio": 100, "has": ["manifest.json"] },
"fields": ["checksPassed", "checks"]
}
(单独使用 fields 会保留 checks[] 中的行;verbosity: 'summary' 则会移除这些行,仅保留 checksPassed。)
错误:VALIDATION_ERROR、INPUT_TOO_LARGE、INPUT_NOT_FOUND、SECURITY_VIOLATION、INVALID_EXTENSION、IO_ERROR、LIMIT_CEILING_EXCEEDED、ZIP_STRICT_DIAGNOSTIC,以及结构性拒绝错误(ZIP_EOCD_NOT_FOUND、ZIP_EOCD_INCONSISTENT、ZIP_CD_INCONSISTENT、ZIP_RECORD_TRUNCATED、ZIP_SIGNATURE_MISMATCH、ZIP_ZIP64_LOCATOR_MISSING、ZIP_ZIP64_EOCD_MISPLACED、ZIP_ZIP64_CONTRADICTION、ZIP_ENTRY_OVERLAP、ZIP_CD_LFH_MISMATCH、ZIP_VALUE_UNREPRESENTABLE、ZIP_UNSUPPORTED_MULTI_DISK、ZIP_LIMIT_EXCEEDED)。
list_zip_entries
只读中央目录清单,不解压任何内容:按目录顺序列出每个条目(包括重复项)的完整行 — index、name、nameEncoding、isDirectory、isSymlink、method / methodName、compressedSize、uncompressedSize、ratio、crc32、lastModified(UTC)、isEncrypted、usesZip64、usesDataDescriptor、unixMode、sanitizedPath(null = 提取门禁会拒绝该条目)、comment、解码后的 flags、versionMadeBy / versionNeeded、hostSystem、属性、localHeaderOffset、DOS 日期 / 时间、命名的 extraFields、rawNameHex、commentHex。支持分页,因此包含 100 000 个条目的归档也不会超出令牌限制。nameEncoding 为 'utf-8' 或 'cp437'(引擎的 'custom' 仅由 nameDecoder 提供,本服务不公开该选项)。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
zipBase64 / zipPath | string | — | 必须恰好提供一个 |
access | 'auto' | 'memory' | 'range' | 'auto' | 与 inspect_zip 相同;通过字节范围读取器提供结果时,结果会带有 access: 'range' |
offset | integer ≥ 0 | 0 | 跳过这么多个匹配条目 |
limit | integer 1–2000 | 200 | hasMore 会提示是否需要继续分页 |
filter | object | — | names(≤ 1000 个精确名称)、prefix、glob(≤ 32 个,每个 ≤ 1024 个字符;* 匹配一个路径段内的内容,** 跨段匹配,? 匹配一个字符,[a-z] 表示字符类;不含 / = 任意深度;以 / 结尾 = 子树;按线性时间匹配 — 对于长度超过 1 024 个字符的字面名称(合法长度上限为 4 096 字节),使用 names 或 prefix 而非 glob)、includeDirectories(未提供筛选条件时会列出目录) |
includeExtraData | boolean | false | 将额外字段负载以 base64 形式返回(用于取证) |
includeExtendedTimestamps | boolean | false | 每行的 extendedTimestamps(mtime / atime / ctime,值为 UTC ISO-8601 或 null,source:'ut' → 'ntfs' → 'dos') |
includeUnixIds | boolean | false | 每行的 unixIds(来自 Info-ZIP 0x7875 扩展字段的 { uid, gid },或 null) |
validate | 'lazy' | 'eager' | 'lazy' | |
strict、limits、verbosity、fields | 通用片段 |
输出:entryCount、matchedCount、offset、limit、returnedCount、hasMore、isZip64、entries[]、access(仅限字节范围读取)、diagnostics[]。摘要:计数以及 names(本页)。
{ "zipBase64": "<base64 ZIP>", "filter": { "prefix": "src/", "glob": ["**/*.json"] }, "limit": 50, "fields": ["entries.name", "entries.uncompressedSize", "hasMore"] }
错误:与 inspect_zip 相同(结构性拒绝会在 validate: 'eager' 时出现,或在中央目录本身损坏时出现);无效 glob(例如 [z-a] 这样的逆序字符类范围)会导致 VALIDATION_ERROR。
read_zip_entry
按 name(精确匹配,区分大小写;重名时取最后一项)或 index(中央目录中的位置,可区分重名项)读取一个条目,不解压整个归档。mode: 'data'(默认)返回解压后的内容,并验证 CRC;结果以 dataBase64 返回,或在 encoding: 'utf8' 时以 text 返回。range 会通过分块流读取一段字节(内存占用有上限;读取字节范围时不验证 CRC)。mode: 'raw' 会原样返回压缩后的载荷(零拷贝,可传给 inflate_raw)。mode: 'verify' 仅返回 verification: { ok, crcMatch, sizeMatch, localHeaderMatch, skipped? },即引擎的判定;即使条目无法解码,也会进行实际的本地文件头比较。skipped ∈ 'encrypted' | 'stream-only-codec' | 'unsupported-method'。在 data 和 raw 模式下不支持加密条目(ZIP_UNSUPPORTED_ENCRYPTION——此引擎不提供解密功能)。通过字节范围读取器(access: 'range',或 zipPath 大于 1 GiB)读取时,只会获取所读条目的字节;limits.maxEntryCompressedSize 限制单次获取的载荷大小。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
zipBase64 / zipPath | 字符串 | — | 必须且只能指定一个 |
name / index | 字符串 / 整数 ≥ 0 | — | 必须且只能指定一个 |
access | 'auto' | 'memory' | 'range' | 'auto' | 与 inspect_zip 相同 |
mode | 'data' | 'raw' | 'verify' | 'data' | |
encoding | 'base64' | 'utf8' | 'base64' | 仅适用于 data 模式;无效 UTF-8 → ENTRY_NOT_UTF8 |
verifyCrc | 布尔值 | true | data 模式且未指定 range 时适用 |
range | { offset ≥ 0, length 1–16777216 } | — | 仅适用于 data 模式 |
includeExtendedTimestamps / includeUnixIds | 布尔值 | false | 与 list_zip_entries 相同,作用于 entry 行 |
strict、limits、verbosity、fields | 共享片段 |
输出:entry(完整行)、mode、sizeBytes、crcVerified、encoding、dataBase64 / text + textLength、range: { offset, length, returned }、verification、access(仅限字节范围读取)、diagnostics[]。每个条目的内联大小上限为 16 MiB(ENTRY_TOO_LARGE,data.remedy: 'range'):在 mode: 'data' 下读取 range 范围,或使用 extract_zip 文件模式;超过上限的 raw 载荷无法以内联方式获取——采用相同补救方式可取得解压后的内容。超出范围的 index 会触发 ZIP_ENTRY_NOT_FOUND,并指出有效范围(data.remedy: 'list_zip_entries')。
{ "zipBase64": "<base64 ZIP>", "name": "META-INF/MANIFEST.MF", "encoding": "utf8" }
错误:ZIP_ENTRY_NOT_FOUND、ENTRY_TOO_LARGE、ENTRY_NOT_UTF8、ZIP_UNSUPPORTED_ENCRYPTION、ZIP_UNSUPPORTED_METHOD、ZIP_CRC_MISMATCH、ZIP_SIZE_MISMATCH、ZIP_DEFLATE_CORRUPT、ZIP_DEFLATE_TRUNCATED、ZIP_INFLATE_OUTPUT_OVERFLOW、ZIP_CD_LFH_MISMATCH、ZIP_ENTRY_OVERLAP、ZIP_RECORD_TRUNCATED(字节范围数据源提供的字节数少于请求数),以及上述结构性拒绝错误和封装器错误代码。
verify_zip
一次调用即可进行深度验证——原样返回 zipnative 的 verifyZip 报告:先进行积极的结构验证,然后检查每个条目的 CRC-32、大小和本地文件头是否一致。结构有效且每个可验证条目均通过时,ok 为 true。此工具绝不会因归档本身的问题而失败:结构拒绝会写入 error: { code: 'ZIP_*', message };无法验证的条目会附带 skipped 原因。计数遵循引擎的归档规则:本地文件头与中央目录一致的加密条目或仅支持流式处理的编解码器条目会被跳过,不会导致归档验证失败;所用方法没有对应编解码器的条目(skipped: 'unsupported-method'——除 0(存储)和 8(deflate)外的任何方法),以及本地文件头与中央目录不一致的加密条目均视为失败(ok: false)。只有调用方错误(限制无效、输入无效)才会返回 isError。请先验证再信任:对任何来自不可信来源的归档,都应在运行 extract_zip 前使用此工具。
| 输入 | 类型 | 默认值 | 备注 |
|---|---|---|---|
zipBase64 / zipPath | string | — | 必须且只能提供其中一项 |
entries | 'all' | 'failed' | 'skipped' | 'none' | 'all' | 要返回哪些逐条目记录 |
maxEntries | 整数 1–100000 | 1000 | 返回记录的上限(entriesTruncated);计数始终涵盖所有条目 |
limits、verbosity、fields | 共享片段 |
输出:ok、error(或 null)、entryCount、verifiedCount、failedCount、skippedCount、entries[]({ name, ok, crcMatch, sizeMatch, localHeaderMatch, skipped? })、entriesTruncated、diagnostics[](按代码和条目去重,最多 200 条;只有达到上限时才会有 diagnosticsTruncated: true;不提供 diagnosticCounts,以保持 1.0.0 的数据结构)。若条目使用此服务没有对应编解码器的方法存储(除 0(存储)和 8(deflate)外的任何方法——Zstandard、LZMA 等),则会返回 skipped: 'unsupported-method' 和 ok: false,并计入 failedCount:应将其表述为“未检查”,而非“已损坏”(merge_zip 在 verify: true 时会拒绝此类条目)。验证一旦开始便无法中断:zipnative 的 verifyZip 是同步函数且不接受信号,因此验证期间到达的取消请求会被忽略,调用会运行至完成。
{ "zipBase64": "<base64 ZIP>", "entries": "failed", "verbosity": "summary" }
错误(仅限调用方错误):VALIDATION_ERROR、INPUT_TOO_LARGE、INPUT_NOT_FOUND、SECURITY_VIOLATION、INVALID_EXTENSION、IO_ERROR、LIMIT_CEILING_EXCEEDED、ZIP_LIMIT_INVALID。
extract_zip
除非明确指定放宽措施,否则所有引擎防护均保持开启:zip-slip / 绝对路径 / 驱动器路径 / UNC / NUL / ADS / Windows 设备名称 → ZIP_PATH_TRAVERSAL(rejectTraversal: false 会跳过这些路径,并列入 skipped;绝不会输出不安全路径);符号链接 → ZIP_SYMLINK_REJECTED(rejectSymlinks: false 会将目标文本作为数据提取,绝不会创建链接);清理后路径重复 → ZIP_EXTRACT_DUPLICATE_PATH(由 onDuplicate 控制);声明的大小 / 压缩比超出 limits → ZIP_LIMIT_EXCEEDED;始终拒绝重叠条目和中央目录 / 本地目录信息不一致。两种模式下,都会在执行任何计划前立即打开归档,因此试运行会执行与提取相同的打开时防护:重叠条目、延伸到中央目录内或超出文件末尾的条目,以及伪造的 Zip64 信息,都会在返回任何计划行之前以相应的 ZIP_* 代码被拒绝(文件模式下,提取也会在首次写入前失败,data.writtenCount: 0);方法、CRC 或大小的中央目录 / 本地目录信息不一致,会在读取条目时检测到;verify_zip(localHeaderMatch)是一次调用即可完成此项检查的关卡。在 base64 模式下,随后会计算计划(筛选、清理、符号链接策略、重复项、预算),但不会接触任何有效载荷;includeData: false 会将该计划作为试运行结果返回。在文件模式下,每个文件都会在沙箱内的 outputDir 中以流式方式写入:只会拼接引擎清理后的路径,会检查父目录的真实路径,以独占方式打开文件;通过 rejectSymlinks: false 接受的符号链接会作为普通文件写入,其中保存链接目标。归档本身会读入内存(zipPath 最大为 1 GiB)。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
zipBase64 / zipPath | string | — | 必须且只能指定一个 |
outputMode | 'base64' | 'file' | 'base64' | 内嵌模式下每个文件 ≤ 16 MiB,总计 ≤ 32 MiB;文件模式受 ZIPNATIVE_MCP_MAX_FILE_OUTPUT_BYTES 限制 |
outputDir | string | — | 文件模式:沙箱内的相对目录(会创建;绝不覆盖现有内容) |
includeData | boolean | true | base64 模式:false = 试运行(返回路径和大小,不解压任何内容;先拒绝恶意范围) |
filter | object | — | 与 list_zip_entries 相同(除非设置 includeDirectories,否则排除目录) |
rejectTraversal | boolean | true | false 会跳过不安全名称并将其列入 skipped |
rejectSymlinks | boolean | true | false 会将目标文本作为数据写入 |
onDuplicate | 'error' | 'first' | 'last' | 'error' | 两个条目映射到同一清理后路径时的处理方式 |
emptyDirectories | boolean | false | 文件模式:创建不包含文件的显式目录条目 |
strict、limits、verbosity、fields | 通用片段 |
输出:mode、dryRun、fileCount、totalBytes、entries[]({ path, entryName, index, sizeBytes, crc32, method, dataBase64? | filePath? })、skipped[]({ entryName, reason: 'unsafe-path' })、outputDir、directoriesCreated、diagnostics[];文件模式还会添加最多 50 个 resource_link 内容块。摘要:mode、dryRun、fileCount、totalBytes、skippedCount、paths。
{ "zipBase64": "<base64 ZIP>", "outputMode": "file", "outputDir": "unpacked/report", "filter": { "glob": ["docs/", "*.json"] } }
错误:ZIP_PATH_TRAVERSAL、ZIP_SYMLINK_REJECTED、ZIP_EXTRACT_DUPLICATE_PATH、ZIP_LIMIT_EXCEEDED、ZIP_ENTRY_OVERLAP、ZIP_CD_LFH_MISMATCH、ZIP_UNSUPPORTED_ENCRYPTION、ZIP_UNSUPPORTED_METHOD、ZIP_CRC_MISMATCH、ZIP_SIZE_MISMATCH、ZIP_DEFLATE_CORRUPT、ZIP_DEFLATE_TRUNCATED、ENTRY_TOO_LARGE、OUTPUT_TOO_LARGE、OUTPUT_EXISTS、IO_ERROR、MISSING_OUTPUT_PATH、SECURITY_VIOLATION、CANCELLED,以及结构性拒绝和包装器代码。
scan_zip_forward
按流顺序遍历本地头,并使用有界内存(zipnative 的无中央目录读取器 iterateZipEntries)。这是唯一能处理截断归档或中途截断的流的工具——流必须从本地头开始:它无法跳过 SFX / 前置前缀,遇到此类前缀时会以 ZIP_SIGNATURE_MISMATCH 拒绝处理(带前缀的归档应使用 inspect_zip,它会报告 prependedData / ZIP_PREPENDED_DATA 并调整偏移量;modify_zip mode: 'compact' 会移除前缀)——它也是唯一一个结果不具权威性的工具:正向迭代仅信任本地头,因此恶意归档在此处呈现的内容可能与 inspect_zip / list_zip_entries 报告的内容不同(上传扫描器差异)。只要整个归档可用,就优先使用这些工具;此工具用于取证。名称不会经过清理——sanitizedPath 显示提取检查会使用的路径。zipPath 会通过一个打开的句柄从磁盘流式读取,不受 1 GiB 缓冲上限限制。封装器绝不会读取 PK 签名:stoppedAt 根据字节计数得出(引擎遇到中央目录时会让流中的其余部分保持未读取状态)。在所有运行时层级中,损坏的 deflate 数据都会报告为 ZIP_DEFLATE_CORRUPT / ZIP_DEFLATE_TRUNCATED(1.0.0 在此处报告为 ZIP_DECOMPRESSION_FAILED)。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
zipBase64 / zipPath | string | — | 必须且只能指定其中一个 |
data | 'none' | 'verify' | 'include' | 'none' | none 跳过负载(数据描述符条目仍需解压并丢弃,因而会产生开销);verify 检查 CRC;include 返回内容(受内联上限约束) |
filter | object | — | 与 list_zip_entries 相同(未提供筛选条件时包含目录) |
maxEntries | integer ≥ 1 | 10000 | 默认值会限制在 ZIPNATIVE_MCP_MAX_ENTRIES 上限以内;显式指定超过上限的值会报错 LIMIT_CEILING_EXCEEDED(data.remedy: 'maxEntries ≤ N') |
tolerateTruncation | boolean | false | true:遇到截断 / 损坏的流时,以 stoppedAt: 'error' + error 结束扫描,而不是报错退出 |
strict、limits、verbosity、fields | 共享片段 |
输出:trust: 'local-headers-only'、entryCount、keptCount、entries[](包含 kept 和 data: { verified, bytesProduced, dataBase64? } 的行;isSymlink / usesZip64 / unixMode 为 null)、stoppedAt('central-directory' — 读取器遇到中央目录,并让其余内容保持未读取状态 | 'eof' — 未遇到中央目录便读完整个流:流已截断或不含中央目录 | 'max-entries' — 预算耗尽后仍有更多本地头(条目数恰好等于 maxEntries 的归档会以 'central-directory' 结束) | 'error')、truncated、inputBytes、bytesDelivered、maxEntries(限制后生效的预算值)、error、diagnostics[]。
{ "zipBase64": "<base64 of a truncated download>", "tolerateTruncation": true, "verbosity": "summary" }
错误:ZIP_STREAM_TRUNCATED、ZIP_SIGNATURE_MISMATCH、ZIP_RECORD_TRUNCATED、ZIP_DESCRIPTOR_MISMATCH、ZIP_UNSUPPORTED_CD_LESS_DESCRIPTOR、ZIP_UNSUPPORTED_ENCRYPTION、ZIP_UNSUPPORTED_METHOD、ZIP_CRC_MISMATCH、ZIP_SIZE_MISMATCH、ZIP_DEFLATE_CORRUPT、ZIP_DEFLATE_TRUNCATED、ZIP_INFLATE_OUTPUT_OVERFLOW、ZIP_LIMIT_EXCEEDED、ENTRY_TOO_LARGE、OUTPUT_TOO_LARGE、LIMIT_CEILING_EXCEEDED(启用 tolerateTruncation: true 时,所有引擎错误代码都会写入 error)。
sanitize_entry_paths
对名称列表应用 zipnative 的单一遍历门控 sanitizeEntryPath():返回每个名称对应的安全 / 分隔相对路径(将其拼接到你的解压根目录下——绝不要使用原始名称),或返回 null 并注明触发的规则。使用其他工具解压或计划写入外部文件系统时,可使用此工具。无需提供归档文件。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
names | string[] 1–10000 | — | 每个名称最多 4096 个字符,按其在归档中的存储形式处理 |
verbosity, fields | 投影 |
输出:count、rejectedCount、results[]({ name, sanitized, rejected, reason? },其中 reason ∈ empty、nul、absolute、drive、unc、traversal、ads、device-name、no-segments)。摘要:count、rejectedCount、rejectedNames。
{ "names": ["docs/readme.md", "../../etc/passwd", "C:\\Windows\\win.ini", "aux.txt", "a/./b//c.txt"] }
错误:VALIDATION_ERROR。
create_zip
从内联条目(dataBase64 | text | 沙盒中的 sourcePath,或 directory: true)写入 ZIP。默认可复现:规范顺序(原始 UTF-8 名称字节)、DOS 纪元时间戳(所有日期均以 UTC 写入)、UTF-8 名称、固定属性——defaultDate: 'now' 可退出该默认行为(诊断信息为 ZIP_TIMESTAMP_NOT_PINNED)。compression.deterministic: true 会固定纯 TS 编码器,使每个运行时生成的字节完全相同(summary.deflateTier: 'pure-pinned');默认的 node-zlib 层仅保证在同一环境中字节稳定。三种确定性判定,请在适用处查看:只有当每个条目均设置 compression.deterministic: true 且未使用当前时间日期时,summary.deterministic 才为 true(跨运行时一致——默认调用虽然在同一运行时中生成可复现的字节,但仍会报告 false);summary.sha256(includeSha256,适用于 base64 和文件模式)可作为证明;inspect_zip.determinism.deterministic 是根据规范默认值(纪元时间戳 + 规范顺序 + UTF-8 标志)得出的结构判定(固定非纪元日期虽可复现,但在此处会报告 false)。order: 'insertion' 会保留调用顺序,适用于 EPUB / JAR(mimetype 在首位,且采用存储方式)。对 sourcePath 设置 stream: true 时,会使用一个打开的句柄通过 addStream 读取文件(数据描述符布局,内存占用有界);如果流式条目超过 4 GiB,则会报错 ZIP_UNSUPPORTED_ZIP64_STREAMING,除非设置 zip64: true 以启用 Zip64 流式布局(APPNOTE 4.3.9.2)。parallel 会通过工作线程池进行压缩——输出字节完全相同;若未设置 workers,则使用引擎默认值 max(1, min(cores − 1, 8)),并受 ZIPNATIVE_MCP_WORKERS 限制。仅在字段溢出时才会生成 Zip64——此处每次调用最多可处理 100 000 个条目(引擎默认的 maxEntries 和 ZIPNATIVE_MCP_MAX_ENTRIES 上限仍是实际限制),因此 65 536 个条目的归档会自动升级。以 / 结尾的名称表示目录,不能携带负载(会报错 VALIDATION_ERROR——删除斜杠或传入 directory: true)。所有生成的归档均符合 ISO/IEC 21320-1(已通过 CI 验证)。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
entries | array 0–100000 | — | 必填;每项包含:name(1–4096,以 / 分隔;末尾的 / 表示目录,且不接受载荷)、dataBase64 / text / sourcePath 中的一个,或 directory: true;每项可设置 compression、date(ISO-8601,pattern ^\d{4}-\d{2}-\d{2},1980–2107,按 UTC 读取)、comment(≤ 65535)、unixMode(pattern ^(?:0o)?[0-7]{3,4}$ — 3–4 位八进制数字,例如 '0644'、'755'、'0o755',前后不能有空白)或 externalAttributes(uint32,二者互斥)、extraFields(≤ 16 个 { id 0–65535 except 1, dataBase64 })、stream(与 sourcePath 配合使用)、zip64(仅可与 stream: true 配合使用,否则返回 VALIDATION_ERROR) |
order | 'canonical' | 'insertion' | 'canonical' | |
defaultDate | string | DOS epoch | ISO-8601 或 'now'(pattern ^(?:now|\d{4}-\d{2}-\d{2})) |
compression | object | deflate 6 | method('store' | 'deflate')、level 0–9、deterministic(将流式条目的大小限制为 2 GiB) |
comment | string ≤ 65535 | — | 存档注释 |
chunkSize | integer 1024–16777216 | 64 KiB | 文件模式下的流式传输块大小;不会改变字节内容 |
parallel | object | — | workers 0–64(≤ ZIPNATIVE_MCP_WORKERS;省略时使用引擎默认值 max(1, min(cores − 1, 8)),且不超过上限)、minWorkerJobSize ≥ 1、jobTimeout 1000–600000 ms |
includeSha256 | boolean | false | 在 base64 和文件模式下提供 summary.sha256(流式传输时计算哈希 — 用于确定性证明) |
outputMode / outputPath | 'base64' | 文件模式:以容器扩展名结尾的相对路径 | |
strict、limits | 通用片段 |
低于 4 GiB 的 zip64: true 条目仍会包含 Zip64 记录,某些流式读取器(如 Java 的 ZipInputStream)无法读取这些记录 — 仅对可能超过 4 GiB 的条目启用此选项;并提高 ZIPNATIVE_MCP_MAX_FILE_OUTPUT_BYTES,以便将结果写入沙箱。
输出:存档作为嵌入式 resource(≤ 50 MiB)或 resource_link;structuredContent:mode、sizeBytes、filePath、summary(在工具的 outputSchema 中定义类型:entryCount、fileCount、directoryCount、streamedCount、uncompressedBytes、order、deterministic、deflateTier、parallel: { requested, workers }、sha256)、diagnostics[]。
{
"entries": [
{ "name": "mimetype", "text": "application/epub+zip", "compression": { "method": "store" } },
{ "name": "META-INF/container.xml", "text": "<container/>" },
{ "name": "OEBPS/", "directory": true }
],
"order": "insertion",
"compression": { "deterministic": true },
"includeSha256": true,
"outputMode": "file",
"outputPath": "books/sample.epub"
}
错误:VALIDATION_ERROR、INPUT_TOO_LARGE、INPUT_NOT_FOUND、OUTPUT_TOO_LARGE、OUTPUT_EXISTS、IO_ERROR、MISSING_OUTPUT_PATH、INVALID_PATH、INVALID_EXTENSION、SECURITY_VIOLATION、LIMIT_CEILING_EXCEEDED、CANCELLED、ZIP_INVALID_ENTRY_NAME、ZIP_INVALID_OPTION、ZIP_LIMIT_EXCEEDED、ZIP_UNSUPPORTED_ZIP64_STREAMING、ZIP_INPUT_TOO_LARGE、ZIP_STRICT_DIAGNOSTIC、ZIP_API_MISUSE。
modify_zip
编辑现有归档,不重新压缩任何内容:按顺序应用 operations 中的 add / replace / remove / rename / setComment 操作。在两种模式下,输入都会被立即打开——任何操作运行前,都会检查重叠情况和每个条目的范围,因此即使在 mode: 'append' 下,存在重叠或头部截断的归档也会被拒绝;以追加模式保存前,还会检查每个未加密条目的本地头部和声明的大小(仅进行原始读取,不解压缩),因此方法 / CRC / 大小不一致(ZIP_CD_LFH_MISMATCH)或声明大小炸弹(ZIP_LIMIT_EXCEEDED)会被拒绝,mode: 'compact' 和其他写入器也会拒绝此类归档。除此之外,负载会原样复制,绝不解码:归档中损坏的负载或不安全的名称(../../evil.txt)会原样保留在输出中——extract_zip 仍会拒绝此类名称。mode: 'append'(默认值)= save():原始字节保持原样,编辑内容追加在后——速度快且保留字节,但已移除或替换的负载仍会留在文件中(数据残留:任何人都可以恢复;死字节超过 50 % 时会触发 ZIP_DEAD_BYTES_RATIO 诊断,而且已知 7-Zip 会读取过期负载)。mode: 'compact' = saveCompact():不重新压缩的情况下重写归档,并按原始名称字节排序条目(不会保留按插入顺序排列的布局,例如 EPUB 的 mimetype 在首位、JAR 清单在首位:使用 create_zip 的 order: 'insertion' 重建此类容器);已移除的数据会彻底删除,SFX 前缀会被丢弃;添加 canonical: {…},可在编辑后写入规范的确定性格式(遵循 canonicalize_zip 的规则)。如果没有编辑且注释未更改,则返回相同字节(summary.noOp)。含有重复条目名称的归档会被拒绝。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
zipBase64 / zipPath | 字符串 | — | 必须且只能提供一个 |
operations | 数组,1–1000 项 | — | { op: 'add' | 'replace', name, dataBase64 | text | sourcePath, compression?, date?, comment?, unixMode? | externalAttributes?, extraFields?, directory? (仅限 add) }、{ op: 'remove', name }、{ op: 'rename', from, to }、{ op: 'setComment', comment }——负载规则和 pattern 与 create_zip 相同(带负载且名称以 / 结尾时会触发 VALIDATION_ERROR) |
mode | 'append' | 'compact' | 'append' | |
canonical | 对象 | — | 仅限 mode: 'compact'(否则触发 VALIDATION_ERROR):{ date?, keepComments? (false), keepExternalAttributes? (true) };{} 使用默认值 |
compression | 对象 | 引擎默认值 | 用于新负载(格式与 create_zip 相同:method、level、deterministic) |
defaultDate | 字符串 | DOS 纪元 | 用于新负载;ISO-8601 或 'now'(pattern 为 ^(?:now|\d{4}-\d{2}-\d{2});'now' → ZIP_TIMESTAMP_NOT_PINNED) |
includeSha256 | 布尔值 | false | |
outputMode / outputPath | 'base64' | ||
strict、limits | 共享片段 |
输出:作为嵌入式 resource 或 resource_link 的归档;summary(saveMode、operationsApplied、entryCountBefore、entryCountAfter、inputBytes、outputBytes、grewByBytes、noOp、canonical(写入规范格式时出现)、sha256);diagnostics[]。
{ "zipBase64": "<base64 ZIP>", "operations": [{ "op": "remove", "name": ".env" }, { "op": "rename", "from": "config.json", "to": "config/app.json" }], "mode": "compact", "canonical": {} }
错误:ZIP_ENTRY_NOT_FOUND、ZIP_ENTRY_EXISTS、ZIP_DUPLICATE_ENTRY_NAME、ZIP_INVALID_ENTRY_NAME、ZIP_ENTRY_OVERLAP、ZIP_CD_LFH_MISMATCH、ZIP_RECORD_TRUNCATED、ZIP_LIMIT_EXCEEDED、ZIP_STRICT_DIAGNOSTIC,以及结构检查拒绝、输出错误代码和封装器错误代码(data.operationIndex / data.op 指明失败的操作)。
canonicalize_zip
将任意归档转换为可复现格式。zipnative 的 canonicalizeZip() 会将你未创建的归档——Gradle、Maven、zip、Windows Explorer、7-Zip、bsdtar 创建的归档——重写为引擎自身写入器生成的规范确定性格式:条目按原始名称字节排序,所有条目使用同一时间戳(DOS 纪元时间,或固定的 date),每个名称都带有 UTF-8 标志,除 Zip64 外不含任何扩展字段,使用固定的 made-by 版本(0x032D),且不使用数据描述符。不会重新压缩或解码任何负载:压缩字节会逐位复制,因此损坏或加密的条目也会原样保留;名称也会原样复制,所以诸如 ../../evil.txt 这样的不安全名称仍会出现在输出中(canonicalForm 仍可能为 true;extract_zip 会拒绝该名称,而 merge_zip 会通过经过检查的写入器写入名称,因此也会以 ZIP_INVALID_ENTRY_NAME 拒绝它)。由于不会运行编解码器,结果在不同运行时之间保持字节稳定。此操作具有幂等性——再次规范化输出会得到相同字节(summary.alreadyCanonical)。引擎还会使用相同的固定日期再次通过 analyzeDeterminism() 检查输出,检查结果为 summary.canonicalForm;之后可通过 inspect_zip { check: ['canonical-form'], canonicalDate } 验证。含有重复条目名称的归档会被拒绝,与 modify_zip 的处理方式相同。如需在一次调用中更改内容并进行规范化,请使用 modify_zip mode: 'compact' 并设置 canonical。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
zipBase64 / zipPath | 字符串 | — | 必须且只能提供一个 |
date | 字符串 | DOS 纪元时间 | 写入每个条目的唯一时间戳(ISO-8601,1980-01-01 … 2107-12-31,按 UTC 读取;DOS 时间精度为 2 秒) |
keepComments | 布尔值 | false | 保留归档注释和条目注释(规范格式不含注释) |
keepExternalAttributes | 布尔值 | true | 保留 Unix 模式 / DOS 属性;false 则写入规范默认值(文件为 0o100644,目录为 0o40755) |
includeSha256 | 布尔值 | false | 生成字节的 summary.sha256 |
outputMode / outputPath | 'base64' | 文件模式:以容器扩展名结尾的相对路径 | |
strict、limits | 共享片段 |
输出:作为嵌入式 resource(≤ 50 MiB)或 resource_link 返回的归档;summary(entryCount、inputBytes、outputBytes、alreadyCanonical、canonicalForm、pinnedDate(UTC ISO-8601;DOS 纪元时间时为 null)、keepComments、keepExternalAttributes、sha256);以及 diagnostics[]。
{ "zipBase64": "<base64 ZIP>", "date": "2026-10-08T00:00:00Z", "keepExternalAttributes": false, "includeSha256": true }
错误:VALIDATION_ERROR(date 格式错误或超出范围)、INPUT_TOO_LARGE、INPUT_NOT_FOUND、SECURITY_VIOLATION、INVALID_EXTENSION、IO_ERROR、LIMIT_CEILING_EXCEEDED、OUTPUT_TOO_LARGE、OUTPUT_EXISTS、MISSING_OUTPUT_PATH、CANCELLED、ZIP_DUPLICATE_ENTRY_NAME、ZIP_LIMIT_EXCEEDED、ZIP_STRICT_DIAGNOSTIC,以及结构性 ZIP_* 拒绝错误。
merge_zip
将多个归档合并为一个,无需重新压缩任何内容:zipnative 的 ZipWriter.addFromReader() 会移植每个条目的压缩字节及其压缩方法、CRC、大小、时间戳、属性、注释和额外字段(重新计算 Zip64)。使用 verify: true(默认值)时,每个条目都会先解压一次,并在复制前检查其 CRC 和大小,因此损坏的负载会以其固定错误码被拒绝,而不会被传递;如果条目使用此服务无法解压的方法(非 0 存储/8 deflate),则会以 ZIP_UNSUPPORTED_METHOD 拒绝,而不会未经检查就复制(verify: false 会原样复制;summary.verified 会报告是否启用了验证)。每个名称都会通过写入器的名称规则检查,因此写入器拒绝的源条目——例如 bsdtar 写入的 ./ 目录条目、包含 .. 的片段或设备名称——会导致合并失败,并返回 ZIP_INVALID_ENTRY_NAME 和 data.sourceIndex:使用该来源的 filter 将其排除。加密条目会被拒绝(ZIP_UNSUPPORTED_ENCRYPTION——无法读取其原始数据);将它们过滤掉即可合并其余内容。名称冲突:onConflict: 'error'(默认值)会让引擎拒绝第二个同名条目(ZIP_DUPLICATE_ENTRY_NAME);'first'/'last' 会按来源顺序保留第一个/最后一个条目,并报告其他条目。这里只提供经过检查的移植方式——引擎的 addRaw()(调用方需保证 CRC 和大小正确)不会对外开放,因此 Agent 无法通过此工具伪造内容不一致的归档。结果的排序方式与 create_zip 相同(默认 order: 'canonical');如需完整的规范形式,请对结果运行 canonicalize_zip。每个来源都会在内存中打开。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
sources | 数组,1–32 项 | — | 必需;每项为 { zipBase64 | zipPath, filter? }(filter 与 list_zip_entries 相同;除非过滤器将目录排除,否则会保留目录);总大小 ≤ 1 GiB,所有内嵌负载总大小 ≤ 128 MiB |
onConflict | 'error' | 'first' | 'last' | 'error' | 处理名称相同的两个条目 |
verify | 布尔值 | true | false 表示信任来源——其字节会原样传递 |
order | 'canonical' | 'insertion' | 'canonical' | 'insertion':按来源顺序排列,然后按各来源中央目录中的顺序排列 |
comment | 字符串,≤ 65535 | — | 结果归档的注释(不会合并来源归档的注释) |
includeSha256 | 布尔值 | false | |
outputMode / outputPath | 'base64' | 文件模式会将结果流式写入沙箱 | |
strict、limits | 共用字段 |
输出:以嵌入式 resource 或 resource_link 形式返回归档;summary(sourceCount、entryCount、inputBytes、outputBytes、onConflict、verified、order、perSource[]({ index, label, entryCount, taken, filteredOut, dropped })、dropped[]({ name, source },最多 200 行)、sha256)、diagnostics[]。拒绝操作时会在 data.sourceIndex 中注明来源。
{ "sources": [{ "zipBase64": "<base64 ZIP A>" }, { "zipBase64": "<base64 ZIP B>", "filter": { "prefix": "assets/" } }], "onConflict": "last", "includeSha256": true }
错误:VALIDATION_ERROR、INPUT_TOO_LARGE、INPUT_NOT_FOUND、SECURITY_VIOLATION、INVALID_EXTENSION、IO_ERROR、LIMIT_CEILING_EXCEEDED、OUTPUT_TOO_LARGE、OUTPUT_EXISTS、MISSING_OUTPUT_PATH、CANCELLED、ZIP_DUPLICATE_ENTRY_NAME、ZIP_INVALID_ENTRY_NAME(写入器拒绝的来源名称——请将其过滤掉)、ZIP_CRC_MISMATCH、ZIP_SIZE_MISMATCH、ZIP_DEFLATE_CORRUPT、ZIP_DEFLATE_TRUNCATED、ZIP_UNSUPPORTED_METHOD(verify: true 时遇到此处没有编解码器支持的方法)、ZIP_UNSUPPORTED_ENCRYPTION、ZIP_CD_LFH_MISMATCH、ZIP_ENTRY_OVERLAP、ZIP_LIMIT_EXCEEDED、ZIP_STRICT_DIAGNOSTIC,以及结构相关的 ZIP_* 拒绝错误。
compute_crc32
内联字节/文本或沙盒文件的 ZIP 校验和(IEEE 802.3 CRC-32,采用引擎的 slice-by-8 实现)。文件通过一个打开的句柄以 1 MiB 为块流式读取,大小不超过 1 GiB。seed 用于跨连续数据块延续 CRC;expect 用于与已知值比较。可用它将 list_zip_entries 中条目的 crc32 与磁盘上的文件进行交叉校验。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
dataBase64 / text / sourcePath | string | — | 必须且只能提供其中一项 |
seed | integer 0–4294967295 | 0 | 要延续计算的运行中 CRC |
expect | string | — | 1–8 位十六进制数字,可选 0x(pattern ^(?:0x)?[0-9a-fA-F]{1,8}$) |
输出:crc32(无符号)、hex(8 位小写十六进制数字)、byteLength、seed、matches(提供 expect 时)。
{ "text": "hello world", "expect": "0d4a1185" }
错误:VALIDATION_ERROR、INPUT_TOO_LARGE、INPUT_NOT_FOUND、SECURITY_VIOLATION、IO_ERROR、CANCELLED(在每个 1 MiB 数据块之间检查)。
inflate_raw
使用 zipnative 的可恢复解压器解压原始 DEFLATE(RFC 1951)流,例如 read_zip_entry mode: 'raw' 返回的数据。必须设置 maxOutput 上限。解压器使用恒定内存,精确报告 bytesConsumed,并将尾随字节报告为 leftover;超过上限时返回 ZIP_INFLATE_OUTPUT_OVERFLOW。method: 'store' 表示带上限的直通处理;数字方法 ID 用于选择已注册的编解码器(此服务除 0 / 8 外均不支持 → ZIP_UNSUPPORTED_METHOD)。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
dataBase64 / sourcePath | string | — | 必须且只能提供其中一项 |
maxOutput | integer ≥ 1 | — | 必填;内联结果上限另为 50 MiB,文件结果上限为 ZIPNATIVE_MCP_MAX_FILE_OUTPUT_BYTES |
method | string | 'deflate' | 'deflate'、'store' 或数字 ID(pattern ^(?:deflate|store|[0-9]+)$) |
allowTrailing | boolean | false | 静默接受流之后的字节(始终报告为 leftover) |
outputMode / outputPath | 'base64' | 文件模式:.bin .dat .txt .json .xml .md .csv .html .zip .tar .raw |
输出:以嵌入式 resource(application/octet-stream)或 resource_link 形式返回解压后的字节;以及 summary(method、methodName、bytesIn、bytesOut、bytesConsumed、leftover、finished、maxOutput、trailingWarning)。
{ "dataBase64": "<raw deflate payload>", "maxOutput": 1048576 }
错误:ZIP_INFLATE_OUTPUT_OVERFLOW、ZIP_DEFLATE_CORRUPT、ZIP_DEFLATE_TRUNCATED、ZIP_UNSUPPORTED_METHOD、ZIP_UNSUPPORTED_CODEC_MODE、ZIP_API_MISUSE、CANCELLED(在输入数据块之间检查)、输入封装器错误代码以及文件模式错误代码(OUTPUT_EXISTS、MISSING_OUTPUT_PATH、INVALID_EXTENSION)。若 maxOutput 超过内联或文件上限,则会下调至该上限,因此结果过大时返回 ZIP_INFLATE_OUTPUT_OVERFLOW(data.configured = 实际生效的上限),而不是 OUTPUT_TOO_LARGE。
describe_engine
离线预检(无需存档):服务端/引擎/工具 API 版本和协议字符串、工具数量、正在使用的 deflate 层级和固定的确定性层级、运行时编解码器(node:zlib、CompressionStream、DecompressionStream)和工作线程、编解码器注册表(codecs[],包含 sync、stream 和 incremental——前向读取器和字节范围读取器是否逐块解码该编解码器)、引擎的默认 limits(九个键)、四个操作员上限(maxUncompressedBytes、maxEntries、maxWorkers、maxFileOutputBytes,其中 env 用于命名变量)、每个服务端上限、沙箱和缓存是否启用、39 个冻结的 ZIP_* 错误代码和 12 个诊断代码,以及此服务有意不公开的引擎导出项及各自的原因(nameDecoder、addRaw、registerCodec、工作线程 URL,……)。network 始终为 'none'。从不缓存。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
verbosity、fields | 仅用于投影 |
输出:server、engine、capabilities、codecs[]、defaultLimits、ceilings、caps、sandbox、network、errorCodes[]、diagnosticCodes[]、unexposed[]。
{ "fields": ["defaultLimits", "ceilings", "caps", "sandbox"] }
错误:VALIDATION_ERROR。
draft_governance_issue
在本地起草符合治理要求的 GitHub issue,供人工审核和提交——面向 zipnative(引擎行为:解析、写入、限制、编解码器)或 zipnative-mcp(封装器行为:架构、沙箱、传输)。服务端绝不会联系 GitHub——它完全没有网络代码路径;它会返回 issue 草稿 Markdown 和机器可读的合规报告。将两者都交给用户,然后停止:由用户自行审核并以自己的身份提交。
| 输入 | 类型 | 默认值 | 说明 |
|---|---|---|---|
title | string 8–160 | — | 必填 |
summary | string ≥ 16 | — | 必填;自由文本字段上限为 16 384 个字符 |
issueType | 'bug' | 'feature' | 'security' | 'docs' | 'performance' | — | 必填 |
targetRepo | string 1–100 | 'zipnative-mcp' | 仅用于文档说明 |
reproduction | { command, result } | — | 必填,两者都不能为空 |
expectedBehavior | string ≥ 4 | — | 必填 |
actualBehavior | string | 复现结果 | |
affectedPackages | string[] ≤ 16 | ['zipnative-mcp'] | |
duplicateSearchPerformed | boolean | — | 必填,必须为 true |
outputMode / outputPath | 'inline' | 'file' | 'inline' | 文件模式还会在 ZIPNATIVE_MCP_OUTPUT_DIR 内写入相对 .md 文件(复制到 .github/drafts/ 进行审核——工具绝不会写入该目录) |
输出:title、issueType、targetRepo、outputMode、filePath、sizeBytes、draftMarkdown、warnings[]、compliance(zeroDependencyConfirmed、reproductionCommand、reproductionResult、duplicateSearchPerformed、affectedPackages、identityReminderShown、humanGate、environment)。
{
"title": "list_zip_entries: an optional sort order for the returned page",
"issueType": "feature",
"targetRepo": "zipnative-mcp",
"summary": "Paging through a 70 000-entry archive returns rows in central-directory order only; finding the largest entries means reading every page.",
"reproduction": { "command": "list_zip_entries { zipPath: 'big.zip', limit: 200, fields: ['entries.name', 'entries.uncompressedSize'] }", "result": "rows in central-directory order; no input sorts them by size or name" },
"expectedBehavior": "An optional sort input (name or uncompressedSize, ascending or descending) applied before offset and limit.",
"affectedPackages": ["zipnative-mcp"],
"duplicateSearchPerformed": true
}
若草稿提议添加运行时依赖,或将 duplicateSearchPerformed 设为 false,则会因 GOVERNANCE_VIOLATION 被拒绝;缺少 reproduction(必填输入)则会报 VALIDATION_ERROR。其他错误:VALIDATION_ERROR、MISSING_OUTPUT_PATH、INVALID_EXTENSION、OUTPUT_EXISTS、SECURITY_VIOLATION。完整的人机协作约定请参阅 governance_contract 和 draft_issue_workflow 提示词,以及 docs/guides/AI_GOVERNANCE.md。
🔐 安全模型
zipnative-mcp 在宿主进程内部运行,并提供 stdio MCP 服务(或仅限环回地址的 HTTP 端点)。它将所有存档视为不可信输入,除 ZIPNATIVE_MCP_CACHE_DIR 下的可选响应缓存外,不会在配置的沙箱之外执行任何 I/O。
| 威胁 | 防御措施 | CWE |
|---|---|---|
Zip-slip 路径遍历(../、绝对路径、驱动器号、UNC、反斜杠、NUL、NTFS ADS)以及 Windows 保留设备名称(CON、NUL、AUX、COM1…LPT9) | 默认设置为 rejectTraversal: true → ZIP_PATH_TRAVERSAL;设置为 false 时会跳过,绝不输出;sanitize_entry_paths 为外部接收端提供相同的拦截机制;写入器也会拒绝此类名称 | CWE-22 / CWE-67 |
| 解压缩炸弹(声明大小、总大小、压缩比、条目泛滥) | 九项 ZipLimits 限制在解压过程中强制执行,而非事后检查 → ZIP_LIMIT_EXCEEDED;每次调用的 limits 绝不会超过运维方设定的上限;inflate_raw 必须指定 maxOutput | CWE-400 / CWE-409 |
| 字节范围读取器获取的超大负载 | limits.maxEntryCompressedSize(默认为 1 GiB + 1 MiB,且受 ZIPNATIVE_MCP_MAX_UNCOMPRESSED_BYTES 限制) | CWE-770 |
| 重定向解压路径的符号链接条目 | 默认设置为 rejectSymlinks: true → ZIP_SYMLINK_REJECTED;设置为 false 时,会将目标文本作为普通文件写入——绝不会实际创建链接 | CWE-59 |
| 条目重叠(一个负载被多个条目认领) | 始终启用重叠检测 → ZIP_ENTRY_OVERLAP,不可关闭;modify_zip 会立即打开输入,因此追加路径也会检查 | CWE-405 |
| 解析器差异导致的欺骗(中央目录与本地文件头不一致) | 以中央目录为准;压缩方法/大小/CRC 不一致时返回 ZIP_CD_LFH_MISMATCH(不可关闭),名称不一致时返回 ZIP_NAME_MISMATCH 诊断信息;scan_zip_forward 会标记 trust: 'local-headers-only' | CWE-436 |
| 伪造 Zip64 哨兵值 | 将 Zip64 记录与所有非哨兵经典字段交叉核对 → ZIP_ZIP64_CONTRADICTION,不可关闭 | CWE-1288 |
| 重复条目名称(解压时造成遮蔽) | 默认设置为 onDuplicate: 'error' → ZIP_EXTRACT_DUPLICATE_PATH;'first'/'last' 可有意消解决该情况 | CWE-694 |
| 存在歧义的 EOCD/尾随垃圾数据、超过 2^53 的 64 位字段 | 拒绝处理(ZIP_EOCD_NOT_FOUND、ZIP_VALUE_UNREPRESENTABLE),绝不猜测 | CWE-190 |
| 恶意条目名称导致灾难性回溯 | glob 会编译为 Thompson NFA:单次匹配复杂度为 O(name × pattern),模式最长为 1 024 个字符;治理策略模式也采用线性复杂度 | CWE-1333 |
| 检查与读取之间沙箱文件被替换 | 每次读取都通过同一个已打开的句柄进行,该句柄的真实路径已验证位于沙箱内,并通过设备号和 inode 与句柄绑定;读取期间发生变化的文件会导致 IO_ERROR | CWE-367 |
- 沙箱(
ZIPNATIVE_MCP_OUTPUT_DIR)是读取(zipPath、sourcePath、resources/read、merge_zip的源、前向扫描器的流、字节范围读取器)和写入(outputPath、outputDir、解压后的文件、治理草稿)的唯一文件系统边界。路径必须为相对路径;绝对路径、UNC 路径、..、NUL 字节和非容器扩展名都会被拒绝;读取文件的实际路径和写入文件的父目录必须位于沙箱内(在沙箱中植入的符号链接或 junction 在读取和写入时都会触发SECURITY_VIOLATION——读取时会检查文件本身,因此文件符号链接无法通过仅检查父目录的方式蒙混过关);文件以独占方式打开(OUTPUT_EXISTS——绝不覆盖);写入失败或取消时会删除不完整文件。未设置时 ⇒ 仅使用 base64(ZIPNATIVE_MCP_CACHE_DIR下的可选响应缓存是唯一的其他文件 I/O)。 - 输入会在每个工具的边界处根据严格的 JSON Schema 和 Zod 进行验证——未知或拼写错误的键(顶层或嵌套)会触发
VALIDATION_ERROR;在运行任何解析器之前会对 base64 进行合理性检查(允许data:前缀,拒绝双重 base64 编码);fields路径会拒绝原型链相关的片段,投影仅遍历自有属性。 - 错误边界——每个
ZipError都保留其冻结代码;任何从引擎或运行时逃逸的其他内容都会变为ENGINE_ERROR,并带有data.errorClass: 'internal',其消息中的绝对路径会被移除。错误文本不包含任何主机路径。 - 绝不执行加密:会检测加密条目;如果其本地文件头一致,
verify_zip会将其标记为skipped;读取路径和merge_zip会以ZIP_UNSUPPORTED_ENCRYPTION拒绝处理。没有密码输入项。 - 所有引擎诊断信息都会通过接收器传递——stdio 传输绝不会向 stdout 打印内容。
- HTTP 传输(
ZIPNATIVE_MCP_PORT)仅绑定到环回地址,并设有 Host / Origin 防护、请求超时和标头数量上限;除非设置了ZIPNATIVE_MCP_HTTP_TOKEN,否则不进行身份验证(未提供有效的 bearer token 时返回401)。
完整的威胁模型、供应链说明和可复现性承诺见 SECURITY.md;防护措施及其 CWE 编号见 docs/guides/SECURITY.md。
网络与出站流量
绝不联网。 服务没有任何网络代码路径:没有遥测、没有 GitHub、没有更新检查、没有来自任何工具参数的 URL、没有远程字节范围数据源(引擎的 openZipRange 仅通过沙箱文件句柄运行),并且与它的 PDF 同类产品不同,它没有任何可由操作员配置的端点。describe_engine 报告 network: 'none',而 tests/no-network.test.ts 会据此检查源代码树。归档字节只会通过 JSON-RPC 响应返回,或进入沙箱。引擎本身绝不会打开套接字、访问文件系统或执行 eval。
| 上限 | 值 |
|---|---|
| stdio 帧 / HTTP 正文 | 256 MiB |
每次调用解码后的 zipBase64 / 内联载荷 | 128 MiB |
缓冲的 zipPath / sourcePath | 1 GiB(scan_zip_forward 对 zipPath 不设上限地进行流式处理;access: 'range' 通过字节范围读取更大的 zipPath) |
| 内联输出(归档、解压后的字节、资源读取) | 50 MiB |
| 文件输出 | 默认 4 GiB(ZIPNATIVE_MCP_MAX_FILE_OUTPUT_BYTES,在流式传输期间强制执行) |
内联条目(read_zip_entry、extract_zip、scan_zip_forward) | 16 MiB |
| 内联提取总量 | 32 MiB |
list_zip_entries 分页 | 默认 200 / 上限 2000 |
create_zip 条目数 / modify_zip 操作数 / sanitize_entry_paths 名称数 | 100000 / 1000 / 10000 |
merge_zip 源数 / 源总大小 | 32 / 1 GiB |
filter.names / filter.glob / glob 长度 / 每个条目的 extraFields / fields 路径 | 1000 / 32 / 1024 / 16 / 16 |
scan_zip_forward 的 maxEntries 默认值 / read_zip_entry 范围长度 / extract_zip 资源链接数 | 10000(限制在上限以内) / 16 MiB / 50 |
inspect_zip 确定性问题项 / draft_governance_issue 自由文本 | 200 行 / 16 384 个字符 |
resources/list 条目数 / 遍历深度 / resources/read | 1000 / 8 / 50 MiB |
响应缓存(ZIPNATIVE_MCP_CACHE_DIR)TTL / 大小 | 3600 s / 256 MiB |
| 每个结果的诊断信息 | 200 条(按代码 + 条目去重) |
引擎默认值(limits) | 100000 个条目 · 每个条目 1 GiB · 每个获取条目 1 GiB + 1 MiB 压缩数据 · 总计 8 GiB · 比率 1024 · 名称 4096 字节 · 额外字段和注释 65535 字节 · 中央目录 256 MiB |
每一项都是 src/caps.ts 中的常量,并通过 describe_engine.caps 公布(stdioMaxFrameBytes、maxBase64InputBytes、maxPathInputBytes、maxBase64OutputBytes、maxFileOutputBytes、maxEntryInlineBytes、maxExtractInlineTotalBytes、maxListLimit、defaultListLimit、maxCreateEntries、maxModifyOperations、maxMergeSources、maxMergeInputBytes、maxSanitizeNames、maxDiagnostics、maxDeterminismOffenders、maxFilterNames、maxFilterGlobs、maxGlobLength、maxExtraFields、maxIssueTextChars、maxFieldsPaths、defaultScanMaxEntries、maxResourceLinks、maxRangeLength、maxListedResources、maxResourceWalkDepth、maxResourceReadBytes、cacheTtlSeconds、cacheMaxBytes);当前生效的文件输出上限为 describe_engine.ceilings.maxFileOutputBytes。
有关负责任披露流程,请参阅 SECURITY.md。
🧪 一致性(veraZIP)
ZIP 没有 veraPDF——JHOVE 从未发布过 ZIP 模块,也不存在 ISO/IEC 21320-1 验证器——因此 zipnative 生态系统推出了自己的门禁 veraZIP:一个 ISO/IEC 21320-1:2015(文档容器文件)验证器,取自引擎在 1.1.0 提交中的代码(scripts/verazip-core.mjs),它会使用自己的 EOCD / 中央目录 / 本地文件头读取器直接解析原始字节,并且绝不导入 zipnative——如果验证器与引擎共用解析器,就等于让引擎为自己背书。
npm run validate:zip 会构建服务,通过 真实的 tools/call 处理程序驱动 create_zip、modify_zip、canonicalize_zip 和 merge_zip,覆盖所有写入路径——缓冲、stream: true、一个 Zip64 流式条目、parallel、compression.deterministic、order: 'insertion'、扩展字段、注释、Unix 模式、追加、compact 以及 compact + canonical、追加模式存档的规范化(断言幂等性)、固定日期下的规范化,以及合并——并生成原始构造的文件,写出一个包含 43 个存档的语料库,然后逐条款验证每个文件(23 个检查 ID)。39 个符合规范的存档中包括 4 个恶意但符合规范的存档(zip-slip、一个 Windows 设备名称、重复路径、一个符号链接条目):ISO 配置文件约束的是容器,而非名称的含义,因此这些存档会通过验证器,但 extract_zip 必须拒绝它们——此门禁会同时检查这两点。4 个原始构造的负向金丝雀必须被拒绝,并附带声明的条款 ID。预期结果为 39 个 PASS 和 4 个 XFAIL。第 0 级(ISO 条款)无需外部工具,始终运行;第 1 级会在机器上有相应外部完整性工具时,用这些工具重新测试每个符合规范的存档(unzip -t、7z t、python -m zipfile -t、tar -tf、jar tf),并明确显示跳过缺失的工具;VERAZIP_REQUIRED=1(在 CI 中设置)会在工具缺失时直接失败。语料库定义记录在 docs/data/verazip.json 中,每次运行的清单记录在 test-output/zip/manifest.json 中。
PASS 证明此服务写出的每个存档都是格式正确的 ISO/IEC 21320-1 文档容器:包含一条自洽的中央目录结束记录,中央目录与每个本地文件头一致,仅使用 store / deflate 方法,不加密,不包含多磁盘字段,只在字段溢出时使用有效的 Zip64 记录,并且数据描述符的宽度与本地文件头的 Zip64 扩展字段相匹配。这不代表认证——它只是针对特定验证器版本的验证证据;符合规范不等于安全:安全防护是在符合规范的基础上额外实现的。
此门禁会阻止流程继续:ci 工作流会在 Linux(Node 22 和 24)、Windows 和 macOS 上通过 scripts/gate.ts --ci --require-all 运行该门禁;verazip.yml 会在每次向 main 推送和提交拉取请求时(以及手动触发时)在 Linux 和 Windows 上重复运行该门禁,并且每次发布前也会再次运行。测试通过工具生成的每个存档都必须通过 assertValidZip(包括 ISO 一致性检查)。参见 docs/guides/CONFORMANCE.md。
🧪 本地开发
git clone https://github.com/Nizoka/zipnative-mcp.git
cd zipnative-mcp
npm ci --ignore-scripts # .npmrc sets ignore-scripts=true: nothing builds on install
npm run gate:fast # before every commit: typecheck:all, lint, test, server-json, verify:docs
npm run gate # the CI profile: + build, dist checks, stdio smoke test, tool shape, samples, coverage, docs, the veraZIP corpus, examples
npx tsx scripts/gate.ts --publish --require-all # release branches: every step, a skipped step fails
npm run gate (scripts/gate.ts) 是通过标准的唯一依据:79 个测试文件中的 1643 项测试、vitest.config.ts 的覆盖率阈值(94 / 90 / 95 / 94),以及通过 stdio 驱动的构建后服务,其中 stdout 只能包含 JSON-RPC 帧。每个步骤会打印一行,并将日志写入 test-output/.gate/<step>.log;--only <step> 运行一个步骤,--from <step> 从指定步骤恢复,--json 输出机器可读结果(直接调用脚本以传递标志:PowerShell 会吞掉 npm run 后单独的 --)。该 gate 具有封闭性:TZ=UTC,清除所有继承的 ZIPNATIVE_MCP_* 变量,不使用网络。各个步骤都是普通的 npm 脚本:
| 脚本 | 功能 |
|---|---|
npm run typecheck:all | 对 src/ + tests/ 运行 tsc --noEmit,然后检查 scripts/ |
npm run lint | eslint src --max-warnings 0 — 出现警告即失败(no-console:stdout 是 stdio 通道) |
npm test / npm run test:coverage | vitest / 使用 v8 覆盖率 — 阈值见 vitest.config.ts |
npm run build | tsc -p tsconfig.build.json → dist/ |
npm run examples:check | 通过 tools/call 处理程序实时运行 38 个 examples/*.json(多步骤示例会串联执行) |
npm run test:generate / npm run verify:samples | 54 个样本基线:在封闭环境下运行构建后的服务 → test-output/samples/,并根据 tests/_fixtures/samples.sha256.json 校验(since 链会标明每个输出所属的版本) |
npm run corpus:zip / npm run validate:zip | 将 veraZIP 语料写入 test-output/zip/,并在 0 和 1 级进行验证(缺少外部工具时,VERAZIP_REQUIRED=1 会拒绝通过) |
npm run verify:tool-shape | 在 192 KiB 目录和 8 KiB 指令预算内,将构建后的 tools/list 结构与 tests/_fixtures/tool-shape.json 进行比对(仅在有意更改架构后运行 npx tsx scripts/tool-shape.ts --write) |
npm run verify:docs | 根据 docs/assets/ecosystem.json 和源代码树校验文档中的所有数量、版本、工具、代码、操作员变量、链接和锚点 |
npm run verify:issue | 治理草案检查器 |
npm run agents:rules | 根据 .github/instructions/*.instructions.md 重新生成 .claude/rules/*.md |
npm run release:prepare | 机械式提升版本(绝不会提交、打标签或发布) |
npm run hooks:install / hooks:uninstall | 可选的 git hooks(pre-commit 和 pre-push) |
通过 stdio 对服务进行冒烟测试:
node dist/cli.js
# In another terminal, send a JSON-RPC initialize request via stdin (e.g. with the MCP Inspector).
npx @modelcontextprotocol/inspector --cli node dist/cli.js --method tools/list
使用仓库的 .mcp.json 从 Claude Code 驱动构建后的服务(先运行 npm run build;Claude Code 首次使用时会请求批准,并注入 ${CLAUDE_PROJECT_DIR});也可以使用绝对路径从 Claude Desktop 驱动,或使用 MCP Inspector 驱动 — 要重放的场景和预期结果见 docs/guides/LOCAL_TESTING.md §“通过 Claude Code / Claude Desktop / MCP Inspector 驱动”。
使用 bearer token 和沙箱通过 HTTP 运行:
ZIPNATIVE_MCP_PORT=3000 ZIPNATIVE_MCP_HTTP_TOKEN=change-me-to-a-real-secret ZIPNATIVE_MCP_OUTPUT_DIR=/tmp/zips npx zipnative-mcp
# POST http://127.0.0.1:3000/mcp with Authorization: Bearer …
贡献者: 请从
AGENTS.md开始(所有编码 Agent 和贡献者共用的仓库规则),并参阅 CONTRIBUTING.md 了解完整工作流 — 包括 gate、作为测试的示例、样本基线、对测试写入的每个归档文件调用assertValidZip、veraZIP 语料以及 MCP Inspector。
📣 发布流程
zipnative-mcp 遵循与 zipnative、pdfnative-mcp 和 pkinative-mcp 相同的发布规范:
- 每个标签对应一个发布说明文件,位于
release-notes/vX.Y.Z.md(不使用表情符号);CHANGELOG.md镜像记录每次发布的项目列表;GitHub Release 正文从发布说明中复制 npx tsx scripts/release-prepare.ts --version X.Y.Z执行版本升级的机械性工作(不会提交、打标签或发布);package.json、src/version.ts、server.json和CITATION.cff(tests/metadata.test.ts)中的版本保持同步,docs/assets/ecosystem.json也会同步更新(npm run verify:docs);只有架构或错误代码发生变化时,才会升级TOOL_API_VERSION- 发布分支必须通过
npx tsx scripts/gate.ts --publish --require-all——执行所有步骤,包括 veraZIP 语料库,不得跳过 - npm 发布由 GitHub Actions Trusted Publishing(OIDC)处理,不使用
NPM_TOKEN:publish.yml依次运行verify(发布门禁、一次npm pack、CycloneDX SBOM、摘要)→publish(受保护的npm-publish环境,发布传递过来的 tarball,并附带--provenance)→attest(比对注册表中的字节,为 tarball 和 SBOM 生成构建来源证明,并将二者附加到发布中)→registry(通过固定到 SHA-256 的mcp-publisher将server.json发布到 MCP 注册表) - 每个作业都从
step-security/harden-runner开始(macOS 上会跳过,因为该操作不支持 macOS),检出时设置persist-credentials: false,使用npm ci --ignore-scripts安装,并在遵循最小权限原则的permissions下运行;操作均固定到提交 SHA - 人工参与流程:编码 Agent 负责准备和验证;维护者负责推送、创建拉取请求、打标签和发布(
.github/AGENT_RULES.md)
规范结构和发布检查清单见 release-notes/TEMPLATE.md,发布流程见 CONTRIBUTING.md。
📚 项目结构
src/
├── cli.ts # entrypoint: stdio (default, 256 MiB frames) or Streamable HTTP (ZIPNATIVE_MCP_PORT); reads the four ceilings once
├── http.ts # Node http <-> Web Request/Response bridge, 256 MiB body cap, Host/Origin loopback guard, timeouts, security headers
├── auth.ts # opt-in HTTP bearer token (ZIPNATIVE_MCP_HTTP_TOKEN)
├── server.ts # Server factory, TOOLS registry, dispatchOutput, cache gate, cancellation / progress wiring, SERVER_INSTRUCTIONS, 7 prompts, resources
├── call-context.ts # per-call context: the cancellation signal, the progress reporter, CANCELLED
├── caps.ts # every byte / count cap + the operator ceilings (MAX_UNCOMPRESSED_BYTES, MAX_ENTRIES, WORKERS, MAX_FILE_OUTPUT_BYTES)
├── limits.ts # the nine ZipLimits bounds as an input fragment; LIMIT_CEILING_EXCEEDED
├── sandbox.ts # the single filesystem boundary (ZIPNATIVE_MCP_OUTPUT_DIR): container extensions, one-handle reads, realpath checks, wx writes
├── archive-input.ts # zipBase64 XOR zipPath; buffered load, streamed source, access auto / memory / range (openZipRange over the file handle)
├── canonical.ts # the canonical-form options shared by canonicalize_zip and modify_zip canonical
├── base64.ts # base64 boundary decoding with agent-facing diagnostics
├── zip-errors.ts # ZipError -> ToolError (the 39 frozen ZIP_* codes verbatim), guard(), the 12 diagnostic codes
├── wrapper-codes.ts # the 17 wrapper error codes with meaning and remedy
├── diagnostics.ts # engine diagnostic sink (dosTimeMode utc, signal, onProgress; de-duplicated, capped at 200) -> diagnostics[]
├── entry.ts # EntryView: the CLI's --json row shape (flags, unixMode, sanitizedPath, extra fields, rawNameHex, opt-in timestamps / ids)
├── filter.ts # names / prefix / glob entry filter (linear-time Thompson NFA)
├── entry-spec.ts # create / modify payloads: compression, dates (UTC), unixMode / externalAttributes, extra fields
├── engine.ts # initNodeZipCodecs once; runtime capability probe
├── output.ts # base64 emitter / sandboxed exclusive file writer (buffered + streamed, partial file removed)
├── resources.ts # zipnative://output/{+path} over every sandbox file (MIME by extension)
├── projection.ts # verbosity / fields projection for the read tools (prototype segments refused)
├── cache.ts # opt-in SHA-256 response cache (ZIPNATIVE_MCP_CACHE_DIR)
├── governance.ts # AI-governance / HITL contract text + draft validation (linear-time patterns)
├── errors.ts # ToolError, SecurityError, GovernanceError, absolute-path redaction
├── version.ts # ZIPNATIVE_MCP_VERSION, TOOL_API_VERSION
├── index.ts # public library exports
└── tools/
├── _shared.ts # parseInput, ProjectionShape, EngineOptionsShape, sha256Hex
├── inspect-zip.ts
├── list-zip-entries.ts
├── read-zip-entry.ts
├── verify-zip.ts
├── extract-zip.ts
├── scan-zip-forward.ts
├── sanitize-entry-paths.ts
├── create-zip.ts
├── modify-zip.ts
├── canonicalize-zip.ts
├── merge-zip.ts
├── compute-crc32.ts
├── inflate-raw.ts
├── describe-engine.ts
└── draft-governance-issue.ts
scripts/
├── gate.ts # THE quality gate (npm run gate / gate:fast; --publish --require-all on release branches)
├── verify-docs.ts # npm run verify:docs — the docs held to docs/assets/ecosystem.json and the source tree
├── release-prepare.ts # mechanical version bump (never commits, tags or publishes)
├── tool-shape.ts # structural tools/list fingerprint and size budgets (--write refreshes the fixture, --check, --stats)
├── generate-samples.ts # npm run test:generate — the examples through the built server -> test-output/samples/
├── verify-samples.ts # npm run verify:samples — the sample baseline (tests/_fixtures/samples.sha256.json)
├── build-claude-rules.ts # npm run agents:rules — .github/instructions/ -> .claude/rules/
├── install-git-hooks.mjs # npm run hooks:install / hooks:uninstall
├── verazip-core.mjs # vendored engine-independent ISO/IEC 21320-1 validator (never imports zipnative)
├── verazip-core.d.mts # its type declarations
├── generate-zip-corpus.mjs # writes the veraZIP corpus through the real tools + raw-crafted canaries (npm run corpus:zip)
├── validate-zip.mjs # the veraZIP gate: level 0 (ISO clauses) + level 1 (foreign integrity tools)
├── verify-issue.mjs # governance draft checker (npm run verify:issue)
├── helpers/
│ ├── zip-corpus.mjs # the corpus definition (every writer path + the hostile-but-conformant quartet + the canaries)
│ ├── zip-corpus.d.mts # its type declarations
│ ├── raw-zip-builder.mjs # engine-independent raw ZIP writer for the crafted canaries (vendored from zipnative)
│ ├── interop-tools.mjs # unzip / 7z / python zipfile / tar / jar probes for level 1
│ ├── hermetic.ts # the hermetic environment (TZ=UTC, ZIPNATIVE_MCP_* scrubbed)
│ ├── tz.ts # time-zone helpers for the hermetic runs
│ ├── io.ts # file helpers of the scripts
│ └── server.ts # drives the built server from the scripts
└── lib/
├── tool-shape.ts # the fingerprint and the 192 KiB / 8 KiB budgets
├── sample-fingerprint.ts # bytes / semantic fingerprints of the samples
├── example-runner.ts # runs an examples/*.json sequence
├── mcp-surface.ts # tools, codes and variables read from the source tree
├── markdown-anchors.ts # heading anchors for the link checks
├── agent-config.ts # .claude/ settings, guard hook and PR template checks
├── prose-language.ts # the English-only rule
├── secret-needles.ts # the no-secret-material needles
└── json-schema-lite.ts # offline server.json validation against the vendored registry schema
docs/
├── AGENT_CONTRACT.md # the consumer contract for agents that USE the server (catalogue, decision tree, recipes, error reference)
├── AI_GUIDE.md # decision tree + pitfalls for agents
├── API_STABILITY.md # the tool-API stability charter (versioning, bump rules, per-tool matrix)
├── KNOWLEDGE_BASE.md # architecture reference + the 106-export coverage ledger (§8)
├── guides/AI_GOVERNANCE.md # the human-in-the-loop contract, narrated
├── guides/CONFORMANCE.md # the veraZIP gate explained
├── guides/DETERMINISM.md # the determinism levels, canonicalisation and how to prove them
├── guides/INCREMENTAL.md # modify_zip: append vs compact, remanence, the 7-Zip differential
├── guides/LARGE_ARCHIVES.md # byte-range access, Zip64 streaming, the file-output ceiling
├── guides/LOCAL_TESTING.md # the gate, assertValidZip, veraZIP locally, driving the server from Claude Code / Inspector
├── guides/SECURITY.md # threat model and defences with CWE ids
├── data/errors.json # the 39 codes + 12 diagnostics (copy of the engine registry)
├── data/core-exports.json # the 106 exports of zipnative 1.1.0 and their reach
├── data/verazip.json # the corpus counts
└── assets/ecosystem.json # the single source of every count and version quoted in the docs
examples/ # 38 executable tool invocations (npm run examples:check)
tests/ # vitest suites, one per tool / module (<tool>.test.ts, <module>.test.ts) plus:
├── _zip-fixtures.ts # benign archives via the engine + hostile ones via _fixtures/raw-zip-builder.ts (vendored)
├── _zip-assert.ts # assertValidZip / assertIsoConformant / expectCheck
├── _mcp-harness.ts # in-memory legacy-handshake client (captures notifications)
├── _http-fixture.ts # loopback HTTP fixture (2026-07-28 envelope + legacy initialize)
├── _agent-client.ts # the scripted MCP client of the autonomy scenario (stdio / HTTP × legacy / modern)
├── _fuzz.ts # seeded PRNG and mutators (deterministic; not coverage-guided)
├── autonomy.test.ts # S0–S17 agent scenario on stdio legacy / stdio modern / HTTP legacy / HTTP modern + bearer token
├── protocol-revisions.test.ts # the five legacy revisions (2024-10-07 … 2025-11-25) negotiated on both transports
├── stdio-modern.test.ts # 2026-07-28 server/discover + _meta envelope over the built CLI
├── http-modern.test.ts # 2026-07-28 over HTTP: cache hints, Mcp-Method / Mcp-Name, -32602, batches
├── http-hardening.test.ts # body cap, timeouts, header bound, security headers
├── http-shutdown.test.ts # SIGTERM in HTTP mode exits cleanly and releases the port
├── cancellation.test.ts # CANCELLED and notifications/progress over MCP
├── range-access.test.ts # access 'range' / 'auto' through the byte-range reader
├── zip64-streaming.test.ts # create_zip zip64 on stream entries and the file-output ceiling
├── zip64.test.ts # 70 000-entry reads and a 65 536-entry create_zip (auto-promotion)
├── reproducible-build.test.ts # identical bytes from the built server under two time zones
├── zip-fuzz.test.ts # the seeded hostile-input suite over every tool
├── no-network.test.ts # the no-network doctrine over src/
├── schema-lockstep.test.ts # Zod input schemas ↔ advertised JSON Schemas (keys, required, enums, defaults, bounds, patterns)
├── catalogue-parity.test.ts # tools/list vs tests/_fixtures/tool-shape.json
├── catalogue-superset.test.ts # tools/list is a superset of the frozen tests/_fixtures/tool-shape.v1.0.0.json
├── docs-consistency.test.ts # counts / names / codes quoted in the docs, the SFX guard, the export ledger, the veraZIP corpus counts, this tree
├── diagnostics-inventory.test.ts # every reachable diagnostic produced by a tool call
├── tools/ # the repository tooling suites (gate, verify-docs, release-prepare, workflows, guard, …)
└── fixtures/ # interop archives (bsdtar, PowerShell), the frozen example inputs, SHA256SUMS, PROVENANCE.md
AGENTS.md, CLAUDE.md # repository rules for coding agents; .github/instructions/ holds the per-area rules
.claude/ # shared agent settings, the fail-closed guard hook, generated rules, the release-audit skill
.mcp.json # drives the built server from Claude Code (stdio, sandbox under test-output/mcp-sandbox)
.github/workflows/ci.yml # the gate (--ci --require-all) on Linux (Node 22 / 24), Windows and macOS
.github/workflows/verazip.yml # BLOCKING veraZIP job on Linux and Windows (VERAZIP_REQUIRED=1)
.github/workflows/sample-regression.yml # the sample baseline on every pull request that can change an output
.github/workflows/publish.yml # verify -> publish -> attest -> registry (Trusted Publishing, provenance, SBOM, attestation, MCP registry)
.github/workflows/docs.yml # verify:docs on docs changes and weekly; the manifest against npm
.github/workflows/codeql.yml # CodeQL security-extended
.github/workflows/scorecard.yml # OpenSSF Scorecard
.github/workflows/dependency-review.yml # licence and advisory gate on dependency changes
.github/workflows/audit.yml # weekly npm audit (full tree and runtime tree)
.github/workflows/node-current.yml # the gate on the current Node line (advisory)
.github/rulesets/ # branch and tag rulesets to import
🗺 路线图
v1.1.0 是首个次要版本,基于 zipnative 1.1.0:新增两个工具(canonicalize_zip、merge_zip)、字节范围读取、Zip64 流式处理的可选启用、取消与进度报告、UTC 时间戳,以及一个经过实时检查、确保涵盖冻结的 1.0.0 目录内容的目录。完整计划——已发布的里程碑、上游阻塞事项和长期方向——见 ROADMAP.md。
出于设计考虑,不提供:
- 加密和解密——engine 1.x 中没有此功能(ZipCrypto 已不安全;AES 是 engine 2.0 的候选功能);只有届时这里才会提供密码输入。
nameEncoding/nameDecoder——按照规范,旧式非 UTF-8 名称会按 cp437 解码;不提供由 Agent 提供的解码器。addRaw、自定义编解码器、远程字节范围源——merge_zip是经过检查的移植功能,registerCodec是可执行代码,而此服务没有网络访问路径。
有功能创意?欢迎提交 issue 或 PR,也可以让 Agent 使用 draft_governance_issue 起草一个,然后由你自行提交。
⭐ 为项目点星
如果 zipnative-mcp 对你有帮助,请为此仓库点 ⭐——也欢迎为底层引擎 Nizoka/zipnative 点星。星标有助于其他人发现项目,也能激励我们持续开发。
🤝 参与贡献
我们非常欢迎贡献。请阅读 CONTRIBUTING.md,查看未解决的问题,并遵守行为准则。
📄 许可证
MIT © 2026 Nizoka。第三方材料:THIRD-PARTY-NOTICES.md。
zipnative-mcp 基于 zipnative 和 Model Context Protocol TypeScript SDK 构建。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。