mcpField
S
scree

scree

本地服务
scree.jrpko.dev搜索与检索01 周前更新

关于 scree

scree 是面向 Claude Code 用户的本地搜索工具,可检索代码仓库和笔记文件夹中的 Markdown。它结合语义与关键词检索,以 SQLite 按文件夹保存索引,并返回带源文件行号的匹配片段。

主要功能

  1. 01按标题将 Markdown 拆分为片段
  2. 02支持语义、关键词和混合搜索
  3. 03每个文件夹单独保存 SQLite 索引
  4. 04在 Claude Code 会话期间保持索引更新
  5. 05返回带行位置的匹配片段
  6. 06应用多层文件忽略规则

适用场景

  1. 01查找相关笔记而不加载整个文件
  2. 02同时搜索精确标识符和相关 Markdown
  3. 03按源文件行号定位文档内容
  4. 04建立索引前排除私人文件

MCP 相关

MCP 服务通过 stdio 向 Claude Code 提供文档搜索。它在本地为 Markdown 建立索引;语义嵌入通过 API 请求,关键词搜索则在本地运行。

配置

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

暂未收录安装方式

我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。

代码仓库
安装包
ocighcr.io/jrapakko/scree:0.4.1
mcpbscree_0.4.1.mcpb

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

scree

通过 MCP 向 Claude Code 提供对仓库和笔记中 Markdown 内容的本地语义搜索。

Scree 按标题拆分 Markdown,通过 API 为各部分生成嵌入向量,并将其存储在磁盘上的 SQLite 文件中,每个文件夹对应一个索引。Claude Code 会检索与问题匹配的少量文本块,而不是加载整个文件。每条结果都会注明其来源行,因此 Claude 只需读取这些内容即可。Markdown 始终是事实来源;索引可随时删除并重建。

设计说明请参阅 docs/SPEC.md。

快速开始

需要 Go 1.26 和一个 OpenRouter API 密钥,获取地址为 https://openrouter.ai/settings/keys。除非某个步骤另有说明,否则命令均在此仓库的根目录下运行。

  1. 构建静态二进制文件(不使用 CGO):

    CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o bin/scree ./cmd/scree
    
  2. 将密钥保存到设置文件中。scree key 会提示你输入密钥,输入时不会回显,因此密钥不会留在 shell 历史记录中,也不会显示在屏幕上;它会以权限模式 600 写入 ~/.config/scree/env,并向 API 发起一次测试调用:

    bin/scree key
    

    它会保留文件中的其他行,并替换之前保存的密钥。scree key < file 则会从文件的第一行读取密钥,并且只有使用 -replace 才会替换已保存的密钥;-offline 会跳过测试调用,-check 则只执行测试调用。在提示处按 Ctrl-C 不会保存任何内容。若要将 Claude Code 的 OpenRouter 费用与自己的搜索费用分开,请使用 bin/scree key -mcp 保存第二个密钥:之后 scree mcp 会使用该密钥,其他命令仍使用第一个密钥(见设置文件)。

  3. 安装二进制文件:

    mkdir -p ~/.local/bin
    install -m 755 bin/scree ~/.local/bin/
    

    Claude Code 必须能在 PATH 中找到 scree。如果 ~/.local/bin 不在其中,请在 shell 配置文件中添加它。

  4. 在为仓库建立索引前检查它。scree run 会加载设置文件并运行 scree 命令。在仓库内运行:

    cd ~/code/myrepo
    scree run doctor -v
    

    doctor -v 会列出所有将被忽略的文件,并估算为其余文件建立索引的费用。如果任何私密内容显示为可建立索引,请在建立索引前添加 .screeignore 或 .gitignore 条目。

  5. **在仓库中启用 scree。**在仓库根目录运行:

    claude mcp add scree --scope project -- scree mcp
    

    这会写入 .mcp.json,内容为 "command": "scree", "args": ["mcp"],不含密钥或路径,因此请将其提交到仓库。Claude Code 会要求每个人批准一次项目服务。此后,该仓库中的每个会话都会保持索引为最新状态;第一个会话会在后台构建索引。若仓库自身的 .mcp.json 未声明 scree mcp,serve 就会拒绝处理该仓库,因此即使 scree 也在其他位置注册,该仓库没有此条目也绝不会建立索引。无论如何,都不要在用户级别注册 scree。

    **批准项目服务意味着信任该仓库。**Claude Code 会在启动服务前应用仓库 .mcp.json 中的 env,包括 PATH,因此你批准的仓库可以决定 scree 实际指向哪个程序,而该程序可以访问你的设置文件。只有在信任仓库的 .mcp.json 时才批准其中的 scree,就像批准任何项目服务一样。若要撤销此选择,请参阅绝对路径。

  6. **可选:在仓库之外使用笔记文件夹。**请参阅笔记文件夹。

构建

需要 Go 1.26。不使用 CGO。带标签的版本还会在 GitHub releases 页面发布 Linux、macOS 和 Windows(amd64 和 arm64)的预编译二进制文件、ghcr.io/jrapakko/scree 镜像,以及一个 Claude Desktop 安装包;scripts/mcpb.sh 会使用该版本的二进制文件将其打包为 zip。

CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o bin/scree ./cmd/scree

配置

设置通过环境变量提供。设置文件是存放这些设置(包括 API 密钥)的唯一位置。不要在 shell 配置文件中 export 密钥。如果未设置 OPENROUTER_API_KEY,直接运行命令(scree search、doctor、reindex、watch)时仍会使用设置文件中的密钥,运行方式与 scree run 相同;详见下文。

