内容
# ts-header-mcp
一个MCP服务器,为AI编码代理生成TypeScript源代码的头文件视图:函数、类和类型签名,并带有原始行号,可按文件、目录或整个项目请求。
```typescript
// ==== src/services/userService.ts — 312 lines, 8 exports ====
export class UserService { // L24-198
constructor(db: Database, cache?: CacheLayer) // L31
getUser(id: UserId): Promise<User | null> // L45
// Fetches a user by ID, checking cache first.
patch(id: UserId, p: Partial<User>): Promise<User> // L69 ⚠ deprecated
}
// -- types: L201-240 --
export type UserId = Brand<string, "UserId">;
export interface User { id: UserId; name: string; email: string; roles: Role[]; }
export function createUserService(cfg: Config): UserService // L245
```
其理念与C头文件相同:代理首先读取紧凑视图,然后仅在需要时打开源代码到特定行号。返回类型来自TypeScript类型检查器,因此推断的返回类型会明确显示。具有类型或语法错误的源文件仍会生成头文件;不可靠的签名会单独标记(`// L84 ⚠ TS2304: Cannot find name 'Ordr'`),而不是导致整个文件失败。
## 与现有工具的关系
几种现有方法涵盖了部分内容。具体取决于代理和任务;ts-header是为特定空白而构建的。
- **`tsc --emitDeclarationOnly`** 生成`.d.ts`文件,与头文件最接近。差异:声明发出需要可编译的项目,将文件写入树中,不携带源代码行号,并且仅涵盖公共接口。如果您想为库消费者生成构建产物,`.d.ts`是合适的工具;对于导航,尤其是在当前无法编译的代码中,ts-header更合适。
- **LSP支持的MCP服务器** (Serena、lsmcp、symbols-mcp)将符号查询公开为单独的工具:获取大纲、查找符号、查找引用。它们比ts-header更精确、更强大,但需要一系列工具调用才能回答问题。ts-header将工作流折叠为一个工具,其输出针对请求路径完整。
- **仓库映射** (Aider的仓库映射、RepoMapper)生成最重要的符号的单个排名摘要,适合自动上下文注入。该格式适合,但有意丢失:不排名的符号被省略,无法请求特定文件的完整内容。
ts-header结合了以下功能:
- 完整的每个路径输出(无排名省略)带有原始行号作为跳转目标
- 一个工具适用于所有级别:项目概览、目录列表、文件头
- 适用于无法编译的代码,带有每个符号的错误标记
- 包括非导出和函数局部声明(按需)
- 默认不写入文件,因此不会泄漏到版本控制中
- 关注结果,减少LLM注意力所需的工具调用
(参见下表比较。)
## 工具
一个工具,`ts_header(path, depth?, docs?, max_tokens?, filter?)`。导航深度由路径表示,因此交互模型类似于熟悉的`ls` / `cat`模式,而不是一组工具。
- `path`: 文件或目录,相对于工作区。目录中的目录返回项目概览;目录中的文件返回每个文件的导出列表(带有桶文件检测和 `[test]` 标签);文件返回完整的头文件。`"."` 给出项目概览。还接受文件路径数组或 glob 模式(`"src/**/*.ts"`)用于批量多文件头文件,一次调用最多 20 个文件;令牌预算按批次分配,每个项目的问题(缺少文件、目录、非TS)内联报告,不会失败其他文件。
- `depth`: `exports`(默认)| `all`(添加非导出声明和私有成员)| `deep`(还深入函数体:内部函数、闭包、局部声明的类)。
- `docs`: `none` | `brief`(默认:第一个JSDoc句子;显示在单行签名后,多行声明前)| `full`(完整的JSDoc,包括`@param`和`@throws`)。`@deprecated`始终显示。文件顶部的JSDoc块被视为文件的描述,而不是第一个声明的描述:它在头文件横幅下渲染,并在目录列表中作为文件行的简短注释。
- `max_tokens`: 近似输出预算,默认4000。截断的输出会说明这一点以及如何请求更多。
- `filter`: 仅显示名称与模式(不区分大小写正则表达式;纯文本也适用)匹配的符号。在每个级别应用,因此`ts_header(".", {filter: "booking"})`作为跨项目的轻量级类型符号搜索。过滤器仅适用于名称;函数体内的全文搜索仍然是grep的工作。
- `includeImports`: 当为真时,头文件以`// -- imports --`块开头,列出文件的导入语句,每个导入语句折叠为一行,省略为120个字符。默认关闭(导入通常不值得为定位赚取令牌)。
对于诸如Convex的`export const f = mutation({ args: {...}, handler: ... })`之类的框架包装器声明,头文件在签名下添加`// args:`行,显示验证器形状(或处理程序的参数列表,如果没有`args`属性)。如果该行只会重述已经在检查的签名中可见的属性名称,则该行被抑制;如果太长,则整个属性被省略,并带有`…n more`而不是在标识符中间剪切。
### 直观比较:ts-header vs. Alternatives
| 功能 | ts-header | LSP 服务器 | 仓库映射(Aider) | tsc --emitDeclaration |
| :--- | :---: | :---: | :---: | :---: |
| **保留行号** | **是(Lnn)** | 是(符号) | 否 | 否 |
| **令牌预算感知** | **是** | 否 | **是** | 否 |
| **适用于不可编译的代码** | **是** | 是 | 是 | 否 |
| **一次性项目导航** | **是** | 否(多步骤) | **是**(有损) | 否 |
| **包括私有/局部符号** | **可选** | 是 | 否 | 否 |
## 为什么使用它
通过grep和阅读整个文件来定位的代理会烧掉令牌并仍然会错过某些内容。为了衡量差异,我们在大型单体仓库中运行了相同的查询——“在此项目中解释waitlist队列的工作原理”——在两个会话中使用相同的LLM:一个使用`ts_header`,另一个不使用。
| 维度 | 无`ts_header` | 有`ts_header` |
| :--- | :--- | :--- |
| **初始发现策略** | 无过滤的`grep_search("waitlist")`(200个匹配) | 结构化的`ts_header`目录扫描和过滤 |
| **模块覆盖** | 找到4个关键文件;错过2个 | 找到所有5个与waitlist相关的文件 |
| **工具执行效率** | 试错grep + 完整文件查看 | 目录概览→过滤签名→目标行视图 |
| **解释完整性** | 扎实的概览,错过两个入口点 | 完整的端到端跟踪,包括管理员发布和后台通知 |
使用`ts_header`的会话更加高效(基于索引的发现而不是试错grep),并且更加完整(它找到了另一个会话忽略的入口点)。完整的会话间分解在[docs/case-study.md](docs/case-study.md)中。
## 安装
需要Node 20+和[pnpm](https://pnpm.io)。
```bash
git clone https://github.com/<your-username>/ts-header-mcp.git ~/tools/ts-header
cd ~/tools/ts-header
pnpm install
pnpm test # 静默单元测试(提取器、格式化器、路由器)
pnpm run smoke-test # 详细:打印完整示例头文件以供审阅
pnpm run build # -> dist/server.js 和 dist/cli.js
```
将仓库克隆到工作仓库之外(例如`~/tools`),以保持服务器不在项目的版本控制中。
注意适用于TypeScript 6.0+:编译器不再自动包含`node_modules/@types`中的包,因此项目tsconfig显式设置`"types": ["node"]`。如果在`pnpm run build`期间看到`TS2591: Cannot find name 'process'`,则缺少该行。
## CLI用法
对于非MCP集成或命令行脚本,可以直接从终端运行CLI。
```bash
# 使用node运行
node dist/cli.js <workspaceRoot> <path> [options]
# 或通过ts-header-cli命令(如果安装/链接)
ts-header-cli <workspaceRoot> <path> [options]
```
### 选项
* `--depth=exports|all|deep`: 要提取的声明详细程度。
* `--docs=none|brief|full`: JSDoc详细程度。
* `--max-tokens=N`: 近似令牌预算限制。
* `--filter=PATTERN`: 用于按名称过滤符号的RegEx模式。
输出写入`stdout`,错误写入`stderr`(成功时退出代码`0`,错误时退出代码`1`)。
## 客户端设置
服务器使用stdio通信。第二个`args`条目是它所服务的工作区;如果省略,则使用进程工作目录。
### VS Code(Copilot代理模式)
在工作区中创建`.vscode/mcp.json`(此文件可以提交)或从命令面板运行`MCP: Open User Configuration`以进行用户级配置。注意根键是`servers`,而不是`mcpServers`,并且支持`${workspaceFolder}`:
```json
{
"servers": {
"ts-header": {
"type": "stdio",
"command": "node",
"args": ["/home/you/tools/ts-header/dist/server.js", "${workspaceFolder}"]
}
}
}
```
MCP工具仅在Copilot的Agent模式下可用(聊天视图中的模式下拉菜单)。如果服务器行为异常,`MCP: List Servers` → 选择它 → 显示输出会显示其stderr。
### Cursor
在项目中创建`.cursor/mcp.json`或`~/.cursor/mcp.json`用于所有项目。Cursor使用`mcpServers`根键;使用绝对路径:
```json
{
"mcpServers": {
"ts-header": {
"command": "node",
"args": ["/home/you/tools/ts-header/dist/server.js", "/path/to/your/workspace"]
}
}
}
```
在Cursor设置中启用服务器 → MCP,如果它没有自动出现。对于全局配置服务多个项目,请为每个工作区添加一个条目(例如`ts-header-projA`、`ts-header-projB`)。
### Google Antigravity(2.x)
共享配置为`~/.gemini/config/mcp_config.json`(2.0之前的安装使用`~/.gemini/antigravity/mcp_config.json`)。您可以从IDE中打开正确的文件:代理面板`…`菜单 → MCP服务器 → 管理MCP服务器 → 查看原始配置。将条目合并到现有的`mcpServers`对象中(与Cursor示例相同,绝对路径,JSON中没有`~`),然后刷新在设置 → 自定义化 → 已安装的MCP服务器下。
<details>
<summary>提示Antigravity的代理执行设置</summary>
替换占位符并粘贴到代理面板:
```
为我设置一个名为ts-header的本地MCP服务器。按照以下步骤执行并
验证每个步骤,然后再继续到下一步。不要跳过测试步骤。
来源:https://github.com/<your-username>/ts-header-mcp.git
它将服务的工作区:<PATH_TO_MY_TS_PROJECT>
1. 预检:
运行`node -v`以确保我的环境具有Node.js 20或更高版本。
如果版本较低,请立即停止并说明需要Node 20+。
还要确认pnpm可用(`pnpm -v`);如果没有,请运行`corepack enable`。
2. 安装位置:在任何我工作的git仓库之外:
将SOURCE克隆到~/tools/ts-header。永远不要复制它到我的当前
工作区;不得将此设置中的任何内容提交到我的任何仓库中。
3. 构建和测试:
cd ~/tools/ts-header
pnpm install
pnpm test # 单元测试:必须以“fail 0”结束
pnpm run build # 生成dist/server.js
如果测试失败,请停止并显示完整的输出。不要修改源代码
以使测试通过而不告诉我更改了什么以及原因。
4. 注册服务器:
查找我的MCP配置:~/.gemini/config/mcp_config.json在当前Antigravity
版本(旧安装使用~/.gemini/antigravity/mcp_config.json ...使用
哪一个存在;如果两者都存在,请使用IDE打开的那个
面板"…"菜单 > MCP服务器 > 管理MCP服务器 > 查看原始配置)。
将以下条目**合并**到现有的“mcpServers”对象中。不要
覆盖或删除文件中已有的任何服务器。显示配置的差异
更改前。
"ts-header": {
"command": "node",
"args": ["<HOME PATH>/tools/ts-header/dist/server.js",
"<WORKSPACE IT WILL SERVE>"]
}
使用绝对路径(JSON内部不使用~)。
5. 激活和验证:
刷新MCP服务器(设置 > 自定义化 > 已安装的MCP服务器 >
刷新,或重启IDE)。确认“ts-header”出现,带有1个工具,
ts_header。如果服务器启动失败,请运行
node ~/tools/ts-header/dist/server.js <WORKSPACE> 手动,捕获stderr,
并在更改任何内容之前向我显示它。
6. 烟雾测试工具,通过调用它三次并显示每个输出:
ts_header(".") -> 项目概览
ts_header("<some src directory>") -> 每个文件的导出列表
ts_header("<one .ts file from that list>") -> 带有// L45行号的签名
7. 从现在开始,在此工作区:当您需要了解TypeScript代码时,
调用ts_header目录或文件**,仅在它报告的特定行号处打开源文件。
不要为定位而读取整个.ts文件。将其规则添加到您的项目规则/内存中
如果您支持的话。
请报告:安装路径、编辑的配置文件、配置差异、
测试结果和三个烟雾测试输出。
```
</details>
### 其他客户端(HTTP桥)
对于无法启动stdio服务器的客户端,`http-server.mjs`包装相同的路由器,并通过本地HTTP提供纯JSON。集成示例位于[`mirica-tool/`](mirica-tool/README.md)。
## 教你的代理使用它
注册服务器只是设置的一半。没有明确的指令,代理倾向于回落到读取整个文件进行定位。在项目的代理说明文件(`AGENTS.md`,`.cursorrules`,`CLAUDE.md`或等效文件)中添加一条规则:
```markdown
# TypeScript项目分析
- 分析TypeScript项目时,始终调用`ts_header`工具
获取文件和目录结构,而不是读取整个源文件。
- 仅在`ts_header`报告的特定行号处打开源文件。
```markdown
在现场测试中,这条规则是代理一致使用该工具与忽略它的区别。
## 文件、缓存和沙盒
默认情况下,服务器执行无磁盘写入;所有缓存都在内存中,它在只读沙盒中运行。编译器选项被`noEmit`和`incremental: false`覆盖,因此具有`incremental: true`的工作区tsconfig不会导致`.tsbuildinfo`文件出现在您的仓库中。有一个回归测试用于该用例。
持久缓存作为`TS_HEADER_CACHE=1`的选项提供。其位置按顺序解析:`TS_HEADER_CACHE_DIR`,然后`$XDG_CACHE_HOME/ts-header`,然后`os.tmpdir()/ts-header`。每个候选文件在启动时都会被探测写入;如果没有一个可写入,则服务器会记录一行并继续仅使用内存缓存。如果您故意将缓存放在工作区中,则会写入`.gitignore`目录中的`*`。
其他环境变量:
- `TS_HEADER_GITIGNORE=0`: 禁用列表中的.gitignore处理
- `TS_HEADER_DOCS=none|brief|full`: 服务器范围内的`docs`选项默认值,用于测试文档摘要是否值得为您的代理赚取令牌
- `TS_HEADER_DENSE_MIN`: 声明块的分组阈值,默认为6个源行
- `TS_HEADER_MAX_PROJECTS`: 语言服务LRU大小,对于monorepo,默认为4
## 架构
`server.ts`(MCP层,唯一导入SDK的模块)和`cli.ts`(CLI入口点)→ `router.ts`(路径→项目概览 | 目录列表 | 文件头文件,附加内容哈希缓存)→ `formatter.ts`(所有布局规则)← `FileHeaderModel`(`model.ts`中的纯JSON合约)← `extractor.ts`(原始TypeScript编译器API)← `project.ts`(最近的tsconfig发现,一个长lived的`ts.LanguageService`配置,每个配置,项目引用源折叠,LRU淘汰)。提取器位于`FileHeaderModel`合约下,因此可以替换它(例如,通过tree-sitter实现)而无需更改格式化器、缓存或MCP层。 `ts-header-design.md`包含设计原理和决策日志。
## 待办事项和下一步计划
大致按照优先级顺序。前两项来自原始设计文档(参见 `ts-header-design.md` §12);其余项是在对真实 monorepo 进行实地测试期间积累的。
1. **基于预算的树深度**。项目概览当前仅显示一个目录级别。更好的是,在令牌预算允许的情况下,展开子目录,并首先折叠最大的子树,这样深度就不再受固定常数的限制,而是取决于 `max_tokens`。
2. **解决方案构建器项目引用**。Monorepo 引用通过将引用项目的源文件折叠到一个程序中来处理 - 正确,但在大工作区中,程序会变得很大。使用编译器的解决方案构建器机制可以保持每个包的程序彼此独立。
3. **文件监视器失效**。目前,新鲜度是每次请求的 mtime 检查(正确,但对大项目来说,`stat` 调用次数过多)。基于 `fs.watch` 的失效器将使重复目录列表更加便宜。
4. **多工作区服务**。服务器在启动时提供给定的单个工作区;每个项目的配置条目是一种变通方法。通过调用路径或客户端 `cwd` 解析工作区,将允许一个注册服务于所有内容。
5. **`docs:"auto"`**。仅当它在符号名称之外添加信息时,才包含简短的文档句子(跳过 `fetchUser` 上的“获取用户”)。需要一种能优雅失败的启发式算法;由于上述评估,尚不清楚它是否重要。
6. **机器可读输出**。对于希望进行后处理而不是读取的编排器,`FileHeaderModel` 的可选 JSON 变体。该模型内部已经是纯 JSON;这主要是 `format` 参数。
7. **嵌套 `.gitignore` 文件**。目前只读取工作区根目录下的 `.gitignore`;每个目录的忽略文件是 `src/ignore.ts` 的直接扩展。
8. **Vue/Svelte SFC 脚本块**。从 `<script lang="ts">` 部分提取。优先级较低,除非目标代码库需要它。
9. **重载改进**。重载链紧密渲染,但实现签名(在 TS 中不可调用)仍然与声明重载一起出现;`.d.ts` 约定将隐藏它,同时保持其在链上的 L 范围。
刻意不涉及的范围:编辑/重构(只读工具)、函数体内的全文搜索(grep 可以更好地完成此任务)以及重要性排名(按照设计,标头是完整的;排名摘要是 Aider-repo-map 领域)。
## 状态和测试
- `pnpm test` 运行单元测试套件(`test/unit/`,Node 内置测试运行器通过 tsx,66 个测试):格式化器测试是基于手动构建的模型的纯函数测试(注释、文档模式、密集块分组、错误横幅、截断、TOC 布局);提取器测试在共享夹具上构建一个程序,并断言模型结构(深度语义、推断返回类型、重载、JSDoc 提取、诊断附件、桶检测);路由器测试在 OS 临时目录中构建一个临时工作区,并涵盖所有三个导航级别、`filter` 参数、`.gitignore` 处理、防护轨和零写入不变性(包括带有 `incremental: true` tsconfig 的情况)。Convex 形状的夹具保护了在实地测试中发现的框架代码回归:大型 `export const x = framework({...})` 声明保留其自己的行注释,渲染类型通过剥离 `import("...")` 修饰符限制长度。
- `pnpm run smoke-test` 故意冗长:它为夹具在两个深度/文档组合上打印完整的渲染标头,供人类审查输出格式,然后是一组摘要断言。
- `server.ts` 针对 `@modelcontextprotocol/sdk` ^1.x。它是在没有注册表访问的环境中编写的,因此 SDK 连线是测试套件未执行的唯一部分;在它之下,所有内容都在 `--strict` 下执行和类型检查。
已知限制被跟踪为上述待办事项 2 和 3。 此外,设计文档描述了对代理错误文件读取的系统评估,有和没有工具;[docs/case-study.md](docs/case-study.md) 中存在非正式比较,但该评估尚未运行。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器