内容
# MapRepo 服务器
**一款常驻的 MCP 服务器,为编码代理提供高效、语义精确的仓库导航。**
MapRepo 在您的机器上永久运行,索引您注册的仓库到独立的每个项目 SQLite 数据库中,通过增量文件监视保持索引新鲜,并暴露 16 个 [模型上下文协议](https://modelcontextprotocol.io) 工具和一个交互式的 3D 网络地图。代理询问 *"谁调用此方法?"*、*"此文件中有什么?"*、*"显示行 178-190"* — 并接收有界限、证据支持的答案,而不是为整个文件读取和假阳性搜索付费。

## 亮点
- **语义 C# 分析** — Roslyn/`MSBuildWorkspace` 解析声明、调用、引用、继承和对象构造,精确到 `文件:行:列` 证据。调用 `Advance()` 找到 61 个真正的调用者,而不是 170 个文本匹配。
- **增量索引** — 每个仓库一个实时的 `MSBuildWorkspace`;保存文件仅重新分析更改的文件并替换其行。测量:**~300 毫秒** 每更改文件,而不是 1-2 分钟的完整解决方案重新加载。
- **严格的项目隔离** — 每个仓库拥有自己的目录 (`data-v4/<slug>__<hash>/index.db`,WAL 模式)。无共享;删除仓库仅删除其自己的数据。
- **重启证明** — 注册表 (`data-v4/catalog.json`) 在服务器重启后恢复每个仓库,包括监视器,重新利用存储的索引而无需重新索引。
- **优化令牌线格式** — 紧凑的 DTO、调用站点聚合(每个调用者一个边,带有 `行` 数组)、SQL 级边类型过滤和悬空边修剪将典型图响应减少约 73%。
- **语义 TypeScript,增量** — 当 Node.js 和 `typescript` 库可用时(仓库 `node_modules`、全局 npm 或服务器的 `tools/` 文件夹),TS 模块运行真正的 TypeScript 类型检查器,用于解析调用、引用、继承和导入;否则,它回落到内置的语法扫描器。可按仓库选择(`tsEngine`: 自动 | 语义 | 语法)。每个仓库的一个 Node 进程常驻(NDJSON 通过 stdin/stdout)并在其解析的 `程序` 中重用 — 仅更改的文件重新解析/重新绑定。测量:全程约 750 毫秒,增量更改的文件 60-360 毫秒(相对于重新启动 Node 并在每次保存时重新解析整个仓库)。
- **FTS5 搜索** — 符号搜索由 SQLite FTS5 索引支持(BM25 排名前缀匹配),带有 LIKE 回落,因此在 monorepo 级索引上保持快速。
- **语言模块作为插件** — 实现一个接口,将 DLL 放入 `MapRepo.Server/modules/`,混合仓库无需服务器更改即可工作。
- **3D 代码地图** — 无依赖的力导向 3D 可视化:围绕任何选定符号轨道,移动、缩放、动画调用脉冲、每个文件轮廓、按需源代码片段。
## 快速开始
```powershell
dotnet run --project .\MapRepo.Server
```
服务器绑定 `http://0.0.0.0:5087`(所有接口;使用 `--urls` 重写)。打开 `http://127.0.0.1:5087/` 以访问地图。
注册仓库(UI **+ 添加**,REST 或 `open_repository` MCP 工具):
```powershell
Invoke-RestMethod http://127.0.0.1:5087/api/repos/open -Method Post -ContentType 'application/json' -Body (@{
id = 'my-repo'
rootPath = 'D:\src\my-repo'
solutionPath = 'D:\src\my-repo\MyRepo.sln' # 可选;否则自动检测
} | ConvertTo-Json)
```
索引在后台运行;`GET /api/repos/{id}/status` 报告进度。从那时起,监视器在每次保存时保持索引新鲜。
## 始终开启的自动启动(Windows)
`dotnet run` 随着终端关闭。为了让 MapRepo 在机器上常驻,`scripts/manage-service.ps1` 发布服务器并将其注册为两种配置模式之一:
| 模式 | 启动 | 需要管理员 | 生存周期 |
| --- | --- | --- | --- |
| `Logon` | 登录时 | 否 | 否 — 在注销时停止 |
| `Service` | 启动前,登录前 | 是 | 是 |
```powershell
# 无需管理员 — 在下次登录时自动启动:
.\scripts\manage-service.ps1 -Action Install -Mode Logon
# 以管理员身份运行 — 真正的 Windows 服务,在启动时启动:
.\scripts\manage-service.ps1 -Action Install -Mode Service
.\scripts\manage-service.ps1 -Action Status # 注册 + 运行状况检查
.\scripts\manage-service.ps1 -Action Start -Mode Logon # 或 -Mode Service
.\scripts\manage-service.ps1 -Action Stop
.\scripts\manage-service.ps1 -Action Uninstall -Mode Logon # 或 -Mode Service
```
`-Port`(默认 5087)和 `-PublishDir`(默认 `<repo>\publish`)在每次调用时都是可配置的;保持 `-PublishDir` 与安装/卸载/状态一致,以便脚本找到正确的可执行文件。已发布的副本管理其**自己的** `data-v4/` 目录,不依赖于 `dotnet run` 开发检查 — 因此通过已安装的实例注册仓库不会触及开发索引,反之亦然。
## MCP 集成
```json
{
"mcpServers": {
"map-repo": { "type": "http", "url": "http://127.0.0.1:5087/mcp" }
}
}
```
克劳德代码:`claude mcp add --scope user --transport http map-repo http://127.0.0.1:5087/mcp`
支持流式 HTTP、遗留 SSE(`/sse` + `/message`)和纯 JSON-RPC POST。
### 工具
| 工具 | 用途 |
| --- | --- |
| `open_repository` | 注册/打开 + 索引 + 监视。`reindex` 强制重建;`includeTextualEvidence` 选择加入字符串字面量挖掘;`allowExternalSymbols`(仅 C#,默认为 false)选择加入索引通过 `ProjectReference` 拉入的外部项目符号 — 否则其符号/边被删除以保持每个仓库的索引隔离。 |
| `list_repositories` | 默认紧凑状态(id,rootPath,符号,关系,索引,诊断计数)— 发现入口点。`includeDiagnostics: true` 返回完整的定义和每个仓库的诊断文本。 |
| `repository_status` | 生成、计数、诊断、监视器/索引状态。 |
| `reindex_repository` | 强制完整重建。 |
| `close_repository` | 停止监视器,释放内存;数据和注册保持。 |
| `remove_repository` | 注销;`deleteData` 还删除仓库的数据库目录。 |
| `exclude_path` | 将路径子字符串添加到仓库的排除列表,并立即清除已索引的行 — 无需重新索引。对于保留污染搜索结果的临时/生成文件夹(`.tmp`,项目特定的构建验证目录)。 |
| `repo_overview` | 缓存的每代定位图:按种类/语言/项目、边种类、顶级文件、中心符号计数。`includeGenerated: true` 包括工具生成的代码(设计器/`.g.cs`/`.pb.cs`/AssemblyInfo`/obj`/Generated),默认排除。 |
| `search_symbols` | 名称/路径搜索,带有 `kind` / `pathContains` 过滤器和精确源代码证据。`includeTextual: true` 针对以 `includeTextualEvidence: false` 索引的仓库返回一个 `diagnostic` 字段,解释为什么没有返回文本内容。 |
| `get_symbol` | 一个带有传入/传出边和邻居记录的符号。 |
| `file_outline` | 文件中的每个声明,按行排序 — 比读取文件更便宜。 |
| `list_files` | 索引文件带有声明计数。 |
| `get_source` | 精确的行范围(最多 400 行);路径遍历安全。默认情况下,如果 `startLine > endLine` 或 `startLine` 超过 EOF,则错误 — 传递 `clamp: true` 以自动纠正。`truncated` 表示 400 行窗口截断了实际内容,而不是您要求的行数超过文件的内容。 |
| `find_callers` / `find_callees` | 符号周围的语义调用边。`find_callers` 默认 `calls`;`find_callees` 默认 `calls`+`constructs`(因此 `new Foo()` 站点计为调用者);两者都接受 `edgeKinds` 重写。 |
| `find_references` | 符号周围的引用边。 |
| `get_graph` | 有界限的关系图;`edgeKinds` 限制遍历(例如 `["calls"]`)。 |
| `batch` | 一个请求中的最多 10 个工具调用(约 200KB 组合响应上限,如果达到则 `truncated`/`nextIndex`);每个调用的错误不会中止其余调用。 |
### 令牌合约
推荐的代理流程 — 每个步骤有界限,比其替代方案更便宜:
```
list_repositories → repo_overview → search_symbols → get_symbol / find_* / get_graph → get_source (仅限确切行)
```
使用 `batch` 将您已经知道的步骤链接到一个往返中:
```json
{ "calls": [
{ "tool": "search_symbols", "arguments": { "repositoryId": "app", "query": "PaymentService" } },
{ "tool": "repo_overview", "arguments": { "repositoryId": "app" } }
] }
```
仓库语料库从未进入模型。参见 [`skills/map-repo/SKILL.md`](skills/map-repo/SKILL.md) 以获取完整的使用指南,包括何时普通 grep 仍然是更好的工具。
## 架构
```
MapRepo.Core IR 接口:SymbolRecord、RelationshipRecord、模块接口
MapRepo.Modules.CSharp Roslyn/MSBuildWorkspace 语义分析、增量增量
MapRepo.Modules.TypeScript 语法级 TS/TSX/JS 声明、导入、调用
MapRepo.Server ASP.NET Core 主机:会话、监视器、SQLite 存储、MCP + REST + 网络地图
```
每个模块发出相同的中间表示;会话管理器将记录合并到仓库的私有数据库中。模块仅替换其自己的行,因此失败或部分模块永远不会损坏另一个模块的数据。增量模块(`IIncrementalAnalyzer`)更进一步,仅替换已更改文件的行。
### 监视器行为
忽略 `.git`、`.tmp`、`bin`、`obj`、`node_modules`、`dist`、`build`、`coverage` — 一个列表 (`MapRepo.Core.PathExclusions`) 由监视器和每个语言模块共享,包括基于 Node 的 TypeScript 语义引擎。延迟 750 毫秒;处理创建/更改/重命名/删除。C# 更改采用增量路径(新文件触发一次完整的模块运行,重新缓存工作区)。字符串字面量挖掘(`textual-evidence`)默认为关闭 — 它将索引膨胀约 30% 且充满噪音;仅在需要搜索嵌入式协议字符串时,每个仓库启用。
可以在 `open_repository` 时使用 `excludedPaths` 或通过 `exclude_path` 工具事后添加项目特定的临时/生成文件夹 — 后者立即清除已索引的行,无需重新索引。
`open_repository` 上的 `enabledModules` 必须与实际模块 ID 匹配(`csharp-roslyn`、`typescript-syntax` — 参见 `GET /api/modules`);如果筛选器与任何内容都不匹配,则会报错(通过 `repository_status` 显示)而不是默默地索引零符号。
### TypeScript 引擎解析
`GET /api/engines` 报告可用性。语义引擎按顺序探测:仓库自己的 `node_modules/typescript`、`MAPREPO_TS_LIB`、服务器的 `MapRepo.Server/tools/node_modules/typescript`(使用 `npm install --prefix MapRepo.Server/tools typescript@5` 安装一次),以及全局 npm 根目录。TypeScript 5.x 是必需的(v7 原生预览版不公开 JS 编译器 API)。
### 添加语言模块
引用 `MapRepo.Core`,实现 `IRepositoryLanguageModule`(可选 `IIncrementalAnalyzer` + `IRepositoryLifecycle`),发出公共 IR,构建为 `MapRepo.Module*.dll` 并复制到 `MapRepo.Server/modules/`。注册在启动时发现它。内部解析器是您的选择 — Tree-sitter、tsserver、编译器 API — MCP 契约永远不会更改。
## 网络地图
- **轨道** (左拖动)围绕选定的节点 — 点击任意节点使其成为中心节点;双击重新根图。
- **平移** (右/中/Shift 拖动,箭头键),**缩放** (滚轮,`+`/`-`),**重置** (`0`)。
- 搜索带有种类过滤器芯片、每个文件的轮廓、概览仪表板和可点击的中心。
- 详细信息面板:签名、传入/传出边、按需精确源代码片段。
- 深度链接:`/#repo=<id>&q=<query>` 自动加载第一个匹配项。
### 阅读详细信息面板的边列表
每行是 `<kind> <symbol name>` — 种类徽章命名关系,名称是该边上的**其他**符号,而不是选定的符号。
- **传入** = 边,其中选定的符号是目标 — 其他符号指向**它**。
- **传出** = 边,其中选定的符号是源 — 它指向**其他**符号。
| 种类 | 含义 |
| --- | --- |
| `calls` | 一个方法/函数调用另一个 |
| `constructs` | `new X(...)` — 一个符号实例化一个类型 |
| `contains` | 声明嵌套 — 一个类型/命名空间包含一个成员 |
| `references` | 读取/使用符号而不调用或构造它 |
| `inherits` | 类扩展一个基类 |
| `implements` | 类/结构体实现接口 |
| `imports` | 一个模块导入另一个模块(TypeScript) |
示例:选择一个方法并看到 **传入:`contains` → `Crc32`** 和 **调用:**
`HashFinal`** 意味着该方法在类 `Crc32` 中声明,并且一个名为 `HashFinal`
的方法调用它。
## 安全说明
服务器**没有身份验证**,默认绑定所有接口,因此 LAN 代理可以访问它。任何可以访问端口的人都可以注册可由您的用户读取的路径并获取索引源代码。在不受信任的网络上,绑定回环 (`--urls http://127.0.0.1:5087`) 或防火墙端口。`get_source` 拒绝逃离已注册仓库根目录的路径。
## 许可证
MIT