变量默认值
SCREE_DB$XDG_DATA_HOME/scree/indexes/<folder>-<hash>/index.db,每个文件夹一个(或使用 -db)
SCREE_MODELopenai/text-embedding-3-small
SCREE_DIMENSIONS512;0 表示使用模型的默认维度
SCREE_EMBED_URLhttps://openrouter.ai/api/v1/embeddings
SCREE_MAX_FILE_BYTES1048576;超过此大小的文件会被跳过
SCREE_FIRST_SYNC_MB50;如果文件夹中的 Markdown 文件超过此大小,Claude Code 会话或 watch 不会启动该文件夹的首次索引(0 = 不限);scree reindex 始终会执行
SCREE_ZDR1;对于 OpenRouter 以外的端点,设为 0
SCREE_HTTP_TOKEN无;使用 serve -allow-remote 时必需,若已设置,也会在回环地址上强制校验
SCREE_PAGER/usr/local/bin、/usr/bin 或 /bin 中的 less -FRX;在终端中显示 scree search 文本视图时使用的分页器,不通过 shell 运行:可以是绝对路径,也可以是这些目录中的名称(绝不通过 PATH 查找),后面可接参数。设为空则不使用分页器
SCREE_COLORSword=1:match=1;33:link=36:lineno=2;文本视图的颜色,使用 SGR 代码(仅限数字和 ;),分别用于词语标题、匹配词语、位置和行号。将某项设为 match= 可关闭其颜色
OPENROUTER_API_KEY无;若未设置,且设置文件中存有密钥(scree key 会将密钥写入该文件),则 search、reindex、doctor 和 watch 的运行方式与 scree run 相同。若没有密钥(未设置或为空),则只为关键词搜索建立笔记索引,auto 搜索会运行 keyword
SCREE_MCP_API_KEY无;仅从设置文件读取(scree key -mcp 会将密钥写入该文件),且仅由 scree mcp 使用;它会将该密钥作为 OPENROUTER_API_KEY 传给 serve,而不是使用文件中的密钥。直接运行的命令和 scree run 均不会使用它

$XDG_DATA_HOME 默认为 ~/.local/share;相对路径会被忽略。如果它未设置,且主目录不是绝对路径,scree 将拒绝打开索引,除非通过 -db 指定索引。

选择文件夹。 使用 -notes <dir> 在命令行中指定文件夹。若未指定,CLI 命令会使用当前目录的 git 根目录;若当前目录不在 git 仓库中,则使用当前目录。在 Claude Code 下,serve 会索引 Claude Code 启动时工作目录的 git 根目录(项目或当前活动的工作树),拒绝使用 -notes、-db 和 SCREE_DB,并要求 CLAUDE_PROJECT_DIR 位于同一个仓库中;.mcp.json 可以设置环境变量,但不能设置工作目录。此外,如果文件夹根目录下的 .mcp.json 未指定 scree mcp 服务,serve 也会拒绝使用该文件夹。在 Claude Code 之外,serve 没有默认文件夹:请传入 -notes。如果自动找到的文件夹是你的主目录(从密码数据库获取,只有查询失败时才回退到 $HOME)、主目录的上级文件夹或文件系统根目录,则会被拒绝;在命令行中传入 -notes 即可强制为其建立索引。即使通过 -notes 指定,serve 也会拒绝此类文件夹(例如 Claude Desktop 这样的客户端会传入用户选择的文件夹),除非指定 -allow-home。检查会比较文件夹本身,而不只是其路径,因此指向主目录的其他路径(如绑定挂载、macOS 上不同的字母大小写、/System/Volumes/Data/Users/…)也会被拒绝。检查只会将所选文件夹与主目录及其上级文件夹进行比较,因此,若某个文件夹内部挂载了主目录(某些容器和开发容器会如此配置),则无法检测到。每个索引都会记录其对应的文件夹,并拒绝用于其他文件夹。

更改模型或维度需要运行 scree reindex -all。索引会记录创建它时使用的模型,并拒绝混用不同模型。

隐私

每次嵌入请求都会要求 OpenRouter 仅路由到数据零留存且 data_collection: deny 的端点。没有此类端点的模型会报出明确错误并指出模型名称,而不会改用会保留数据的端点。设置 SCREE_ZDR=0 可关闭此限制,其他兼容 OpenAI 的端点可能需要这样做。发送到 API 的只有分块文本及其路径和标题;关键词搜索在本地运行。

忽略文件

被忽略的文件不会被读取以进行索引,不会发送到嵌入 API,不会出现在搜索结果中,并且会被 read_doc 和 reindex 拒绝。以下四层规则共同决定忽略哪些文件:

  • 内置规则: 隐藏文件和文件夹,但根目录下的 .claude/(不包括 .claude/worktrees/)、.github/、.gitlab/、.gitea/、.forgejo/、.cursor/、.codex/、.gemini/、.windsurf/、.circleci/ 和 .buildkite/ 除外;扩展名不是 .md、.markdown 或 .mdc 的文件;指向文件夹外部的符号链接;超过 SCREE_MAX_FILE_BYTES 的文件;FIFO 等非普通文件(永远不会打开,且 doctor 会将其报告为不可读);以及名称中包含控制字符的文件。
  • .gitignore: 在 Git 仓库中,Git 忽略的所有内容(包括嵌套的 .gitignore 文件、.git/info/exclude 和全局排除文件)。node_modules/ 等被忽略的文件夹不会被读取,嵌套仓库会被跳过。匹配某条规则的已跟踪文件仍会被忽略。设置 -gitignore=false 可关闭此层规则。
  • .screeignore: 位于已索引文件夹的根目录,使用 gitignore 语法。
  • Front matter: 文件 front matter 中的 scree: ignore。
# .screeignore
journal/
**/private-*.md
/inbox/scratch.md
!journal/public.md

在 .screeignore 中使用 include-hidden .name/ 可索引另一个根级隐藏文件夹;使用 /.cursor/ 之类的规则可取消一条默认规则。! 规则会重新包含被排除文件夹中的文件,但不会重新包含被规则按名称匹配的文件,因此即使在 !archive/2024/ 之下,*.private.md 仍会被忽略;doctor -v 会列出由 ! 规则重新包含的内容。如果无法读取 .screeignore、它是符号链接,或其中有 scree 无法解析的行,则在修复之前不会索引任何内容;doctor 会按行号指出错误行。

---
scree: ignore
---

在依赖某条规则之前,运行 scree doctor -v 查看每一层忽略了哪些内容。完整规则见 docs/SPEC.md。

使用

