关于 Deadzone
Deadzone 是本地优先的文档语义搜索 MCP 服务,为使用 MCP 的开发者和 AI 工具检索程序库文档。它通过向量搜索返回片段,索引保存在本机 Turso 文件中。
主要功能
- 01按自然语言搜索程序库
- 02语义检索文档片段
- 03按库和版本筛选
- 04限制结果令牌预算
- 05本地保存索引
适用场景
- 01查找库中某项功能的实现说明
- 02按指定版本检索文档
- 03为编码 Agent 提供文档片段
MCP 相关
Deadzone 通过 stdio 提供 MCP 服务,向客户端开放 `search_libraries` 和 `search_docs` 两个工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm ghcr.io/laradji/deadzone:v0.7.4本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/laradji/deadzone:v0.7.4stdio工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
_ _
__| | ___ __ _ __| |_______ _ __ ___
/ _` |/ _ \/ _` |/ _` |_ / _ \| '_ \ / _ \
| (_| | __/ (_| | (_| |/ / (_) | | | | __/
\__,_|\___|\__,_|\__,_/___\___/|_| |_|\___|
> semantic doc search. local file. no cloud. no key.
> you ask in english. it answers in snippets.
状态。 向量搜索已端到端接通。通过标准输入输出运行 MCP。单个二进制文件,支持 Linux 和 macOS,零遥测。最新标签请参阅发布版本,正在进行的工作请参阅路线图。 抓取器仍是混乱的那一部分——#64对此毫不避讳。
一段话介绍
你的 AI 客户端问:“如何注册一个工具?”文档里写的是 AddTool。基于 grep 的索引只能耸耸肩,向量索引却能找到答案。Deadzone 就是这个向量索引——使用 nomic-embed-text-v1.5,基于 Turso 原生余弦距离,由一个通过标准输入输出运行 MCP、并将每个字节都留在你笔记本电脑上的 Go 二进制文件封装而成。大致来说,它就是断网版的 Context7。
Deadzone 的规则
- 单个二进制文件。
deadzone。所有功能都通过子命令实现。不需要pip install、npm i或docker compose up。 - 索引绝不离开本机。 本地 Turso 文件。无需账户,无需 API 密钥,关键路径不向外联网。
- 自然语言优先。 使用基于余弦距离的嵌入。不使用
FTS5。 - 二进制文件就是版本。 数据库与二进制文件绑定。升级二进制文件,数据库也会随之更新;不升级,数据库就不会变。
- 要么明确失败,要么不猜。
DEADZONE_DB_OFFLINE=1会拒绝猜测。抓取器中的验证失败会丢弃文档,而不是中止整个任务。
安装(任选一种;最终都会使用同一个二进制文件)
# macOS Apple Silicon — the one-liner
brew install laradji/deadzone/deadzone
# Linux — resolve the latest tag once, then pick a flavor
VERSION=$(curl -fsSL https://api.github.com/repos/laradji/deadzone/releases/latest | grep '"tag_name"' | cut -d'"' -f4)
ARCH=amd64 # or arm64
# self-mounting AppImage
curl -L -O "https://github.com/laradji/deadzone/releases/download/${VERSION}/deadzone_${VERSION}_linux_${ARCH}.AppImage"
chmod +x "deadzone_${VERSION}_linux_${ARCH}.AppImage"
mv "deadzone_${VERSION}_linux_${ARCH}.AppImage" deadzone
# or plain tarball (no FUSE needed)
curl -L "https://github.com/laradji/deadzone/releases/download/${VERSION}/deadzone_${VERSION}_linux_${ARCH}.tar.gz" \
| tar xz --strip-components=1
这两种方式都会在当前目录中生成一个 deadzone 可执行文件,因此下面的 ./deadzone server 代码片段可以直接使用。
# Container — multi-arch (linux/amd64 + linux/arm64), ships with the DB baked, runs offline by default
docker pull ghcr.io/laradji/deadzone:latest
docker run --rm -i ghcr.io/laradji/deadzone:latest server
镜像内置了二进制文件、libonnxruntime、deadzone.db 和 nomic-embed-text-v1.5 ONNX 权重(总计约 230 MB),并以非 root 用户身份运行于 distroless 之上(没有 shell,也没有包管理器)。镜像中已设置 DEADZONE_DB_OFFLINE=1,因此首次启动即可立即运行——无需下载、无需挂载卷,也无需访问 --network。要刷新索引,只需拉取更新的标签。
Windows 目前受上游限制——缺少 libtokenizers.a。请使用 WSL。
校验校验和(可选,但成本很低):
curl -L -O "https://github.com/laradji/deadzone/releases/download/${VERSION}/deadzone_${VERSION}_checksums.txt"
sha256sum --ignore-missing -c "deadzone_${VERSION}_checksums.txt" # Linux
shasum -a 256 --ignore-missing -c "deadzone_${VERSION}_checksums.txt" # macOS
AppImage 需要 FUSE v2。 大多数桌面系统都已安装;精简服务器则没有。如果出现 dlopen(): libfuse.so.2,请运行 apt-get install libfuse2(或 dnf install fuse-libs),也可以传入 --appimage-extract-and-run,完全绕过 FUSE。
运行
./deadzone server
这就是快速入门。首次启动时,它会获取与此二进制文件版本匹配的 deadzone.db,通过 SHA256 校验后,将其缓存到平台数据目录并启动服务。从第二次启动开始:完全不需要联网。升级二进制文件后,下次启动时会重新获取数据库;不升级,缓存就会一直使用。
MCP 客户端连接配置——原生二进制文件(Brew tap、tarball 或 AppImage):
{
"mcpServers": {
"deadzone": {
"type": "stdio",
"command": "/path/to/deadzone",
"args": ["server"]
}
}
}
MCP 客户端连接配置——容器(ghcr.io 上的多架构镜像)。镜像已内置 deadzone.db,因此无需挂载卷,每次启动容器都能立即离线运行:
{
"mcpServers": {
"deadzone": {
"type": "stdio",
"command": "docker",
"args": ["run", "--rm", "-i", "ghcr.io/laradji/deadzone:latest", "server"]
}
}
}
然后,在客户端中:
search_libraries("terraform aws") → ranked (lib_id, version) pairs
search_docs("creating an s3 bucket", lib_id=...) → snippets, token-budgeted
两个工具
┌─────────────────────────────────────────────────────────────────────┐
│ search_libraries(name, limit?) → []LibraryHit │
│ ───────────────────────────────────────────── │
│ free text ──► vector match against the `libs` table │
│ ──► [{lib_id, version, doc_count, match_score}] │
├─────────────────────────────────────────────────────────────────────┤
│ search_docs(query, lib_id?, version?, tokens?) → []Snippet │
│ ────────────────────────────────────────────────── │
│ natural ──► 768-dim embed ──► cosine over docs │
│ language ──► token-budgeted snippets back │
└─────────────────────────────────────────────────────────────────────┘
| 参数 | 形式 | 说明 |
|---|---|---|
query | 字符串 | 按语义匹配。不要写关键词,写出你想要的内容。 |
lib_id | /org/project | 可选筛选条件。从 search_libraries 获取。 |
version | "1.14" 或类似值 | 可选版本固定;需要提供 lib_id。单独提供 version 会被拒绝。 |
tokens | 整数 | 响应预算。默认值为 5000,最小值为 1000,约 4 个字符对应 1 个 token。 |
limit | 整数 | 用于 search_libraries——最大结果数。默认值为 10,最大值为 50。 |
name | 字符串 | search_libraries 的自由文本。留空则返回索引最多的库。 |
实现原理
deadzone server
│
▼
┌──────────────┐ stdio JSON-RPC ┌───────────────┐
│ MCP client │ ─────────────────────► │ handler │
└──────────────┘ └──────┬────────┘
│
┌──────────────────┴──────────────────┐
▼ ▼
┌────────────────┐ ┌──────────────────┐
│ embedder │ │ Turso (local) │
│ hugot + ORT │ │ F32_BLOB(768) │
│ nomic v1.5 │ │ vector_distance │
└────────┬───────┘ └──────────────────┘
│ 768-dim ▲
└────────────── query vector ────────┘
| 层级 | 选择 |
|---|---|
| 语言 | Go 1.26.2,通过 mise 固定版本 |
| 存储 | Turso 本地文件 — 原生支持 F32_BLOB(N) + vector_distance_cos |
| 驱动 | tursogo — 通过 purego 实现 无 CGO |
| 嵌入模型 | hugot → nomic-ai/nomic-embed-text-v1.5,768 维,8192 token 上下文(int8 量化) |
| 运行时 | ONNX Runtime — 构建时以 CGO 链接二进制;首次启动时自动获取并验证 libonnxruntime 的 SHA256 |
| 协议 | 通过 stdio 使用 modelcontextprotocol/go-sdk |
二进制本身通过 CGO 链接(hugot ORT 后端 + 静态 libtokenizers.a)。在运行时,唯一的原生依赖是 libonnxruntime,它会在 SHA256 验证通过的自动下载后通过 dlopen 加载。其他所有内容——Go 标准库、tursogo、模型权重——要么静态链接,要么首次启动时通过固定哈希获取。无需安装系统依赖,无需 sudo。如果下载内容与固定哈希不符,程序将中止运行;不会回退到未经验证的下载。
适用于气隙隔离设备的备用方式:
| 环境变量 | 作用 |
|---|---|
DEADZONE_ORT_LIB_PATH | 手动指定 libonnxruntime 路径。跳过下载。 |
DEADZONE_ORT_CACHE | 覆盖 ORT 库缓存目录。 |
DEADZONE_HUGOT_CACHE | 覆盖模型权重缓存目录。 |
DEADZONE_DB_CACHE | 覆盖 deadzone.db 缓存目录。 |
DEADZONE_DB_OFFLINE=1 | 拒绝任何网络调用。如果没有缓存内容则明确报错。容器镜像默认设置此项(镜像中已预置 deadzone.db)。 |
DEADZONE_DB_AUTOUPDATE=0 | 禁用启动时的数据库新鲜度检查(默认会执行该检查;无论此标志为何值,fetch-db 都会始终执行检查)。 |
各平台的默认缓存路径:
| 平台 | deadzone.db 的位置 |
|---|---|
| macOS | ~/Library/Application Support/deadzone/deadzone.db |
| Linux | $XDG_DATA_HOME/deadzone/deadzone.db(否则为 ~/.local/share/...) |
| Windows | %LOCALAPPDATA%\deadzone\deadzone.db |
同目录下的 deadzone.db.release JSON 清单记录 {tag, sha256, fetched_at}。启动时会将缓存的标签与二进制中编译的版本进行比较:匹配 → 向对应 GitHub Release 中的 deadzone.db.sha256 发起 3 秒新鲜度检查,如果远程 sha 不同则原子替换(发生任何网络错误时软失败并继续使用缓存);不匹配 → 获取新标签对应的发布版本并原子替换;开发构建 → 回退到 /releases/latest,并记录 server.db_version_dev_fallback WARN。#197 之前的二进制会写入仅含标签的单行 sidecar;JSON 读取器仍接受此格式,并会在首次检查时将其重写为 v1 格式。
添加库
贡献者路径。最终用户无需处理此项——他们只需使用 deadzone.db 中提供的内容。
不打算自己编辑 YAML? 请通过新建问题页面提交 issue,并选择添加库或刷新库。模板会收集注册表条目所需的全部信息。
打算自己编辑 YAML? 请将条目追加到 libraries_sources.yaml:
libraries:
# Single-version lib — no `versions` key, urls used as-is.
- lib_id: /modelcontextprotocol/go-sdk
kind: github-md
urls:
- https://raw.githubusercontent.com/modelcontextprotocol/go-sdk/main/README.md
- https://raw.githubusercontent.com/modelcontextprotocol/go-sdk/main/docs/quick_start.md
# Multi-version lib — `versions` expands into one effective lib_id
# per version (/org/project/1.4, /org/project/1.5, …). {ref} is
# substituted from each version's ref: field.
- lib_id: /modelcontextprotocol/go-sdk
kind: github-md
versions:
"1.4": { ref: v1.4.1 }
"1.5": { ref: v1.5.0 }
urls:
- https://raw.githubusercontent.com/modelcontextprotocol/go-sdk/{ref}/README.md
- https://raw.githubusercontent.com/modelcontextprotocol/go-sdk/{ref}/docs/getting-started.md
| 字段 | 必填 | 用途 |
|---|---|---|
lib_id | 是 | 规范的 /org/project 标识符(与 db.docs.lib_id 一致)。 |
kind | 是 | github-md(原始 markdown)、github-rst(原始 reStructuredText)或 scrape-via-agent(通过 LLM 处理 HTML/文本)。 |
urls | 是 | 文档 URL 列表,可选包含 {ref} 占位符。 |
versions | 否 | {"1.4": {ref: v1.4.1, urls: [...]}, "1.5": {ref: v1.5.0}, …} — 面向用户的标识符优先使用 major.minor。 |
ref | 否 | 替换 {ref} 的 Git 标签或提交 SHA。每个版本的 ref: 会覆盖顶层设置。 |
versions[v].urls | 否 | 每个版本的 URL 列表——会整体替换基准列表。适用于结构差异较大的版本。 |
1.0 之前:无需编辑 Go 代码,也无需重新编译。只需编辑 YAML 并重新抓取。
通过 Agent 抓取(实验性)
⚠️ 比较麻烦的部分。 目前适用于非 markdown 来源(Terraform 提供程序、mkdocs、GitBook 等),但 LLM→验证器循环容易受输入截断(上限为 48 KiB)、HTML→markdown 技能以及逐字代码匹配的影响。在内容密集的文档网站上,实际命中率约为每个 URL 50%——参见 #64。只要项目提供了已提交的 markdown,就优先使用
github-md。
使用你自己的 LLM 运行时——Ollama、llama.cpp、vLLM、LocalAI、LM Studio、Groq、OpenAI,或任何支持 POST /v1/chat/completions 的运行时:
export DEADZONE_AGENT_ENDPOINT=http://localhost:11434/v1
export DEADZONE_AGENT_ENDPOINT_MODEL=qwen2.5:7b
export DEADZONE_AGENT_ENDPOINT_API_KEY=sk-... # optional
然后在 libraries_sources.yaml 中添加一个 kind: scrape-via-agent 条目,并列出页面 URL。下游流水线(解析 → 分块 → 嵌入 → 存储)与 github-md 完全相同;只有 markdown 来源不同。
防护措施。 LLM 输出中的每个围栏代码块都会与来源逐字验证——虚构示例会导致文档被丢弃(scraper.agent_verification_failed),而不会中止整个运行。端点缺失或无法访问时会在启动时中止;不会静默回退。
本地流水线(贡献者)
分两步引导:先准备工具链,再准备 CGO 原生依赖——两者分开处理,以便使用已供应 libtokenizers.a 的隔离网络 / CI 运行器通过覆盖 DEADZONE_TOKENIZERS_LIB 跳过第 2 步。
just bootstrap # Go 1.26.2 + just toolchain (mise install)
just fetch-tokenizers # libtokenizers.a — one-shot CGO setup
just build # CGO + ORT, all packages
just scrape # all libs — one artifact folder per lib
just scrape /hashicorp/terraform # one base lib, every version
just scrape /hashicorp/terraform/1.14 # one exact version
just consolidate # merge artifacts/*/artifact.db → deadzone.db
just serve # MCP server against deadzone.db
不带参数运行 just 会列出所有配方。每次抓取都会就地重写 artifacts/<slug>/artifact.db 和 state.yaml;consolidate 会将所有构件数据库原子性地合并到 deadzone.db。每个库的文件夹都被 gitignore 忽略;已提交的 artifacts/manifest.yaml 只记录发布历史。
通过 CI 获取完整注册表。 gh workflow run scrape-pack.yml -f tag=vX.Y.Z 会并行运行矩阵任务、合并结果,并将 deadzone.db 上传到带标签的发布版本。省略 -f tag=… 即会在生成合并数据库缓存后停止。
发布流程
自 #101 起采用两阶段流程——CI 发布二进制文件,操作者发布数据库。
# 1. Regenerate deadzone.db from the committed scraper config.
just scrape && just consolidate
# 2. Tag + push. CI's release.yml builds tarballs + AppImages, creates the release,
# and auto-bumps the Homebrew tap on release.published.
git tag v0.X.0 && git push --tags
# 3. Ship deadzone.db + deadzone.db.sha256 to the same release.
just dbrelease v0.X.0
# 4. Commit artifacts/manifest.yaml so the release-history trace lands in git.
git add artifacts/manifest.yaml && git commit -m "release v0.X.0" && git push
推送稳定版标签后,CI 会完整执行整个流程:release.yml -> chain-release.yml 分派 scrape-pack.yml -> chain-image.yml 分派 docker-publish.yml(每个工作流各司其职,通过 workflow_run 串联)。
手动执行 Homebrew 回退流程。 tap 会在 release.published 时自动更新(#148)。如果 RELEASE_PUBLISH_TOKEN 过期导致流程中断,请手动运行:
gh workflow run update-package-channels.yml -f tag=v0.X.0
日志
通过 log/slog 将结构化 JSON 写入 stderr。deadzone server 的 stdout 专用于 MCP JSON-RPC。
| 子命令 | 关键事件 |
|---|---|
scrape | scraper.start、scraper.lib_start、scraper.fetch(每个 URL 一条)、scraper.indexed、scraper.lib_done、scraper.done。错误:scraper.fetch_failed、scraper.insert_failed。Agent 路径还会记录 scraper.agent_configured、scraper.agent_ping_ok、scraper.agent_verification_failed、agent.input_truncated。 |
consolidate | consolidate.start、consolidate.done,包含 artifacts、docs_merged、libs_merged、duration_ms。 |
dbrelease | dbrelease.start、packs.dbrelease.uploaded(每个资源文件一条)、dbrelease.done,包含 sha256、size、lib_count、doc_count。 |
server | server.start(包含 embedder 和 doc_count),每次调用记录一条 search_docs(包含 lib_id、tokens、results、latency_ms)。启动时可能会记录 server.db_upgraded、server.db_version_dev_fallback WARN、server.db_tag_sidecar_write_failed WARN。 |
任何子命令都可以使用 --verbose 添加调试级别的详细信息。用于 server 时会记录原始 query(默认关闭,因为查询可能包含用户数据)。用于 scrape 时会添加每篇文档的 scraper.doc_indexed。
MCP 客户端日志路径:macOS 上的 Claude Code 写入 ~/Library/Logs/Claude/mcp-server-deadzone.log;其他客户端的路径各不相同。
路线图与贡献
问题列表:laradji/deadzone/issues。通过 milestones 确定范围。使用 feature / research 标签标注类别;使用 P1 / P2 / P3 标注优先级。
新增或刷新库:前往 New issue 页面,选择对应表单。
为什么要使用向量
因为 "how to register a tool" 应该能找到写有 AddTool 的文档,而如果用户事先不知道答案,任何 FTS5 查询都无法找到它。以嵌入为先进行检索才是重点;其他一切都只是基础设施。
长篇分析:docs/research/context7-analysis.md。
许可证
Apache License, Version 2.0。第三方归属信息见 NOTICE。
有一点需要特别注意。 Apache 2.0 仅涵盖 Deadzone 源代码,不包括其他内容。它不涵盖抓取器索引的第三方文档——这些文档归原作者所有,并受其各自许可证约束。运行 deadzone scrape 须遵守每个来源的服务条款。预构建包受原始内容的许可证约束,而非 Apache 2.0。个人在本地建立索引:没问题。公开再分发:请先做好功课。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。