内容
<div align="center">
# 🍬 水果豆
**一款MCP服务器,让编码代理无需阅读代码库即可理解代码库。**
存储库映射、符号轮廓、排名搜索、导入跟踪、更改审查和解析诊断 - 每个结果都在代币预算下,实际上它遵守预算。
[](https://github.com/rayhankhilji/jellybean/actions/workflows/ci.yml)
[](https://nodejs.org)
[](LICENSE)
[](https://modelcontextprotocol.io)
<img src="docs/map.svg" alt="jb_map showing a repository tree in 106 tokens" width="700">
</div>
---
## 问题
大多数MCP服务器只是`readFile`和`grep`的薄包装。这使得它们很容易编写,但使用起来很昂贵。一个要求添加字段到服务的代理通常会消耗大量资源:
```
grep -rn "UserService" → 240 matching lines, most of them imports
read src/user/service.ts → 4,100 tokens, of which ~30 were relevant
read src/user/types.ts → 1,800 tokens, to learn one interface
npm test → 3,900 lines of log for four real failures
```
大约14,000个代币来学习四个事实。上下文窗口充满了模型永远不会再次引用的材料,有用的信号被埋在其中。
Jelly Bean直接解决这个问题。相同的任务,相同的存储库:
```
jb_map {focus:"user service"} → ~150 tokens, the five files that matter
jb_outline {path:"src/user/service.ts"} → ~290 tokens, every declaration, no bodies
jb_read {handle:"jb_7c1e9a04"} → ~180 tokens, the one method
jb_diagnose {check:"test"} → ~220 tokens, four failures with source
```
不到900个代币,代理人对所需信息的了解比以往更加准确——因为它也知道那些文件里还有什么以及依赖于它们的模块。
## 三个理念
这里的一切都源于三个决定。
**1. 使用句柄代替转储。** 每个结果都是紧凑的行,携带一个像`jb_7c1e9a04`这样的标识符,地址是一个确切的文件区域。代理人只为他们选择跟随的句柄花费代币。句柄源自内容,因此同一个区域总是产生相同的句柄——代理人可以不扩展就知道搜索结果和轮廓条目是同一个函数。
**2. 预算是一种合同,而不是提示。** 每个工具都采用`tokenBudget`并在其中拟合,降级细节而不是截断行。页脚始终报告省略的内容并命名一个调用来揭示它,因此截断的结果是一个标志,而不是死胡同。
**3. 结构优于文本。** Jelly Bean进行解析。它知道一个文件包含一个有九个方法的类,哪些方法是导出的,哪些文件导入它,以及哪些是测试。关于形状的问题从索引中回答,而不是通过将源代码发送到模型并希望如此。
## 测量
在M系列Mac上针对三个真实存储库进行基准测试。使用`node scripts/benchmark.mjs --markdown <repo>`重现——测试框架从它指向的存储库中选择自己的主题文件,因此数字不是精心挑选的。
#### 延迟
冷启动是指存储库的第一个索引。Warm是重启并带有解析缓存,这几乎总是会话的样子。工具延迟是稳态的,带有文件系统监视器运行。
| 存储库 | 文件 | 冷索引 | 暖启动 | `jb_map` | `jb_outline` | `jb_search` | `jb_trace` |
|---|---|---|---|---|---|---|---|
| expressjs/express | 213 | 965ms | 100ms | 21ms | 2ms | 42ms | 4ms |
| nestjs/nest | 2,124 | 5.3s | 997ms | 22ms | 1ms | 21ms | 3ms |
| microsoft/vscode | 16,000 | 97s | 13.4s | 116ms | 1ms | 24ms | 4ms |
#### 代币成本
基线是没有这些工具的代理实际支付的费用:读取文件进行定位,以及`grep`然后读取匹配的文件来查找概念。两者都是经过测量,而不是假设的。
| 存储库 | 问题 | 基线 | Jelly Bean | 节省 |
|---|---|---|---|---|
| express | 在存储库中定位 | 236,235 — 读取所有213个文件 | 749 — `jb_map`树 | **99.7%** |
| | 排名重要性 | 236,235 | 1,864 — `jb_map`文件 | **99%** |
| | `lib/utils.js`中有什么? | 1,776 — 读取它 | 222 — `jb_outline` | **88%** |
| | 在哪里有`contentType`? | 110,340 — `grep` → 读取20个文件 | 1,992 — `jb_search` | **98%** |
| nest | 在存储库中定位 | 1,281,435 — 读取所有2,124个文件 | 1,875 — `jb_map`树 | **99.9%** |
| | `core/injector/container.ts`中有什么? | 3,350 — 读取它 | 1,213 — `jb_outline` | **64%** |
| | 在哪里有`ModuleMetatype`? | 56,224 — `grep` → 读取20个文件 | 1,680 — `jb_search` | **97%** |
| vscode | 在存储库中定位 | 66,199,497 — 读取所有16,000个文件 | 1,880 — `jb_map`树 | **99.9%** |
| | `base/common/lifecycle.ts`中有什么? | 8,411 — 读取它 | 1,899 — `jb_outline` | **77%** |
| | 在哪里有`TRACK_DISPOSABLES`? | 110,271 — `grep` → 读取20个文件 | 1,881 — `jb_search` | **98%** |
定位行的外观几乎过于美好,因此有必要准确说明其含义:没有人会阅读6600万个代币,因为没有人能做到这一点。没有地图,代理人会读取一些任意的子集并希望它选择了正确的一个;比较是针对了解整个形状的,这是以前无论如何都买不到的。
#### 诚实的限制
* **vscode处于边缘。** 16,000个文件需要97秒的冷索引和~580MB的堆栈。Warm启动是13秒。之后的所有操作都很快,但这种规模的monorepo不是该设计的最佳路径。
* **估计器是我们自己的。** 代币计数来自Jelly Bean自己的估计器(`src/core/tokens.ts`),它故意略微高估。实际数字将与真正的BPE分词器有几个百分点的差异;比率不会。
* **搜索延迟取决于查询。** 搜索词出现在数千个文件中的次数比搜索罕见词要高,因为要读取更多的候选文件。
## 安装
需要Node 18.17或更新版本。没有原生模块,没有安装时的构建步骤,两个运行时依赖项(MCP SDK和Zod)。
### Claude Code
```bash
claude mcp add jellybean -- npx -y github:rayhankhilji/jellybean /absolute/path/to/your/repo
```
### Claude Desktop, Cursor, Windsurf, Zed
将以下内容添加到MCP配置文件:
```json
{
"mcpServers": {
"jellybean": {
"command": "npx",
"args": ["-y", "github:rayhankhilji/jellybean", "/absolute/path/to/your/repo"]
}
}
}
```
### 从源代码
```bash
git clone https://github.com/rayhankhilji/jellybean.git
cd jellybean
npm install && npm run build
node dist/index.js /path/to/your/repo
```
尚未在npm注册表中,因此上述命令直接从此存储库安装——`npx`通过`prepare`脚本自行构建。
## 在安装前查看
MCP服务器很难评估:通常,评估它的唯一方法是将其连接到代理人并希望代理人选择调用它。因此,有一个引导式教程,通过每个工具驱动到一个真实的存储库并打印出模型实际接收的内容:
```bash
git clone https://github.com/rayhankhilji/jellybean.git
cd jellybean && npm install
npm run demo
```
指向您自己的代码,并可选地运行一个项目的检查:
```bash
node scripts/demo.mjs /path/to/your/repo
node scripts/demo.mjs /path/to/your/repo --check test
```
游览结束时,将其打印的内容与完全读取存储库的成本进行比较。
## 九种工具
### `jb_map` — 定位
按结构重要性排名的文件:哪些文件导入,加权依赖于被依赖,因为这些文件值得首先查看。传递`focus`按主题排名。
```
jb_map {depth:"tree"}
jb_map — jellybean-mcp 43 files 8.1k lines typescript×34 json×3 text×2 markdown×2 yaml×1
./ 7 files 678L json×3 text×2 markdown×2
.github/
workflows/ 1 file 46L yaml×1
scripts/ 1 file 44L javascript×1
src/ 3 files 494L typescript×3
core/ 8 files 1.4kL typescript×8
diagnostics/ 2 files 700L typescript×2
lang/ 6 files 1.5kL typescript×6
tools/ 8 files 1.7kL typescript×8
util/ 1 file 78L typescript×1
test/ 6 files 1.4kL typescript×6
[140/2000 tok]
next: jb_map {path:"<dir>", depth:"symbols"} to see what a directory contains
```
`depth:"files"`每行一个文件,带有句柄和依赖计数;`depth:"symbols"`添加每个文件的顶级声明。
### `jb_outline` — 结构而非主体
提供最大的节省。签名、种类、行范围、可见性——以及每个的句柄,以便可以选择阅读两个相关的符号,而无需支付其他40个符号的费用。
```
jb_outline {path:"src/core/handles.ts"}
jb_outline — src/core/handles.ts 1 file 16 symbols
src/core/handles.ts 83L typescript 16 symbols
export interface HandleTarget jb_6dcfec6b :16-27
path: string :18
startLine: number :20
endLine: number :22
kind: string :24
label: string :26
const ID_PREFIX = 'jb_' jb_37efc771 :29 private
const ID_PATTERN = /^jb_[0-9a-f]{8}$/ jb_4ccdce46 :30 private
export class HandleStore jb_fa7adbb4 :40-72
private readonly entries = new Map<string, HandleTarget>() :41 private
constructor(private readonly capacity = 4096) {} jb_3bdc2fcf :43
mint(target: HandleTarget): string jb_38a494b4 :46-58
get(id: string): HandleTarget | undefined jb_2ad5be16 :61-67
get size(): number jb_4f944248 :69-71
export function handleId(target: HandleTarget): string jb_bf57b96c :75-78
export function isHandle(value: string): boolean jb_8706f6fb :81-83
[269/700 tok]
```
<img src="docs/outline.svg" alt="jb_outline listing every declaration in a file with no bodies" width="680">
也适用于目录,在这种情况下,它默认为仅导出符号。
### `jb_search` — 排名行,而不是文件列表
BM25反向索引对*文件*进行排名;只读取排名靠前的文件,并提取它们最佳匹配的行,并带有包含每个符号的符号。成本不随着搜索词的普遍程度而扩展。
自然单词有效:标识符作为整体和拆分索引,因此`retry backoff`找到`retryWithBackoff`、`RETRY_BACKOFF_MS`和`retry_with_backoff`.
```
jb_search {query:"least recently used eviction"}
jb_search — "least recently used eviction" auto
src/core/handles.ts 3 hits typescript
→ :37 jb_853fa374
* least-recently-used, and because IDs are content-derived, an evicted handle
→ HandleStore jb_fa7adbb4 :60
/** Look up a handle, marking it as recently used. */
src/core/tokens.ts 8 hits typescript
→ push jb_b7a4164c :110
if (this.used + cost > this.budget - this.reserved) {
… 2 more in this file
```
<img src="docs/search.svg" alt="jb_search returning matched lines with their enclosing symbols" width="700">
`mode:"symbol"`仅匹配声明名称,并且不触摸任何文件。`mode:"regex"`采用精确模式。
### `jb_read` — 你确切需要的内容
按句柄、按符号名称或按行范围。
```
jb_read {path:"src/core/handles.ts", symbol:"HandleStore.mint"}
jb_read — src/core/handles.ts:46-58 mint (method) typescript of 87 lines
46| mint(target: HandleTarget): string {
47| const id = handleId(target);
48| // Re-inserting moves the key to the end of the Map's iteration order, which
49| // is what makes plain Map deletion order equal to LRU order.
50| this.entries.delete(id);
51| this.entries.set(id, target);
52|
53| if (this.entries.size > this.capacity) {
54| const oldest = this.entries.keys().next();
55| if (!oldest.done) this.entries.delete(oldest.value);
56| }
57| return id;
58| }
```
当您真正需要整个文件时,`mode:"skeleton"`保留每个声明并省略函数体:
```
71| export async function runSearch(args: SearchArgs, ctx: ToolContext): Promise<string> | … 84 lines
156| }
157|
165|
[j269/700 tok]
```
### `jb_define` — 在哪里定义
与名称搜索不同,后者会排名。阅读存储库中的`store.load()`时,代理人无法仅凭排名列表确定它是哪个存储库;给定`from`,此方法会跟随该文件自己的导入语句 — 跨 barrel 重新导出 — 并精确回答。
```
jb_define {symbol:"BudgetWriter", from:"src/tools/map.ts"}
jb_define — BudgetWriter imported from ../core/tokens.js
→ src/core/tokens.ts:64 class jb_5974455a
export class BudgetWriter
— Accumulates lines while enforcing a token ceiling.
12 files import src/core/tokens.ts
```
<img src="docs/define.svg" alt="jb_define resolving a symbol through the importing file" width="700">
当解析确实不明确时,它会说明并列出候选项,而不是选择一个并让代理基于错误答案进行构建。添加`body:true`以获取源代码。
### `jb_trace` — 如果我更改了这个,会发生什么
在任一方向上遍历导入图。对于符号,它还会找到实际的引用站点 — 一个文件可以导入一个模块,但永远不会触摸符号 — 并将依赖项标记为测试、示例或入口点,因为它们对更改者提出了不同的要求。
```
jb_trace {symbol:"estimateTokens"}
jb_trace — estimateTokens in src/core/tokens.ts dependents depth 1
⇒ depended on by
test/core.test.ts 6 references test
→ :12 jb_be12ae5d
→ :13 jb_7d224441
… 2 more
test/tools.test.ts 4 references test
→ :168 jb_554f50fd
```
<img src="docs/trace.svg" alt="jb_trace listing the files that depend on a module" width="470">
笔记锚定到跟踪的文件表面。
### `jb_diagnose` — 问题,而不是日志
运行一个项目的检查并返回去重问题的文件、行、代码和周围源代码。重叠的摘录被合并,冒犯的行被标记,因此三个类型错误在一个函数中花费一个摘录。
```
jb_diagnose {check:"typecheck"}
jb_diagnose — npm run --silent typecheck exit 2 9.7s 3 problems
src/app.ts 7L 3 problems
! Argument of type 'string' is not assignable to parameter of type 'number'. TS2345 :4:21 jb_a543cb8c
! Expected 2 arguments, but got 1. TS2554 :5:18 jb_a543cb8c
! Cannot find name 'missingHelper'. TS2304 :6:10 jb_a543cb8c
2|
7| export function run(): number {
>4| const total = add("one", 2);
>5| const scaled = scale(total);
>6| return missingHelper(scaled);
7| }
[154/2000 tok]
```
调用它时不带参数来列出项目提供的内容。输出被`tsc`、`ESLint`、`Vitest`、`Jest`、`cargo`、`go`、`pytest`、Python跟踪信息、Maven以及`gcc`、`clang`、`ruff`、`flake8`和`shellcheck`共享的`path:line:col: severity: message`惯例所理解。如果无法识别,输出会退回到通用扫描,如果仍然失败,则输出尾部 — 因为“没有问题”是一个危险的答案,当命令明显失败时。
**它从不调用shell。** 参见 [安全](#security)。
### `jb_changes` — 我做了什么,可能会破坏什么
拉取请求前的问题。差异告诉你你输入了什么;这告诉你你*影响了什么*。更改的行范围映射到包含它们的符号,导入图提供每个更改文件的内容。
```
jb_changes {}
jb_changes — uncommitted 3 files +16/-2
src/server.ts modified +16/-2 typescript
· INSTRUCTIONS constant jb_ea9ca408 :32
· registerTools function jb_37a42bce :80
src/core/git.ts untracked +155/-0 typescript
· isRepository function jb_47d7aff7 :34
· changedFiles function jb_51700abf :68
· parseDiff function jb_fa72211c :98
⇒ used by src/tools/changes.ts
```
`scope:"branch"`比较整个分支与其基准 — `origin/main`、`main`或`master`,无论哪一个存在,或者您传递的`base`。依赖项按文件而不是按符号报告,因为导入图记录了哪些文件导入哪些文件,而不是每个导入使用哪个符号;声称相反会高估它所知道的。
### `jb_notes` — 存活下来的发现
一个结论,成本为二十次工具调用,应该被写下来,而不是重新派生。笔记锚定到路径,在`jb_trace`中,这些笔记会在这些文件上重新出现。
```
jb_notes {action:"add",
text:"Retry budget is deliberately shared across shards — see transport.ts:88.",
paths:["src/transport.ts"], tags:["gotcha"]}
```
存储为 `.jellybean/notes.json` 工作区内的纯 JSON,以便人类可以读取、编辑、审查或提交它们。代理人积累的代码库理解不应锁定在私有存储库中。
## 单一代码仓库
单一代码仓库并不是一个扁平的文件树,将其视为扁平结构会忽略一个重要的架构信息:**跨包依赖**。在一个包内,一个文件导入另一个文件是再普通不过的了。但是跨包导入则不同,它代表了一种耦合关系,这是评审者真正关注的重点。
包的检测依赖于其自身的清单文件,例如 `package.json`、`Cargo.toml`、`go.mod` 和 `pyproject.toml`,因此无需额外的配置。`jb_map` 会报告包的数量,而 `jb_trace` 则会标记重要的依赖关系:
```
jb_trace {path:"packages/shared/src/config.ts"}
⇒ 被以下文件依赖
packages/shared/src/local.ts jb_1a2b3c4d typescript
packages/api/src/server.ts jb_5e6f7a8b typescript 跨包依赖 → @acme/api
```
只有一个清单文件的仓库不会被视为单一代码仓库。因为如果每个依赖关系都标记为“跨包依赖”,这不仅会产生噪音,还会造成错误。
## 资源和提示
三种资源镜像映射了最便宜的调用,因此直接附加资源的客户端无需花费额外的调用次数:`jellybean://map`、`jellybean://checks` 和 `jellybean://notes`。
两种提示编码了工作流程:**onboard**(不熟悉的仓库的代币高效的导览)和 **fix-failures**(诊断 → 定位 → 跟踪 → 修复 → 重新验证)。
## 安全
`jb_diagnose` 是唯一运行命令的工具,其安全姿态是显式的。
- **绝不使用 Shell**。命令通过参数数组和 `shell: false` 启动。没有任何通配符扩展、`$(…)` 语法、`;` 命令链接。如果命令为 `echo hi; rm -rf /`,则会将 `echo` 命令运行为字面参数 `hi;`、`rm`、`-rf` 和 `/`,从而无害地失败。
- **默认仅运行已发现的检查**。开箱即用的可运行命令集是项目声明的:npm 脚本、Make 目标,以及 cargo、go、pytest 和 tsc 的语言默认值。其他命令需要 `--allow-command "<cmd>"`(前缀匹配)或生硬的 `--unsafe-commands` 选项。
- **超时和输出限制**。默认情况下,命令在 120 秒后被终止,捕获的输出限制为 2 MB。
- **路径包含**。每个调用者提供的路径都会经过一个函数,该函数拒绝任何解析后位于工作区根目录之外的路径。在遍历过程中不会跟随符号链接,因为它们可以指向树结构之外并创建循环。
- **仅读取 Git 显示的内容**。`.gitignore` 文件被遵守,包括嵌套的和取反的 `.gitignore` 文件,以及内置的永远不需要索引的目录列表。二进制文件被检测并跳过。
Jelly Bean 不执行任何网络 I/O 操作,并且只写入一个文件:笔记存储。
## 配置
```
jellybean [路径] [选项]
-r, --root <路径> 要索引的工作区。也是第一个位置参数。
--token-budget <n> 默认每次调用的预算(默认 2000)。
--max-file-bytes <n> 跳过大于此大小的文件(默认 524288)。
--max-files <n> 索引达到此文件数量后停止(默认 20000)。
--ignore <通配符> 额外的逗号分隔的忽略模式。
--allow-command <c> 允许 jb_diagnose 运行此命令。可重复。
--unsafe-commands 允许 jb_diagnose 运行任何命令。默认关闭。
--command-timeout <s> 命令超时前的时间(默认 120)。
-h, --help 显示用法。
-v, --version 打印版本号。
```
每个选项都有一个环境变量等价:`JELLYBEAN_ROOT`、`JELLYBEAN_TOKEN_BUDGET`、`JELLYBEAN_MAX_FILE_BYTES`、`JELLYBEAN_MAX_FILES`、`JELLYBEAN_IGNORE`、`JELLYBEAN_ALLOW_COMMANDS` 和 `JELLYBEAN_UNSAFE_COMMANDS`。
## 语言支持
完整的轮廓 — 声明、嵌套、可见性、文档注释:
**TypeScript** · **JavaScript** (+ JSX/TSX)· **Python** · **Go** · **Rust** ·
**Java** · **Kotlin** · **Swift** · **C#** · **C** · **C++** · **Ruby** ·
**PHP** · **Shell** · **SQL** · **Markdown** · **YAML** · **TOML** · **CSS**
导入图针对 TypeScript、JavaScript、Python(包括相对 `from .` 导入)、Go、Rust(`crate::`、`super::`、`self::`)、Java、Kotlin、C#、C/C++、Ruby、PHP 和 Shell 进行解析。
解析基于正则表达式,在源代码的掩码副本上进行。每种语言的 tree-sitter 语法都需要原生构建、安装失败和版本漂移;对于需要名称、种类和行范围的轮廓来说,这是一个糟糕的权衡。掩码过程使其变得可靠 — 字符串、注释、模板文字、正则表达式文字和 Python 文档字符串在运行任何模式之前都会被清空,因此字符串中的花括号不能破坏符号的范围。
## 架构
```
src/
index.ts CLI 入口;标准输入/输出传输
server.ts 工具、资源和提示注册
config.ts 标志和环境
core/
workspace.ts 路径包含、遍历、读取
ignore.ts 与 .gitignore 兼容的匹配器
code-index.ts 文件记录、反向索引、导入图
resolver.ts 模块说明符 → 工作区文件,每个语言
handles.ts 内容派生的区域引用(LRU)
cache.ts 持久化解析缓存,按大小和修改时间索引
watcher.ts 文件系统监视,因此新鲜度成本为零
git.ts 用于 jb_changes 的差异和状态解析
packages.ts 单一代码仓库包边界
tokens.ts 估计和预算执行
render.ts 共享输出语法
notes.ts 持久化发现结果
lang/
scanner.ts 字符串/注释掩码,偏移量保留
patterns.ts 每种语言的声明模式
outline.ts 符号提取(括号 / 缩进 / 行策略)
imports.ts 导入提取
registry.ts 扩展 → 语言 → 语法配置文件
diagnostics/
runner.ts 检查发现;无 Shell 执行
parsers.ts 工具输出 → 结构化诊断
tools/ 每个工具一个模块
```
索引的四个属性值得了解。
它是 **增量** 的:重新扫描只会重新解析大小或修改时间发生变化的文件,因此编辑 5,000 个文件的文件夹只需重新解析一个文件。
它是 **监视** 的,而不是轮询的。通过定时器重新遍历会使每个调用在定时器过期后支付遍历费用 — 按秒计,在大规模情况下更是如此。监视器使得“无变化”免费,并且有一个定时器备用方案,用于递归监视不可用的平台。
解析 **缓存在磁盘** 下的 `~/.cache/jellybean`,按大小和修改时间索引,因此重启不会重新解析仓库。故意放在工作区之外:笔记属于仓库,一个多兆字节的派生 blob 不属于仓库。
搜索是 **两阶段** 的:BM25 从反向索引中对文件进行排名,然后仅读取排名靠前的文件以定位行。存储行级帖子将变得更大,并且没有排名收益。精确的符号查找会跳过整个过程,直接命中名称索引。
## 开发
```bash
npm install
npm run build # 编译到 dist/
npm test # 144 个测试
npm run typecheck # 无输出
npm run demo # 每个工具的引导式游览
npm run render # 从实时输出重新生成 README 的 SVG 渲染
node scripts/benchmark.mjs <仓库> # 复现上述数字
```
测试套件涵盖了掩码扫描器(模板嵌套、正则表达式与除法、未终止的字符串)、跨五种语言的符号提取、gitignore 语义、预算执行、句柄驱逐、每个诊断解析器以及对真实临时工作区的端到端传递 — 以及一个协议测试,通过 stdio 使用真实的 MCP 客户端驱动构建的服务器,因为单元测试可以正常通过,而服务器无法完全按照协议进行通信。
## 设计笔记
一些可能看起来很武断的决定:
**README 的截图是生成的**。`npm run render` 从实际工具输出生成它们为 SVG,因此它们不会悄悄地偏离工具实际打印的内容 — 这是每个手动截图的故障模式。SVG 还可以在 git 中保持可差异化,并且不需要图像托管。
**输出不是 JSON**。大括号、引号和重复的键名会使结果的代币成本大致增加一倍,而模型解析对齐的行与可靠性一样高。语法在 `core/render.ts` 中定义一次。
**代币估计器略微高估**。平均而言,预算是真实的,但估计器混合了字符密度和符号计数,因此 `});` 被计为三个代币而不是一个。
**歧义不是解决**。当解析器无法唯一确定指定符指向的位置时,它会记录一个外部依赖项,而不是进行猜测。错误的图边比缺少的图边更糟糕。
**页脚在预算之外写入**。每个工具都为此预留了代币。将页脚丢失到完整的预算中会将截断的结果呈现为完整的结果,这是此设计可能发生的的最坏的故障。
## 贡献
问题和拉取请求是欢迎的。添加一种语言通常意味着在 `lang/registry.ts` 中添加一个条目、`lang/patterns.ts` 中的模式列表,以及在 `test/outline.test.ts` 中的测试 — `lang/outline.ts` 中的三种策略很少需要触及。
## 许可证
MIT © 2026 — 见 [LICENSE](LICENSE)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器