scree key                # save the API key in the settings file
scree key -mcp           # optional: a separate key for scree mcp (Claude Code)
scree doctor             # check config, index, and the API
scree doctor -v          # also list every ignored file, and check the keyword index
scree reindex            # index new and changed files
scree reindex docs/a.md  # re-index one file
scree reindex -all       # rebuild from scratch
scree search "how do I rotate the backup keys"
scree search -mode keyword PURGE_OLD_RECORDS   # exact words, no API call
scree search -format text "ci seed"              # hits grouped by query word (the default on a terminal)
scree search -no-pager "ci seed"                 # the same, printed without the pager
scree search -format json "…"                    # one JSON object per hit
scree search -format grep "…"                    # path:line:text, for fzf or vim -q
scree watch              # keep the index current (run as a service)
scree serve -notes .     # MCP over stdio, from a terminal
scree serve -notes . -http 127.0.0.1:7077   # MCP over HTTP, loopback only
scree indexes            # list per-folder indexes; -prune deletes ones whose folder is gone

除 indexes 和 key 外,每个命令都接受 -notes <dir>、-db <file> 和 -gitignore=false。在 Claude Code 之外,serve 需要 -notes。如果未设置 OPENROUTER_API_KEY,但设置文件中有密钥,那么在终端运行 search、reindex、doctor 和 watch 的效果与运行 scree run <command> 相同;无论如何,scree run 都会加载该文件,例如 scree run search "…"。

搜索模式

scree search -mode 和 search_docs 工具的 mode 可使用以下模式:

  • auto(默认):使用 semantic,除非查询中含有类似标识符的词、包含字母和 _ 或数字的词(例如 PURGE_OLD_RECORDS、psycopg_pool、R7-Q2 或 v2),或文件夹代码词汇表(见下文)中的词;此时使用 hybrid。ID、API、2026 和 well-known 不计入。
  • hybrid:对分块文本、标题和路径执行向量搜索及 SQLite FTS5 关键词搜索,再通过倒数排名融合合并结果,因此精确名称会排在前面。
  • semantic:仅使用向量。
  • keyword:仅使用 FTS5。此模式不会调用 API,因此没有密钥或 API 停机时也能使用。嵌入调用失败时会说明原因。

没有 API 密钥时,auto 会运行 keyword,并在输出末尾附上 [mode: auto → keyword: no API key; run scree key, or set OPENROUTER_API_KEY];使用 -mode semantic 或 hybrid 则会报错。serve 不会自行读取设置文件;在 Claude Code 下会显示相同提示(scree mcp 会传入文件中的密钥),在其他环境(例如 Claude Desktop)则会提示:add an OpenRouter API key in the extension's settings, set OPENROUTER_API_KEY, or start through scree mcp。在 Windows 上,会去掉其中的 scree key 和 scree mcp 部分。 没有密钥时,索引仍可正常工作:每条笔记都会分块并存储,以供关键词搜索,不会调用 API;reindex 会将这些文件报告为 indexed (N keyword only: no API key)。设置密钥后,下一次同步(scree reindex,或写入器启动时)会且只会为这些文件生成嵌入。在此之前,semantic 和 hybrid 搜索不到它们,并会说明原因([N files indexed for keyword search only; scree reindex embeds them]);scree doctor 会在索引行中统计这些文件。设置密钥后发生的 API 错误或服务中断,不会按无密钥处理:文件仍会像以前一样失败或等待 API 响应。若 API 拒绝密钥(401),则从那以后,该进程只会为关键词搜索建立索引,不会再次请求 API;auto 会运行 keyword,并提示 the embedding API rejected the API key; replace it: <hint>;下一个使用有效密钥的进程会为这些文件生成嵌入。OpenRouter 对被其内容审核标记的输入返回 403,这种情况只会使对应文件失败,与其他 API 错误一样;密钥不会被判定为已遭拒绝。

Scree 会去除 OPENROUTER_API_KEY 首尾的空格和换行符。若值是未填写的 ${...} 占位符,或是 scree key 会拒绝的值(包含内部空白、控制字符或引号),则视为没有密钥,并只记录一行日志,且不会显示该值。

在一组由真实笔记构成的私有数据集上,针对 16 个自然语言查询和 7 个标识符查询进行测试后,auto 将自然语言问题的文件 MRR 保持在 0.89,同时把标识符 MRR 从 0.46 提高到 0.80。始终启用的 hybrid 对标识符的提升同样大,但会损害自然语言问题的效果,因此它不是默认模式。

代码词汇表可以捕获没有 _ 或数字的名称,例如 psycopg 或 PageFetcher。每次同步时,程序都会按照与 Markdown 相同的忽略规则读取依赖项名称,但绝不会进入隐藏文件夹(.claude/ 风格的允许列表仅适用于 Markdown);这些名称来自 requirements*.txt、pyproject.toml、package.json、go.mod 和 Cargo.toml,以及 Python、JavaScript、TypeScript 和 Go 文件导入语句及声明中的混合大小写名称(PageFetcher、useState)。跳过 vendored 文件夹和未更改的文件,每次同步最多打开 20,000 个文件。常见词会被排除,即使它们是包名也不例外:golang.org/x/sync 只会添加完整路径;约 350 个词的停用词表会过滤功能词(how、the)、普通单词形式的包名(sync、requests、next、config),以及以混合大小写书写的普通词(setUp、fileName);漏掉的词仍可能让自然语言问题转到 hybrid。查询中的 PageFetcher's 会按 PageFetcher 计数。在本地索引中只保存转为小写的名称;代码绝不会被分块、生成嵌入或发送给 API。在两个包含代码和文档的代码库上,这一机制略微提升了提及代码的问题的结果,且没有让任何自然语言问题转到 hybrid。

路由只依据词汇表,不论笔记中是否包含该名称:hybrid 的关键词搜索会匹配查询中的每个词,因此即使文档很少提及代码,提及代码的问题也能从中受益。提取器采用基于行的启发式方法,而非解析器,因此可能会把字符串中的文本误读为名称;这种误读最坏只会让问题转到 hybrid,绝不会被打印或生成嵌入。scree doctor 会报告读取到的名称数量,以及笔记中也包含的名称数量(pagefetcher 会匹配 PageFetcher;带点或斜杠的名称,例如 golang.org/x/sync,必须作为短语匹配);-v 只会显示后一类名称的示例;仅在代码中找到的名称绝不会被打印。

