关于 Type Atlas
Type Atlas 是为 TypeScript 和 JavaScript 代码库提供语义导航与诊断的 MCP 服务,面向编码 Agent。它结合符号关系、自然语言代码搜索和项目范围信息,适用于大型仓库和 monorepo。
主要功能
- 01导航定义、引用、调用者和类型
- 02按自然语言行为描述查找代码
- 03在响应中附带相关诊断
- 04保留项目范围和源代码位置
- 05返回结构化且适合上下文的代码结果
适用场景
- 01在 monorepo 中追踪调用者和实现
- 02通过描述行为查找已有辅助函数
- 03调查代码时查看类型诊断
MCP 相关
Type Atlas 作为 MCP 服务运行,编码 Agent 可通过客户端配置连接。其工具提供代码导航、搜索和诊断;四种语义索引工具需要 uv。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
40收录的工具列表 · 更新于 3 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| file | array | 是 | 要一并读取的一个或多个文件:可以是路径,也可以是用于限定单个文件范围的 { path, startLine, endLine, fold }。两种形式可以混用,例如 ["a.ts", { "path": "b.ts", "startLine": 1, "endLine": 40 }]。 |
| fold | boolean | 否 | 将函数体折叠为函数签名;适用于未单独设置此项的条目。 |
| endLine | integer | 否 | 最后一行,使用从 1 开始的行号且包含该行;适用于未单独设置此项的条目。 |
| startLine | integer | 否 | 第一行,使用从 1 开始的行号;适用于未单独设置此项的条目。 |
| workspace | string | 是 | 仓库根目录。此项用于选择语言服务器会话,因此每个仓库应使用一个稳定的根目录,而不是子目录。相对路径相对于 MCP 进程的工作目录解析。 |
| includeDiagnostics | enum | 否 | 可选值:summary(一个完整诊断加文件总数)、verbose(完整报告)、off(不包含诊断信息)。off | summary | verbose |
详细介绍
Type Atlas 是我在所有 TypeScript 项目中用于满足编码 Agent 全部代码导航需求的工具。这些项目大多是单体仓库,其中一些规模庞大、结构复杂,要理解某项更改如何融入系统的其他部分,本身就是一项重要工作。这个工具旨在彻底取代 Agent 默认的代码导航方式。
过去几个月里,我一直根据自己的编码 Agent 在项目中的实际工作方式迭代这个工具。Type Atlas 的大多数功能,都是因为我不断遇到同样的问题:
- Agent 对系统的理解并不完整。 它们可能了解找到的文件,却不了解周边代码,而这些代码决定了该文件应如何使用。
- Agent 会重新实现已有功能。 仓库中明明已有相应能力,但 Agent 不知道它叫什么,因此始终找不到。
- Agent 往往读得太少(Claude),或读得太多(Codex)。 读得太少会让它们在缺少足够上下文的情况下做决定。读得太多则会让整个文件和与任务无关的实现细节占满上下文窗口。
- Agent 会反复停下来运行类型检查,只为发现 IDE 早已显示的错误。 这会拖慢整个实现过程,也让反馈来得比必要时间更晚。
- Agent 从根本上说是在盲目操作。 基于字符串搜索的导航无法让它们建立对代码库的完整认知。它们只能根据检索到的文件片段和匹配结果做出实现决策,而重要的结构信息和编译器已知的信息仍然缺失。
随着项目不断增长,这些问题会层层叠加,并直接影响编码 Agent 产出代码的质量。
语义代码导航
编码 Agent 默认通过读取文件和搜索字符串来导航代码。这样虽然能获取源文本,却让模型自行还原 TypeScript 语言服务早已掌握的关系。
Type Atlas 让 Agent 可以直接访问这些语义信息:
- 符号会解析到其实际定义和引用,而不是所有相同文本的出现位置。
- 调用方和实现会根据它们与符号的关系进行识别。
- 推断类型来自语言服务,而不是根据附近的源代码重新推断。
- 结果会附带其源代码范围和所属的 TypeScript 项目。
如果 Agent 要找的就是文本,文本匹配仍然很有用。但当问题关乎程序本身时,文本匹配无法替代语义导航。
找到已有功能
大型代码库包含许多有用的代码,而 Agent 不可能知道它们的名称。只有在 Agent 已掌握足够词汇来构造搜索内容后,字符串搜索才最有效。
Type Atlas 还提供了其他查找途径:
- Agent 可以用自然语言描述行为,并根据代码的功能查找代码。
- 找到的结果可以追溯到真实符号和精确的源代码范围。
- Agent 可以从该符号出发,沿着代码库中的实际关系继续探索,而不是猜测另一个标识符来搜索。
这在大型单体仓库中特别有用。这样一来,Agent 可以更容易地发现已有的辅助工具和成熟实现,而不必决定再创建一个。
正常工作期间的诊断信息
开发者在 IDE 中工作时会看到编译器反馈。编码 Agent 通常要先停下实现,运行类型检查命令,然后等待结果,才能获得这些反馈。
Type Atlas 将其中很多反馈融入 Agent 原本就在进行的工作:
- 相关诊断信息可以随常规代码智能响应一同返回。
- 受影响的代码仍处于 Agent 当前工作上下文中时,错误就会显示出来。
- 类型假设错误可以在引发多个后续编辑之前被发现。
我仍会使用完整的类型检查进行验证。但 Agent 工作时了解错误,不必主要依赖这种方式。
为模型上下文打造的响应
缩小响应只有在被删去的信息并非必要时才有用。模型也会利用剩余信息的组织方式。
Type Atlas 将结构视为信息的一部分:
- 标签会明确说明结果的作用。
- 分组会将相关事实放在一起。
- 文件边界可防止不相关的源代码混杂在一起。
- 源代码位置会与其描述的内容保持关联。
- 树形结构会保留层级,而不是变成扁平序列。
- 诊断信息会保留理解错误所需的源代码。
同一原则也决定了哪些内容可以省略。如果函数签名已经足够,函数体就可以保持折叠。重复的序列化内容和不相关的源代码无需仅仅因为可用,就占据上下文窗口。
目标是提高有用信息的密度。减少 token 固然重要,但如果移除了帮助模型理解这些 token 的结构,就违背了初衷。
为下一步决策提供信息
每次工具调用都是 Agent 推理过程的一部分。好的响应应当回答当前问题,同时让 Agent 更好地判断接下来要检查什么。
Type Atlas 会将有用的后续信息保留在揭示这些信息的结果附近:
- 符号可以附带理解其如何参与代码库所需的关联信息。
- 仓库结构可以在列出文件的同时,附带行数和工作树状态。
- 搜索结果会包含具体的源代码范围,可直接继续查看。
- Agent 从一个结果转向另一个结果时,项目上下文会始终保持关联。
这样,Agent 在调查的每个分支上都能获得更充分的依据。它可以沿着程序中实际存在的关联继续探索,而不是把每个文本匹配都当成同样重要的线索。
这样做的好处是导航质量更高。每一步都会保留更多有助于选择下一步的信息。
项目与范围感知
TypeScript 问题取决于项目上下文。在 monorepo 中,这一点尤其重要:某个答案在一个项目内可能正确,但对于整个仓库而言仍不完整。
Type Atlas 会清晰呈现这些边界:
- 文件会通过拥有它们的 TypeScript 项目进行解析。
- 当项目范围会影响结果时,结果会说明其所属范围。
- 计数会明确显示结果的数量。
- 如果答案仅涵盖仓库的一部分,就会说明范围限制。
- 源代码位置可以直接传递给后续调用。
Agent 在依赖答案之前,能够获得足够的信息来理解答案的实际覆盖范围。
基于日常 Agent 使用打造
我每天都会在自己的所有 TypeScript 项目中使用 Type Atlas 和自己的编码 Agent。当前的行为正是反复使用的结果。
很多设计都可以直接追溯到 Agent 反复出现的行为:
- 读取内容会折叠,因为 Agent 总是把上下文浪费在它们不需要的代码主体上。
- 诊断信息会随常规响应一并返回,因为反复运行类型检查命令浪费了实现时间。
- 语义关系会归为一组,因为 Agent 总是通过单独调用反复重建相同的信息。
- 提供自然语言代码搜索,因为有用的代码往往有个 Agent 无法从任务中推断出的名称。
我至今仍以这种方式使用 Type Atlas。当我发现 Agent 总是在同一个导航问题上浪费时间,或反复错过同一类信息时,我就会修改这个工具。
以下示例取自运行中的服务,针对一个测试用 monorepo,并通过实现进行回归检查。
安装
codex mcp add type-atlas -- npx --yes @type-atlas/mcp@latest
claude mcp add --scope user type-atlas -- npx --yes @type-atlas/mcp@latest
code --add-mcp '{"name":"type-atlas","command":"npx","args":["--yes","@type-atlas/mcp@latest"]}'
其他客户端都采用标准配置格式:
{
"mcpServers": {
"type-atlas": {
"command": "npx",
"args": ["--yes", "@type-atlas/mcp@latest"]
}
}
}
如果客户端启动服务时不使用你的 shell PATH,就无法按名称找到 npx;遇到这种情况,请提供 which npx 输出的绝对路径。在 Windows 上,如果客户端无法启动 npx.cmd 垫片,则需要设置 "command": "cmd",并将 "args": ["/c", "npx", "--yes", "@type-atlas/mcp@latest"] 作为参数。
客户端会在启动时读取 MCP 配置,因此配置后请重启。每次启动进程时,@latest 都会解析到最新版本;如果不想工具行为随版本变化,请固定版本。
search_code、related_code、investigate_code 和 search_dependency_code 会通过 uvx 运行语义索引,因此需要安装
uv。如果没有安装,这四个工具会报告缺少 uv,explore_symbol 会省略相关代码部分,其他功能不受影响。
建议
安装服务并不会改变 Agent 会选择使用什么工具。有些 Agent(包括 Claude)会组合使用 shell 允许的任何命令,每次都给出全新的理由,因此,光是列出几个应避免的命令并不能奏效。指令必须禁止整个类别,并说明例外情况。将以下内容添加到 AGENTS.md 或 CLAUDE.md:
Type Atlas MCP 是读取和浏览 TypeScript 与 JavaScript 代码的必备工具。这不是偏好问题。无论如何组合,都不能用任何 shell 命令替代,也不能直接读取文件。唯一有效的备用方案是服务已停止、调用出错,或文件既不是 TS 也不是 JS。
--require-intent
此可选标志要求在仓库搜索和工作区符号等广泛探索工具调用前提供一句决策说明。定向读取和语义查询不受影响,意图也不会回显在工具响应中。
工具调用结果
路径相对于工作区,坐标从 1 开始,因此一个回答中的位置可用作下一次调用的输入。编辑工具会返回补丁;不会替你写入任何内容。
以下所有内容都取自运行中的服务,针对
fixtures/ledger,由
场景测试套件捕获。该套件会重放相同的调用,并在结果有偏差时失败。这里没有手写内容;任何工具回答的变化都会在同一提交中反映到此文件。源文件是
README.mdoc。每个工具的页面都在
docs/tools中提供了更多示例。
list_files
在同一棵树中列出结构、行数和 git status,并使用编辑器已有的状态徽标字母。已删除文件也会显示一行,即使它们只存在于 git 的结果中。折叠的目录会说明其中包含什么,而不是直接消失。
Agent 的输入
tool: List files
workspace: fixtures/ledger
# working tree arranged: currency.ts edited · rounding.ts created · index.ts deleted
directory: packages/money
depth: 2
# answered in 57ms
响应
packages/money/
├ src/ · 3 changed
│ ├ currency.ts · 21 loc · M +2
│ ├ index.ts · D -12
│ ├ money.ts · 58 loc
│ ├ rounding-mode.ts · 15 loc
│ └ rounding.ts · 11 loc · U
├ tests/
│ ├ money.test.ts · 15 loc
│ └ rounding-parity.ts · 15 loc
├ package.json · 19 loc
└ tsconfig.json · 20 loc
inspect_symbol
在一次调用中查看悬停信息、定义、类型定义、实现、调用者、调用和引用。排除调用者和定义后,剩下的就是引用,因此每处使用只会列出一次。与分别调用这些工具相比,字符数减少 4 倍,往返次数减少 7 倍。
Agent 的输入
tool: Inspect symbol
workspace: fixtures/ledger
file: packages/accounts/src/journal.ts
symbol: Journal
# answered in 49ms
响应
Journal [class] · packages/accounts/src/journal.ts:24:14-24:21 · range 24:1-73:2 · packages/accounts/tsconfig.json
```typescript
class Journal<TMeta = undefined>
```
An append-only journal of balanced entries. `TMeta` carries whatever a
consumer attaches to each entry — an import batch id, an approval trail —
without the journal knowing its shape.
## Callers (4)
packages/accounts/tests/journal.test.ts
├ test("posts a balanced transfer through the overload") callback [function] 5:56-14:2 · calls 6:23-6:30
└ test("refuses an unbalanced entry") callback [function] 16:37-29:2 · calls 17:23-17:30
packages/reports/src/balance.ts
└ balancesAsOf [variable] 23:14-23:26 · range 23:14-51:2 · calls 24:12-24:19
packages/importers/src/csv.ts
└ importStatement [variable] 28:14-28:29 · range 28:14-47:2 · calls 29:12-29:19
## Mentions that are not calls (4 of 9 references · 5 relevant projects searched)
packages/accounts/tests/journal.test.ts:3:25-3:32: import { credit, debit, Journal, UnbalancedEntryError } from "../src/index.ts";
packages/accounts/src/index.ts:11:22-11:29: export { type Entry, Journal, UnbalancedEntryError } from "./journal.ts";
packages/reports/src/balance.ts:4:8-4:15: type Journal,
packages/importers/src/csv.ts:1:10-1:17: import { Journal, type Entry, credit, debit, type AccountPath } from "@ledger/accounts";
references lists all 9, with paging.
read_file
参数是一个数组,因此一次调用可以读取多个文件。默认情况下,正文会折叠为签名,标题会说明因此节省了多少行;设置 fold: false 即可返回正文。
Agent 的输入
tool: Read files
workspace: fixtures/ledger
file: ["packages/accounts/src/posting.ts","packages/money/src/rounding-mode.ts"]
# answered in 7ms
响应
2 files · 42 lines · 6 folded to signatures, pass fold: false for the bodies
=== packages/accounts/src/posting.ts · 32 lines ===
1 | import { type Money, negate } from "@ledger/money";
2 | import type { AccountPath } from "./account.ts";
3 |
4 | /**
5 | * One side of a journal entry. The discriminant is the bookkeeping side, so
6 | * every consumer's switch is checked for exhaustiveness by the compiler.
7 | */
8 | export type Posting =
9 | | { readonly side: "debit"; readonly account: AccountPath; readonly amount: Money }
10 | | { readonly side: "credit"; readonly account: AccountPath; readonly amount: Money };
11 |
12 | export const debit = (account: AccountPath, amount: Money): Posting => ({
13 | side: "debit",
14 | account,
15 | amount,
16 | });
17 |
18 | export const credit = (account: AccountPath, amount: Money): Posting => ({
19 | side: "credit",
20 | account,
21 | amount,
22 | });
23 |
24 | /** A posting's effect on a debit-normal running balance. */
25 | export const signedAmount = (posting: Posting): Money => {
| ... 26-31 folded
32 | };
=== packages/money/src/rounding-mode.ts · 15 lines ===
1 | /** How sub-minor precision resolves when a statement and the books disagree. */
2 | export enum RoundingMode {
3 | HalfUp = "half-up",
4 | HalfEven = "half-even",
5 | Truncate = "truncate",
6 | }
7 |
8 | /** Per-institution conventions, as observed in their exports. */
9 | const bankRounding: Readonly<Record<string, RoundingMode>> = {
10 | "first-national": RoundingMode.HalfEven,
11 | "harbor-credit": RoundingMode.HalfUp,
12 | };
13 |
14 | export const roundingModeOf = (bank: string): RoundingMode =>
15 | bankRounding[bank] ?? RoundingMode.HalfEven;
occurrences
当 Agent 知道标识符的名称,但不知道它所在的文件时,可从精确的标识符开始查找。标识符语法节点会激活相关项目;TypeScript 会解析规范声明和语义引用。同名符号会分开处理,重载会合并,无法解析的标识符会单独指出,而不会混入引用列表。
Agent 的输入
tool: Occurrences
workspace: fixtures/ledger
query: money
limit: 12
# answered in 244ms
响应
Identifiers: "money"
Scope: workspace · 33 project files
Showing 1–12 of 22 references · next offset: 12
=== money [function] · packages/money/src/money.ts:27:14 · 12/22 references shown ===
24 exact-name locations across 8 files · 1 without a workspace declaration
Locations without a workspace declaration (1):
packages/reconcile/src/matching.ts:24:37 — inside emptyRemainder · export const emptyRemainder = () => money(0, "USD");
packages/importers/src/csv.ts
├ 2:37 — at module level · import { type Currency, isCurrency, money, zero, format } from "@ledger/money";
└ 34:20 — inside amount · const amount = money(Math.abs(row.amountMinor), row.currency);
packages/money/src/index.ts
└ 8:3 — at module level · money,
packages/money/src/money.ts
├ 30:52 — inside zero · export const zero = (currency: Currency): Money => money(0n, currency);
├ 42:10 — inside add · return money(left.minorUnits + right.minorUnits, left.currency);
└ 45:48 — inside negate · export const negate = (value: Money): Money => money(-value.minorUnits, value.currency);
packages/reconcile/src/drift.ts
├ 5:18 — at module level · import { format, money, type Money } from "@ledger/money";
└ 21:17 — inside drift · return format(money(journalTotal - statementTotal(statement), "usd"));
packages/accounts/tests/journal.test.ts
├ 1:10 — at module level · import { money } from "@ledger/money";
├ 9:71 — inside test("posts a balanced transfer through the overload") callback · { from: "assets:bank:checking", to: "expenses:furniture", amount: money(24900, "USD") },
├ 23:34 — inside expect() callback · debit("expenses:travel", money(5000, "USD")),
└ 24:40 — inside expect() callback · credit("assets:bank:checking", money(500, "USD")),
search_code
当你无法猜出代码的名称时,可按代码的功能查找。结果按排名顺序返回,每项都附带其来源文件范围,因此下一次调用知道从哪里继续。实时回答还会为每项结果附上相关性百分比;下方未列出该百分比,因为其背后的嵌入分数因机器而异,而这些示例会逐字节比较。
Agent 的输入
tool: Search code
workspace: fixtures/ledger
query: walking an account up through each of its ancestor accounts
snippetLines: 6
# answered in 20ms
响应
Search: walking an account up through each of its ancestor accounts
5 matches · no identifier to anchor on, so these are ranked by meaning alone
=== 1 · packages/accounts/src/account.ts:21-35 ===
Structure: parentPath
Symbol: parentPath [variable] · selection 21:14-21:24 · range 21:14-24:2
21 | export const parentPath = (path: AccountPath): AccountPath | undefined => {
22 | const at = path.lastIndexOf(":");
23 | return at === -1 ? undefined : path.slice(0, at);
24 | };
25 |
26 | /** Every ancestor from root to the account itself: `a`, `a:b`, `a:b:c`. */
=== 2 · packages/reports/src/balance.ts:1-23 ===
Structure: BalanceLine
Symbol: BalanceLine [interface] · selection 11:18-11:29 · range 11:1-16:2
1 | import {
2 | type AccountPath,
3 | type Entry,
4 | type Journal,
5 | lineage,
6 | signedAmount,
=== 3 · packages/accounts/src/journal.ts:59-73 ===
Structure: Journal > history
Symbol: history [method] · selection 60:3-60:10 · range 60:3-64:4
59 | /** Entries touching an account, oldest first. */
60 | history(account: AccountPath): readonly Entry<TMeta>[] {
61 | return this.entries.filter((entry) =>
62 | entry.postings.some((posting) => posting.account === account),
63 | );
64 | }
=== 4 · packages/reports/src/statement.ts:1-11 ===
Structure: statementLine
Symbol: statementLine [variable] · selection 8:14-8:27 · range 8:14-11:2
1 | import { type Account, normalBalance } from "@ledger/accounts";
2 | import { format, type Money, negate } from "@ledger/money";
3 |
4 | /**
5 | * One rendered statement line. The sign follows the account's normal side:
6 | * a liability holding a credit balance reads as positive on its statement.
=== 5 · packages/accounts/src/posting.ts:1-24 ===
Structure: credit
Symbol: credit [variable] · selection 18:14-18:20 · range 18:14-22:3
1 | import { type Money, negate } from "@ledger/money";
2 | import type { AccountPath } from "./account.ts";
3 |
4 | /**
5 | * One side of a journal entry. The discriminant is the bookkeeping side, so
6 | * every consumer's switch is checked for exhaustiveness by the compiler.
diagnostics
按项目执行编译器自身的全程序检查,而不是逐文件检查。编辑一个文件通常会导致另一个文件出错,而此调用会找出那个文件。
Agent 的输入
tool: Diagnostics
workspace: fixtures/ledger
project: packages/reconcile
scope: project
# answered in 23ms
响应
Whole project · 6 problems in 2 files · 11 files checked · packages/reconcile/tsconfig.json
=== packages/reconcile/src/drift.ts ===
error typescript(2365) 16:33-16:52 — inside lines.reduce() callback
Operator '+' cannot be applied to types 'number' and 'Money'.
14 | /** Statement total, computed by someone who forgot Money is not a number.…
15 | export const statementTotal = (lines: readonly StatementLine[]): number =>
16 | lines.reduce((total, line) => total + line.amount, 0);
| ^^^^^^^^^^^^^^^^^^^
17 |
18 | /** Drift between the journal's view and the bank's view of one day. */
error typescript(2365) 20:77-20:91 — inside reduce() callback
Operator '+' cannot be applied to types 'import("packages/money/src/money").Money' and 'import("packages/money/src/money").Money'.
18 | /** Drift between the journal's view and the bank's view of one day. */
19 | export const drift = (postings: readonly Posting[], statement: readonly St…
20 | const journalTotal = postings.map(signedAmount).reduce((total, amount) =…
| ^^^^^^^^^^^^^^
21 | return format(money(journalTotal - statementTotal(statement), "usd"));
22 | };
error typescript(2362) 21:23-21:35 — inside drift
The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
19 | export const drift = (postings: readonly Posting[], statement: readonly St…
20 | const journalTotal = postings.map(signedAmount).reduce((total, amount) =…
21 | return format(money(journalTotal - statementTotal(statement), "usd"));
| ^^^^^^^^^^^^
22 | };
23 |
error typescript(2345) 21:65-21:70 — inside drift
Argument of type '"usd"' is not assignable to parameter of type 'Currency'.
19 | export const drift = (postings: readonly Posting[], statement: readonly St…
20 | const journalTotal = postings.map(signedAmount).reduce((total, amount) =…
21 | return format(money(journalTotal - statementTotal(statement), "usd"));
| ^^^^^
22 | };
23 |
=== packages/reconcile/src/matching.ts ===
error typescript(2304) 14:20-14:32 — inside amount
Cannot find name 'signedAmount'.
12 | const matched = new Map<Posting, StatementLine>();
13 | for (const posting of postings) {
14 | const amount = signedAmount(posting);
| ^^^^^^^^^^^^
15 | const line = lines.find(
16 | (candidate) => candidate.amount.minorUnits === amount.minorUnits,
error typescript(2304) 24:37-24:42 — inside emptyRemainder
Cannot find name 'money'.
22 |
23 | /** The zero of a matching pass, for currencies the statement never names.…
24 | export const emptyRemainder = () => money(0, "USD");
| ^^^^^
25 |
workspace_symbols
当你大致知道声明叫什么,但不知道它位于何处时,可在会话加载的所有项目中按名称查找声明。
Agent 的输入
tool: Workspace symbols
workspace: fixtures/ledger
file: packages/importers/src/statement-parser.ts
query: Parser
# answered in 100ms
响应
3 symbols matching Parser · 8 projects loaded · packages/importers/tsconfig.json
CsvStatementParser [class] · packages/importers/src/statement-parser.ts:25:1-35:2
FixedWidthStatementParser [class] · packages/importers/src/statement-parser.ts:41:1-64:2
StatementParser [class] · packages/importers/src/statement-parser.ts:7:1-23:2
file_references
哪些文件导入了此模块。无需先指定模块中的某个符号,即可回答模块级问题。
Agent 的输入
tool: File references
workspace: fixtures/ledger
file: packages/money/src/money.ts
# answered in 134ms
响应
packages/money/src/money.ts · referenced from 90 places · 6 relevant projects searched · packages/money/tsconfig.json
1-20 of 90 places · pass offset: 20 for the rest
packages/accounts/src/journal.ts
├ 1:10 — at module level
└ 53:15 — inside post
packages/money/src/index.ts
├ 3:3 — at module level
├ 4:3 — at module level
└ 5:3 — at module level
packages/money/tests/money.test.ts
├ 2:10 — at module level
├ 2:15 — at module level
├ 2:38 — at module level
├ 5:10 — inside test("adds amounts of one currency exactly") callback
├ 9:16 — inside expect() callback
├ 9:67 — inside test("refuses to combine currencies") callback
├ 13:10 — inside test("formats major and minor units per currency") callback
└ 14:10 — inside test("formats major and minor units per currency") callback
packages/reports/src/balance.ts
├ 8:10 — at module level
├ 34:9 — inside balancesAsOf
└ 41:28 — inside balancesAsOf
packages/reports/src/statement.ts
├ 2:10 — at module level
└ 10:40 — inside statementLine
packages/rules/src/builtin.ts
├ 2:10 — at module level
└ 28:58 — inside closedPeriodsBalance
软件包
| 软件包 | 作用 |
|---|---|
@type-atlas/mcp | MCP 服务 |
@type-atlas/core | 无头代码智能 API |
@type-atlas/language-server | core 软件包驱动的、基于 Volar 的语言服务 |
开发
vp install
vp run check
vp run check:distribution
CONTRIBUTING.md 介绍了变更和发布流程。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。