查询绝不会作为语法传给 FTS5:每个词都会变成带引号的词项。词项会保留 _ 和 -,因此 psycopg_pool 是一个词项,而单独的 pool 只能通过向量搜索找到它。

结果

在终端中,scree search 会打印按查询词分组的文本视图。每条命中只会列出一次,归在其文本、路径或标题中包含的第一个查询词下,与关键词搜索的匹配方式相同:先显示标题和包含该词的行(最多 10 行,每行截断至 160 个字符),再显示位置,然后显示该范围在当前文件中的所有行,并附上行号(按相同的忽略规则读取,截断至 3,500 字节)。不包含任何查询词的命中(通常仅为语义命中)和过时命中会列在最后;过时命中没有带行号的行。

seed:
  ### 5.1 Files
  - `.forgejo/workflows/ci.yml`: build, test, and the seed from the run number
	>docs/plan.md:189-191
		>>189  ### 5.1 Files
		>>190
		>>191  - `.forgejo/workflows/ci.yml`: build, test, and the seed from the run number

other hits:
  ## Keys
	>docs/keys.md:3-4
		>>3  ## Keys
		>>4  Rotate them yearly.

  # Old notes
	>docs/old.md (stale)
[mode: auto → hybrid]

词语按完整词元匹配,与关键词搜索相同,包括匹配笔记中写出的路径(ci 会匹配 .forgejo/workflows/ci.yml)以及跨行匹配。支持 OSC 8 链接的终端会将每个位置显示为文件链接。查询词在摘录和带行号的行中匹配到的地方都会着色;词语标题、位置和行号也各自有颜色(SCREE_COLORS)。设置 NO_COLOR 或 TERM=dumb 可关闭链接和颜色(scree run search 也会遵循此设置)。使用 -mode keyword 可显示类似 grep、但不含语义命中的视图。

在终端中,文本视图会通过分页器显示,因此会从顶部开始:less -FRX(如果视图能在一屏内显示完毕,就会立即退出;保留颜色和链接,并在退出时让文本留在屏幕上),或使用 SCREE_PAGER。less 566 及更高版本会通过 -R 传递 OSC 8 链接;较旧版本会将其显示为原始转义序列,因此请在这些版本中使用 -no-pager 或 SCREE_PAGER=。使用 -no-pager、设置为空值的 SCREE_PAGER=、管道,或无法启动的分页器时,内容会直接打印。提前退出分页器不算错误。除非设置了 LESSCHARSET,分页器会以 LESSCHARSET=utf-8 运行,因此即使没有 LANG,less 也能显示 → 等字符。scree run search 以及使用设置文件中的密钥直接运行的 scree search,只会从设置文件读取 SCREE_PAGER 和 SCREE_COLORS。只有当 TERM 是 xterm-256color 这类普通终端名称时,它们才会传递你的 TERM;绝不会传递 TERMINFO、TERMINFO_DIRS 或 TERMCAP。如果没有可用的 TERM,就不会使用默认的 less,因为 less 需要它。

通过管道传输或使用 -format xml 时,每条命中都是一个 <hit> 元素:

<hit n="1" path="docs/setup.md" lines="12-19" heading="Setup > Keys" score="0.912" match="both">
chunk text
</hit>
  • lines 是文本块所来自的源文件行范围,因此 Claude 可以准确读取这些行(read_doc(path, start, end))。如果文件在建立索引后发生变化,搜索会在当前文件中查找该文本块(精确匹配或忽略空白变化),并报告当前范围。如果文本已不存在,该命中会带有 stale="true",且没有 lines。已更改的文件会加入重新索引队列。
  • match 表示找到该命中的搜索方式:semantic、keyword 或 both。score 是余弦相似度;仅由关键词搜索命中的结果没有此字段。
  • 如果多个文件中存在相同的文本块(例如已提交的构建副本),搜索只会返回一条命中。显示的副本路径最短;also="docs/print/x.md:12-18, …" 会列出最多另外三个副本,其余副本数量会记录在 also_more="N" 中。列出的副本若其文件发生变化,会像该命中一样重新定位,或显示为 path:stale。使用 .screeignore 排除构建文件夹仍是更好的做法:这样可以节省嵌入成本。
  • 在 auto 模式下,输出末尾会有类似 [mode: auto → hybrid] 的行。

-format json 会逐行打印一个对象,这是脚本和评测使用的稳定格式:{"n","mode","path","start","end","heading","score","match","stale","also","also_more"}。其中 mode 是实际运行的模式;缺失时,start、end 和 score 为 null;also 是由 {"path","start","end"} 组成的列表(文本已不存在的副本会带有 "stale":true);只有存在更多副本时才会出现 also_more。

-format grep 会打印类似 grep -n 的 path:line:text 行:按排名顺序列出每条命中中包含查询词的行,或语义命中的首行;每行只列出一次,并移除控制字符。使用 fzf 选择一条命中并在 vim 中打开,或将所有命中加载到 vim 的 quickfix 列表中:

sg() { scree search -format grep "$*" | fzf --delimiter : \
  --preview 'n={2}; case $n in ""|*[!0-9]*) exit;; esac; sed -n "$(( n>5 ? n-5 : 1 )),+30p" -- {1}' \
  --bind 'enter:become(n={2}; case $n in ""|*[!0-9]*) exit 1;; esac; vim "+$n" -- {1})'; }
vim --cmd 'set efm=%f:%l:%m' -q <(scree search -format grep "ci seed")

路径相对于所在文件夹,因此请从该文件夹的顶层运行这些命令。你没有编写的文件夹可以自行选择文件名和文本,因此应将这些字段视为不可信数据:检查该行是否为数字,并像上面那样在路径前加上 --,而不是将 {1} 或 {2} 粘贴到 Shell 算术表达式或命令行中;同时为 vim -q 指定 %f:%l:%m 错误格式,因为其默认格式也会匹配笔记文本中的 "file" line N:。对于路径中含有 : 或控制字符的匹配项,scree 会将其排除(并在 stderr 中显示数量);对于以 - 或 + 开头的路径,则会在前面加上 ./。

设置文件

scree mcp(用于 Claude Code)、scree run(从终端运行)和 systemd 单元都读取同一个文件 ~/.config/scree/env,因此 API 密钥只需存放一处,且文件权限为 600。scree key(快速开始的第 2 步)会创建该文件或更新其中的密钥。文件中存放密钥和可选设置,不存放文件夹。

直接运行命令而不使用 scree run 时,命令会使用环境变量。如果 OPENROUTER_API_KEY 未设置(或为空、是占位符或无效,如上所述),且此文件中存有密钥,那么 search、reindex、doctor 和 watch 会改为按照 scree run 的方式重新运行:仅使用此文件构建环境,因此密钥只会发送到文件中的 SCREE_EMBED_URL(或默认端点),并通过文件中配置的代理发送(如果有);Shell 中的 SCREE_*、代理、SSL_CERT_FILE 或 GODEBUG 变量均不会生效。此时 doctor 会说明密钥来自此文件。文件缺失或其中没有密钥,均表示没有密钥。若文件未通过下述检查,命令会发出一条指出问题的警告,并在无密钥的情况下运行(auto 搜索会运行 keyword)。

serve 本身从不读取该文件;在 Claude Code 下,scree mcp 已经应用了其中的设置。

文件还可以存放第二个密钥 SCREE_MCP_API_KEY,该密钥由 scree key -mcp 写入(其标志和规则与 scree key 相同;-check -mcp 用于测试该密钥)。随后,scree mcp 和 scree mcp -docker 会将此密钥作为 OPENROUTER_API_KEY 传给 serve,而不是使用文件中的常规密钥。这样,OpenRouter 按密钥统计的用量就能将 Claude Code 与 scree search 及其他命令区分开,后者仍使用 OPENROUTER_API_KEY。SCREE_MCP_API_KEY 不会以其自身名称传递给任何进程。如果该密钥不可用(为空、是占位符、含有内部空白字符或引号),scree mcp 会在 stderr 中说明原因,但绝不会显示密钥值,并会改用 OPENROUTER_API_KEY;doctor 也会对此发出警告,否则会说明 scree mcp 正在使用单独的密钥。和其他设置一样,文件中最后一条 SCREE_MCP_API_KEY 配置会生效。

~ 根据密码数据库确定(即登录用户的主目录),而不是根据 $HOME 或 $XDG_CONFIG_HOME 确定。如果文件缺失、是符号链接、不归你所有,或对组用户或其他用户可读,scree mcp 和 scree run 都会拒绝启动;最后一种情况可通过 chmod 600 修复。对于这类文件,scree key 也会拒绝操作(文件缺失则没问题);如果 ~/.config/scree 文件夹是符号链接、不归你所有或对组用户或其他用户可写,如果 ~/.config 是符号链接,或者密钥会使文件大小超过 64 KB,也会拒绝操作。在 Linux 上,主目录取自 /etc/passwd;如果是 LDAP 或 sssd 登录,则会使用 getent passwd。如果两者都无法识别你的账户,程序会拒绝启动,而不会信任 $HOME。它们不能在 Windows 上运行:请在环境中设置变量,然后直接运行 scree serve -notes … 或其他命令。

每行写一个 NAME=value,并像 scree key 一样用单引号括起值,这样含空格的路径就会作为一个整体值处理。允许使用 export 前缀。文件会作为数据读取,绝不会作为 Shell 脚本运行,因此不会展开值中的任何内容。只接受 scree 自身的变量(SCREE_*、OPENROUTER_API_KEY)、代理变量,以及 DOCKER_HOST 和 DOCKER_CONTEXT(仅传递给 scree mcp -docker 启动的 docker);任何其他变量名都会被视为错误,并指出所在行。Configure 表中的其他变量也可以写入同一文件。值本身不能包含用于包裹它的引号字符。

Claude Code

scree mcp 会加载设置文件并运行 scree serve。Claude Code 只会保存命令,因此密钥不会留在 ~/.claude.json 中。安装 scree(快速入门第 3 步),然后从每个仓库的根目录为其注册:

claude mcp add scree --scope project -- scree mcp

提交生成的 .mcp.json。serve 会为 Claude Code 启动时所在工作目录的 Git 根目录建立索引,检查 CLAUDE_PROJECT_DIR 是否位于同一个仓库中,并检查仓库的 .mcp.json 是否指定了 scree mcp(command 为 scree,或以 /scree 结尾的路径,且第一个参数为 mcp)。在工作树中,建立索引的是该工作树。一个仓库中的多个会话共享同一个索引:一个会话负责写入,其他会话读取;写入者退出后,另一个会话会接手。若仓库大小超过 SCREE_FIRST_SYNC_MB,则在仓库中运行一次 scree run reindex 之前不会建立索引;搜索会对此作出提示。

这些工具是 search_docs(query, k, mode?)、read_doc(path, start?, end?) 和 reindex(path?)。每条搜索结果都包含行范围,因此 Claude 可以只读取这些行;复制文件夹中重复的内容会合并为一条结果(also=)。仍请使用 .screeignore 排除构建输出。

设置文件是 scree mcp 使用的唯一配置。仓库已提交的 .mcp.json 会设置它的启动环境,因此 scree mcp 会忽略该环境:它会拒绝除 -docker 之外的所有参数,从密码数据库中查找设置文件,并用自身二进制替换自身(exec),在仅包含 HOME(你的 passwd 主目录)、PATH=/usr/local/bin:/usr/bin:/bin、CLAUDE_PROJECT_DIR 以及文件中设置项的环境中运行 scree serve。其他任何内容都不会传入:包括继承的 SCREE_*、密钥或代理变量、XDG_DATA_HOME、XDG_CONFIG_HOME、DOCKER_HOST,以及 Go 运行时的 GODEBUG 和 GOMAXPROCS。scree 是不带 shell 的静态二进制,因此 LD_PRELOAD、bash 的 SHELLOPTS 和 PS4,以及导出的 BASH_FUNC_* 函数(这些内容可能会在旧的 shell 包装脚本执行第一行之前产生作用)对它都不起作用。真正的 scree 启动后,仓库环境无法将你的密钥发送到其他端点、替换设置文件、移动索引或让 scree 指向其他文件夹。不过,仓库环境仍可通过 PATH 决定最初以 scree 名义运行哪个程序;请参阅快速入门中的信任说明。(在 macOS 上,Go 二进制会动态链接系统库,因此 DYLD_* 变量仍可影响第一个进程;请参阅 docs/SPEC.md 中尚待解决的事项。)

使用普通的 scree 或绝对路径

已提交的 .mcp.json 指定普通的 scree,因此无论安装目录是什么,每个人都能使用;二进制由每个人自己的 PATH(或仓库的 env)查找。在只有你自己使用的配置中,改为注册绝对路径,这样就不会由 PATH 决定哪个程序能获取你的设置。此项目在 ~/.claude.json 中保存的本地作用域条目,会优先于项目中同名的条目,包括 env:

claude mcp add scree --scope local -- "$HOME/.local/bin/scree" mcp

运行命令时,shell 会展开 $HOME,因此保存的命令是绝对路径,例如 /home/you/.local/bin/scree。仓库已提交的 .mcp.json 仍必须指定 scree mcp;这是仓库选择启用该功能的方式。

建议通过 scree mcp 使用 Stdio。serve -http 仅监听回环地址。非回环地址需要 -allow-remote 和至少 16 个字符的 SCREE_HTTP_TOKEN,之后每个请求都必须发送 Authorization: Bearer <token>。请将令牌保存在设置文件中,而不要放在命令行上:

printf 'SCREE_HTTP_TOKEN=%s\n' "$(openssl rand -hex 32)" >> ~/.config/scree/env
scree run serve -notes ~/notes -http 0.0.0.0:7077 -allow-remote

请在终端中运行此命令,不要在 Claude Code 会话中运行;会话中会设置 CLAUDE_PROJECT_DIR,而 serve 会拒绝 -notes。

客户端随后需要该请求头。如果通过 claude mcp add --transport http ... --header "Authorization: Bearer $SCREE_HTTP_TOKEN" 添加请求头,shell 展开变量可以避免令牌进入 shell 历史记录,但 Claude Code 仍会将展开后的请求头保存在 ~/.claude.json 中。

一个笔记文件夹

在命令行中使用仓库之外的文件夹,例如 ~/notes:

scree run reindex -notes ~/notes
scree run search -notes ~/notes "backup password"

systemd unit 会运行 scree run watch -notes ~/notes 使其保持最新。要在 Claude Code 中搜索该文件夹,请在 ~/notes 中运行 claude mcp add scree --scope project -- scree mcp,然后在那里启动 Claude Code;它不是一个 git 仓库,因此该文件夹本身就是 ~/notes。在其他位置运行的 Claude Code 会话无法访问它,因为在 Claude Code 中,serve 只会索引会话所在的文件夹。

Claude Desktop(一键安装包)

未经测试。 该安装包尚未在任何平台上的任何 MCP 客户端中测试过:既未在 Claude Desktop 中测试,也完全未在 macOS 或 Windows 上测试过。它并非面向 Linux。仅在 Linux 上使用 Linux 构建版本测试了它所运行的服务命令。请预期会有一些问题,并欢迎反馈发现的情况。

0.3.6 之后的版本包含 scree_<version>.mcpb,这是适用于 macOS 和 Windows 上 Claude Desktop 的 MCPB 安装包。它包含 macOS 通用二进制文件和 Windows amd64 二进制文件(Windows ARM 会通过模拟运行)。在 Claude Desktop 中打开该文件即可安装,并会要求设置两项内容:

  • 笔记文件夹(必填):scree 用于索引和搜索的文件夹。选择该文件夹即表示选择加入,因此 .mcp.json 检查不适用。请选择笔记文件夹或仓库:服务会拒绝你的主目录、位于主目录上层的文件夹或驱动器根目录,并且不会启动。
  • OpenRouter API key(可选):没有该密钥时,scree 只会按关键词索引和搜索。提供密钥后,也可以按含义搜索,笔记和每条查询都会发送到 OpenRouter 进行嵌入。粘贴在密钥周围的空格或换行符会被去除。如果 OpenRouter 拒绝该密钥,scree 仍会仅按关键词运行,搜索结果也会说明密钥已被拒绝。

随后,Claude Desktop 会从安装包中运行 server/scree serve -notes <folder>,并将 OPENROUTER_API_KEY 设为该密钥或空值。安装包不会读取设置文件,因此其中的 SCREE_MODEL、SCREE_DIMENSIONS 和 SCREE_EMBED_URL 不适用。已使用其他模型建立索引的文件夹会被拒绝。包含超过 50 MB Markdown 的文件夹不会自动建立索引;搜索结果会说明这一点,并告知 Claude 在运行不带路径的 reindex 工具(该工具仍会为其建立索引)之前先询问你。索引存放在 CLI 指定的位置,因此 CLI 可以搜索同一文件夹;请让两者保持相同版本,因为其中一个可能会将索引升级到另一个无法读取的版本。

这些二进制文件未签名或公证。在 macOS 上,Gatekeeper 可能会拒绝运行已下载安装包中的 server/scree,直到你在“系统设置”→“隐私与安全性”中允许它;未签名的二进制文件也会带来 docs/SPEC.md 中所述的 DYLD_* 注意事项。Windows SmartScreen 也可能发出类似警告。每个版本还包含 scree_<version>.mcpb.sha256(sha256sum 格式;使用 sha256sum -c 检查,或在 macOS 上使用 shasum -a 256 -c),注册表条目 io.github.jrapakko/scree 也记录了相同的 sha256。客户端是否会在安装时检查该值尚未测试。

后台服务(systemd)
# needs ~/.config/scree/env from "Settings file" above
mkdir -p ~/.local/bin ~/.config/systemd/user
cp bin/scree ~/.local/bin/
cp contrib/scree-watch.service ~/.config/systemd/user/
systemctl --user daemon-reload && systemctl --user enable --now scree-watch
journalctl --user -u scree-watch -f

该单元会运行 scree run watch -notes ~/notes,因此它会像 scree mcp 一样读取设置文件(而不是通过 systemd 的 EnvironmentFile)。如需使用其他文件夹,请编辑 ExecStart 中的 -notes。如果该文件夹中的 Claude Code 会话已持有写入锁,它会等待该锁释放。

Docker 或 Podman

该镜像约为 18 MB。它只包含静态二进制文件,并以非特权用户身份运行。文件夹以只读方式挂载,索引存放在 /data 卷中。在 Linux 上,文件变更事件会通过绑定挂载传递到容器中。在 macOS 上,Docker Desktop 不会传递这些事件,因此 watch 无法检测到其中的编辑。日常使用请改用原生二进制文件或 systemd 单元。 SELinux 主机(Fedora、RHEL、CentOS Stream)需要在每个绑定挂载上添加 :z。否则,容器无法读取挂载的文件夹,scree 会报错 open /notes: permission denied。以下示例均包含 :z,而 scree mcp -docker 需要在设置文件中配置 SCREE_MOUNT_OPTS=ro,z。:z 会永久重新标记主机上文件夹中的每个文件(标记为 container_file_t),即使挂载为只读也是如此。请挂载笔记文件夹或代码库,切勿挂载主目录。在未启用 SELinux 的系统上,请移除 :z。如果不想重新标记任何内容,请改用原生二进制文件。

docker build -t scree .            # or: podman build -t scree .

使用 docker run:

# background indexer
docker run -d --name scree-watch --restart unless-stopped \
  -e OPENROUTER_API_KEY \
  -v "$HOME/notes:/notes:ro,z" -v scree-data:/data \
  scree watch -notes /notes

# one-off commands against the same index
docker run --rm -e OPENROUTER_API_KEY -v "$HOME/notes:/notes:ro,z" -v scree-data:/data scree doctor -notes /notes
docker run --rm -e OPENROUTER_API_KEY -v "$HOME/notes:/notes:ro,z" -v scree-data:/data scree search -notes /notes "backup password"

不带值的 -e OPENROUTER_API_KEY 会从 shell 传递该变量,因此密钥不会出现在命令行中。

使用 compose 时,它会从 shell 或 compose.yaml 所在目录中的 .env 读取 OPENROUTER_API_KEY:

SCREE_NOTES_DIR=$HOME/notes docker compose up -d     # starts watch
docker compose logs -f watch

SCREE_NOTES_DIR 只是 compose 为挂载到 /notes 的主机文件夹指定的名称。compose.yaml 也会传递 SCREE_MODEL、SCREE_DIMENSIONS、SCREE_MAX_FILE_BYTES、SCREE_FIRST_SYNC_MB、SCREE_ZDR 和 SCREE_EMBED_URL,并将 SCREE_HTTP_TOKEN 传递给 serve。serve 服务位于 mcp 配置文件之后,因此 up 不会启动它。

对于 Claude Code,MCP 服务可以通过 stdio 为每个会话运行一个容器。scree mcp -docker 会加载设置文件并运行 docker run -i --rm --pull=never(不会从镜像仓库拉取缺失的镜像,因为容器会获取密钥),将项目文件夹以只读方式挂载到其自身路径(因此每个代码库都会在 scree-data 卷中拥有自己的索引),并挂载 scree-data 卷;同时只会按名称传递已设置的选项(-e NAME),因此密钥不会出现在命令行中。它会按照与 serve 相同的规则挂载其工作目录的 git 根目录(仅限通过你拥有且不是符号链接的 .git,并且绝不位于粘滞文件夹中或其上级目录中,例如 /tmp),因此 .gitignore 会生效;如果 CLAUDE_PROJECT_DIR 位于另一个工作树中,它会拒绝启动。serve 会在挂载的文件夹中运行(-w),并应用相同的文件夹规则和 .mcp.json 选择加入检查。你的全局 git 排除文件在容器内不可见,而 git 目录位于挂载文件夹之外的工作树也无法在容器内读取。

代码库中提交的 .mcp.json 指定了 scree mcp,供所有人共用。若要自行使用 Docker,请添加一个本地作用域条目;对你而言,它的优先级高于项目配置:

claude mcp add scree --scope local -- "$HOME/.local/bin/scree" mcp -docker

docker CLI 会获得 HOME 环境变量、值为 /usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin 的 PATH、设置文件中的配置,以及设置文件中指定的 DOCKER_HOST 或 DOCKER_CONTEXT;Claude Code 或代码库环境中的其他内容均不会传递。因此,如果你的引擎需要这两个变量,请在设置文件中设置它们。设置文件中的 SCREE_DOCKER(仅支持 docker 或 podman,且只会在上述目录中查找,不会通过 PATH 查找)、SCREE_IMAGE(默认为 scree:latest;自行拉取的完整限定名 ghcr.io/jrapakko/scree:<version> 也可使用)和 SCREE_DATA_VOLUME(卷名称,而非路径)可以更改引擎、镜像和卷。SCREE_MOUNT_OPTS(默认为 ro)用于设置挂载选项,只接受 ro、ro,z 或 ro,Z;在 SELinux 主机上,请按上文说明设置为 ro,z。它绝不会挂载你的主目录(根据密码数据库确定)、其上级文件夹或 /,并且会拒绝包含 : 的路径。与 scree mcp 一样,它会忽略继承的设置,且不接受其他参数。

在容器内,serve -http 必须绑定非环回地址,才能通过已发布的端口访问,因此需要 -allow-remote 和 SCREE_HTTP_TOKEN。请仅将端口发布到主机的环回地址,例如 -p 127.0.0.1:7077:7077。

watch 和 serve 容器共用 scree-data 卷。与原生进程一样,SQLite 的 WAL 模式允许 serve 在 watch 写入时进行读取。

工作原理

  • 每个文件夹在 $XDG_DATA_HOME/scree/indexes/ 下都有自己的索引。持有索引锁文件的 scree serve(每个 Claude Code 会话运行一个)或 scree watch 是该索引的唯一写入者:它会在启动时按内容哈希同步,然后使用 fsnotify 监视文件;某个路径最后一次发生事件后等待 1.5 s,并且只重新嵌入哈希发生变化的文件。同一索引上的其他进程只读,并每 5 s 重试一次获取锁,因此写入者退出后,其他进程会接管。
  • 首次同步在后台运行,因此 Claude Code 可以立即连接;同步完成前,搜索结果会提示索引尚未完成。SQLite 的 WAL 模式允许读取者在写入者写入时进行搜索。
  • 搜索结果是 <hit> 元素,包含路径、行范围、标题和匹配类型。分块最多 3500 个字符,单条命中的文本最多 4000 个字符,每条响应最多 64 KB。如果查询中包含标识符,搜索会将向量与 SQLite FTS5 关键字索引结合,因此完全匹配的名称会优先显示。read_doc 会在 <doc> 元素中返回文件或指定行范围,最多 256 KB。服务会告知客户端将这两者都视为数据,而非指令。
  • 返回每条命中结果前,都会根据当前忽略规则重新检查;因此,新近被忽略或已删除的文件会立即从结果中移除。
  • 搜索等待 API 的时间最多为 10 s(尝试 2 次)。索引处理每次尝试最多等待 30 s(尝试 3 次)。API 中断后,索引处理会暂停 30 s,之后逐步延长暂停时间,最长为 5 min,然后重新同步;这样,中断期间发生更改的文件无需再次编辑也能被纳入索引。
  • 关闭时,serve 和 watch 等待写入者的时间最多为 5 s;再次按下 Ctrl-C 或发送 SIGTERM 会立即退出。
  • 如果索引文件或文件夹消失或被替换,scree watch 会报错退出,以便 systemd 或 Docker 重启它。在 serve 中,写入者会停止,搜索会报告此情况。文件夹重命名或忽略文件发生变化时,会重新添加监视。索引目录以 0700 权限创建,其文件权限为 0600。
  • 向量存储在 vec1 中,这是 SQLite 的向量扩展,使用平面(精确)余弦索引;关键字存储在 SQLite 的 FTS5 中。两者都由 ncruces/go-sqlite3 编译为 WebAssembly,因此二进制文件无需 CGO。
  • scree 只信任由你拥有且不是符号链接的 .git,绝不会在粘滞目录(如 /tmp)中或其上级目录查找 .git;绝不跟随 git 忽略文件(.gitignore、.git/info/exclude、.git 文件)或 .screeignore 的符号链接;绝不读取仓库的 .git/config,也绝不打印这些文件的内容:消息只会指出文件名和行号。由他人拥有的 .git 会导致错误;若仍要索引其下的文件夹,请传入 -notes <folder> -gitignore=false。
  • 索引文件、其 -wal 和 -shm 文件以及 writer.lock 绝不会通过符号链接打开;如果索引文件夹或其上级的 scree/indexes 文件夹是符号链接,则会拒绝使用。
  • 由同一套策略决定允许读取哪些内容;索引处理、搜索、read_doc 和 reindex 都会通过这套策略。只有位于索引文件夹内的符号链接才会被跟随,并且也会对其目标进行规则检查。不会递归进入符号链接所指向的文件夹。

对于较小的索引,每个进程的空闲内存约为 13–15 MB;索引包含 1000 个文件(4000 个分块)时,约为 20 MB。使用默认模型时,每 MB Markdown 的索引成本约为 $0.0025;doctor 的估算值是上限。

从 scree-mcp 包装脚本迁移

scree-mcp、scree-run 和 scree-mcp-docker 这些 shell 包装脚本已移除;scree mcp、scree run 和 scree mcp -docker 会在二进制文件内部执行相应功能。设置文件保持不变,但不能是符号链接,现在还可以包含 DOCKER_HOST 和 DOCKER_CONTEXT。

  1. 在每个仓库中,重新注册并提交新的 .mcp.json:

    claude mcp remove scree --scope project
    claude mcp add scree --scope project -- scree mcp
    

    serve 仍接受旧条目(其中指定了 scree-mcp),但只有在存在 scree-mcp 程序时该条目才有效,而现在已不再安装此程序。

  2. 删除旧包装脚本:rm -f ~/.local/bin/scree-mcp ~/.local/bin/scree-run。如果你曾将 scree-mcp-docker 安装为 scree-mcp,也请将其删除,并添加本地 Docker 条目。

  3. 在原先使用 scree-run <command> 的地方改用 scree run <command>。

  4. 更新 systemd 单元;现在它会运行 scree run watch,而不是通过 EnvironmentFile 读取文件:cp contrib/scree-watch.service ~/.config/systemd/user/ && systemctl --user daemon-reload && systemctl --user restart scree-watch。

从单文件夹版本迁移

单文件夹版本会读取 SCREE_NOTES,并将一个索引保存在 ~/.local/share/scree/index.db。现在每个文件夹都有自己的索引,文件夹路径取自仓库或 -notes。

  1. 从 ~/.config/scree/env 中删除 SCREE_NOTES= 这一行。该设置会被忽略,而且只要它还存在,doctor 就会发出警告。
  2. 删除用户级别的注册:claude mcp remove scree --scope user。该注册会在你打开的每个项目中启动 scree;随后,serve 会拒绝所有 .mcp.json 未指定 scree mcp 的项目。请改为在每个仓库中注册 scree(参见快速入门第 5 步),并通过命令行指定笔记文件夹。
  3. 使用 scree run reindex -notes ~/notes 在新位置重建笔记索引,然后删除 ~/.local/share/scree/index.db。或者,使用 -db ~/.local/share/scree/index.db 保留该索引,并将其用于该文件夹。scree indexes 会指出旧文件的位置。
  4. 更新 systemd 单元:cp contrib/scree-watch.service ~/.config/systemd/user/ && systemctl --user daemon-reload && systemctl --user restart scree-watch。
  5. Docker:镜像不再设置 SCREE_NOTES 或 SCREE_DB;请传入 -notes /notes。scree-data 卷中的旧文件 /data/index.db 已不再使用;请重新建立索引。

打开早期的逐文件夹版本所建的索引时,系统会就地升级:下次同步时会填充行范围,而不会对未更改的文件重新生成嵌入;重复哈希和关键词索引则会根据已存储的分块构建。对于使用当前分块大小限制之前的版本所建的索引,需要运行一次 scree reindex -all。

许可证

MIT;详见 LICENSE。发布压缩包和容器镜像中包含捆绑依赖项的许可证(THIRD_PARTY_LICENSES/;镜像中位于 /usr/share/doc/scree)。

评论

支持 Markdown

第一次接触 MCP?

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

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