Skip to main content
Glama

npm node license

Type Atlas — это инструмент, который я использую во всех своих проектах на TypeScript для всех задач навигации по коду. Большинство этих проектов — монорепозитории. Некоторые из них достаточно большие и сложные, чтобы понимание того, как изменение вписывается в остальную систему, было реальной частью работы. Этот инструмент был спроектирован как полная замена стандартной методологии навигации по коду для агентов.

Я уже несколько месяцев итерирую этот инструмент, опираясь на то, как мои собственные кодинг-агенты реально работают в моих проектах. Большая часть того, что делает Type Atlas, существует потому, что я постоянно сталкивался с одними и теми же проблемами:

  • Агенты рассуждают, исходя из неполного представления о системе. Они могут понять файл, который нашли, но упускают окружающий код, определяющий, как этот файл следует использовать.

  • Агенты пересоздают то, что уже существует. Возможность уже есть в репозитории, но агент её не находит, потому что не знает, как она называется.

  • Агенты часто читают либо слишком мало кода (Claude), либо слишком много (Codex). Слишком мало — и они принимают решения без достаточного контекста. Слишком много — и контекстное окно заполняется целыми файлами и деталями реализации, которые никогда не имели значения для задачи.

  • Агенты постоянно останавливаются, чтобы запустить проверку типов, хотя IDE уже показывала бы ошибки. Это добавляет задержку на протяжении всей реализации и отодвигает обратную связь дальше, чем нужно.

  • Агенты по сути действуют вслепую. Навигация по строковому поиску никогда не даёт им прочной внутренней карты кодовой базы. Они вынуждены принимать решения по реализации, исходя из фрагментов файлов и совпадений, которые им удалось получить, при этом важная структура и известная компилятору информация остаются недоступными.

По мере роста проектов эти проблемы усугубляются и начинают напрямую сказываться на качестве кода, который пишут агенты.

Семантическая навигация по коду

Кодинг-агенты по умолчанию перемещаются по коду через чтение файлов и строковый поиск. Это даёт им исходный текст и оставляет модели задачу реконструировать связи, которые языковой сервис TypeScript уже знает.

Type Atlas даёт агенту прямой доступ к этой семантической информации:

  • Символ разрешается в его фактическое определение и ссылки, а не в каждое вхождение того же текста.

  • Вызывающие и реализации определяются по их отношению к символу.

  • Выведенные типы берутся из языкового сервиса, а не реконструируются из соседнего исходного кода.

  • Результаты сохраняют привязку к диапазону исходного кода и владеющему проекту TypeScript.

Текстовое совпадение по-прежнему полезно, когда агент ищет именно текст. Но это слабая замена семантической навигации, когда вопрос касается самой программы.

Найти то, что уже существует

В больших кодовых базах есть полезный код, о котором агент не может знать по имени. Строковый поиск работает лучше всего, когда агент уже знает достаточно словаря, чтобы сформулировать запрос.

Type Atlas даёт другие пути входа:

  • Агент может описать поведение на естественном языке и найти код по тому, что он делает.

  • Найденный результат ведёт к реальному символу и точному диапазону исходного кода.

  • От этого символа агент может проследить фактические связи по кодовой базе, а не угадывать другой идентификатор для поиска.

Это особенно полезно в больших монорепозиториях. Существующие хелперы и устоявшиеся реализации легче обнаружить до того, как агент решит, что нужно создать ещё одну.

Диагностика во время обычной работы

Разработчик в IDE видит обратную связь компилятора во время работы. Кодинг-агенты обычно получают эту обратную связь, останавливая реализацию, чтобы запустить команду проверки типов, а затем ожидая результат.

Type Atlas переносит большую часть этой обратной связи в работу, которую агент уже выполняет:

  • Релевантные диагностики могут приходить вместе с обычными ответами по интеллектуальному анализу кода.

  • Ошибки появляются, пока затронутый код всё ещё находится в текущем рабочем контексте агента.

  • Неверное предположение о типе может быть поймано до того, как оно превратится в несколько зависимых правок.

Я по-прежнему использую полные проверки типов для верификации. Но они не должны быть основным способом, которым агент узнаёт об ошибках во время работы.

Ответы построены для контекста модели

Уменьшение ответа полезно только тогда, когда удалённая информация была не нужна. Модели также используют организацию того, что осталось.

Type Atlas рассматривает структуру как часть информации:

  • Метки делают роль результата явной.

  • Группировка держит связанные факты вместе.

  • Границы файлов не дают несвязанному исходному коду смешиваться.

  • Местоположения в исходном коде остаются привязанными к тому, что они описывают.

  • Деревья сохраняют свою иерархию, а не превращаются в плоскую последовательность.

  • Диагностики сохраняют исходный код, необходимый для их понимания.

Тот же принцип определяет, что опускается. Тела функций могут оставаться свёрнутыми, когда сигнатуры достаточно. Повторная сериализация и несвязанный исходный код не должны занимать контекстное окно только потому, что они были доступны.

Цель — полезная плотность информации. Меньше токенов важно, но удаление структуры, которая помогает модели понимать эти токены, лишило бы смысла.

Информация для следующего решения

Каждый вызов инструмента — часть процесса рассуждений агента. Хороший ответ должен отвечать на текущий вопрос, оставляя агента в лучшей позиции для решения, что исследовать дальше.

Type Atlas держит полезную последующую информацию рядом с результатом, который её выявил:

  • Символ может прийти с отношениями, необходимыми для понимания того, как он участвует в кодовой базе.

  • Структура репозитория может нести количество строк и состояние рабочего дерева вместе с самими файлами.

  • Результаты поиска включают конкретные диапазоны исходного кода, по которым можно сразу перейти.

  • Контекст проекта остаётся привязанным, когда агент переходит от одного результата к другому.

Это даёт агенту лучшие доказательства на каждой развилке его исследования. Он может следовать отношениям, которые реально существуют в программе, вместо того чтобы рассматривать каждое текстовое совпадение как одинаково значимую зацепку.

Преимущество — более качественная навигация. Каждый шаг сохраняет больше информации, необходимой для выбора следующего.

Осведомлённость о проекте и области действия

Вопросы TypeScript зависят от контекста проекта. Это особенно важно в монорепозитории, где ответ может быть корректным внутри одного проекта, но неполным для всего репозитория.

Type Atlas сохраняет эти границы видимыми:

  • Файлы разрешаются через проект TypeScript, которому они принадлежат.

  • Результаты указывают область проекта, из которой они получены, когда эта область важна.

  • Счётчики делают размер результата явным.

  • Ограничения указываются, когда ответ покрывает меньше, чем весь репозиторий.

  • Местоположения в исходном коде можно напрямую передавать в последующие вызовы.

Агент получает достаточно информации, чтобы понять, что на самом деле покрывает ответ, прежде чем полагаться на него.

Создано из ежедневного использования агентами

Я использую Type Atlas со своими кодинг-агентами каждый день во всех своих проектах на TypeScript. Текущее поведение возникло из многократного использования.

Многие решения в дизайне можно напрямую проследить до повторяющегося поведения агентов:

  • Чтения сворачиваются, потому что агенты тратили контекст на тела, которые им не нужны.

  • Диагностики путешествуют с обычными ответами, потому что повторные команды проверки типов тратили время реализации.

  • Семантические отношения группируются, потому что агенты постоянно реконструировали одну и ту же информацию через отдельные вызовы.

  • Поиск кода на естественном языке существует, потому что полезный код часто имеет имя, которое агент никогда не смог бы вывести из задачи.

Так я и работаю над Type Atlas. Когда я продолжаю видеть, что агенты тратят время на одну и ту же проблему навигации или постоянно упускают один и тот же вид информации, я меняю инструмент.

Примеры ниже получены от работающего сервера на фикстурном монорепозитории и проверены на регрессии с помощью реализации.

Установка

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"]
    }
  }
}

Клиент, который запускает серверы без вашего 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 теряет раздел связанного кода, а остальное не затрагивается.

Рекомендуется

Установка сервера не меняет того, к чему тянется агент. Некоторые агенты, включая Claude, соберут всё, что позволяет их оболочка, соединят это в цепочку и каждый раз будут выдавать новое обоснование, поэтому перечисление нескольких команд, которых следует избегать, не работает. Инструкция должна исключить всю категорию и назвать исключения. Добавьте это в AGENTS.md или CLAUDE.md:

Type Atlas MCP — обязательный инструмент для чтения и навигации по коду на TypeScript и JavaScript. Это не предпочтение. Никакая команда оболочки не является приемлемой заменой, из чего бы она ни состояла, и обычное чтение файла тоже. Единственные допустимые исключения — сервер не работает, вызов завершился ошибкой или файл не является ни TS, ни JS.

--require-intent

Этот опциональный флаг требует одно решающее предложение для широких инструментов исследования, таких как поиск по репозиторию и символы рабочей области. Целевые чтения и семантические запросы остаются без изменений, и намерение никогда не отражается в ответах инструментов.

Related MCP server: agent-workspace-mcp

Результаты вызовов инструментов

Пути указываются относительно рабочей области, координаты — с единицы, поэтому местоположение из одного ответа является корректным вводом для следующего вызова. Инструменты редактирования возвращают патчи; ничего не записывается за вас.

Всё ниже получено от работающего сервера на fixtures/ledger с помощью набора сценариев, который воспроизводит те же вызовы и падает при расхождении. Здесь нет ничего написанного вручную, и изменение ответов инструментов меняет этот файл в том же коммите. Исходник — README.mdoc. У каждого инструмента есть страница с дополнительными примерами в docs/tools.

list_files

Структура, количество строк и git status в одном дереве, с буквами-бейджами, которые уже используют редакторы. Удалённые файлы получают строку, даже если они существуют только в ответе git. Свёрнутые каталоги говорят, что они содержат, а не исчезают.

Ввод агента

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 раз меньше раундов.

Ввод агента

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 возвращает их.

Ввод агента

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

Literal text, grouped by file, with the number of files scanned. The semantic tools rank what exists, which is useless for confirming a token is gone after a teardown; a zero here comes with the same scan count, so it means something.

Agent's Input

tool: Occurrences
workspace: fixtures/ledger
text: signedAmount

# answered in 12ms

Response

"signedAmount" occurs 12 times in 7 files · 67 files scanned under the workspace · 1 file of declared build output not scanned.

packages/accounts/src/index.ts:12:39 · export { credit, debit, type Posting, signedAmount } from "./posting.ts";
packages/accounts/src/journal.ts
├  3:39  · import { credit, debit, type Posting, signedAmount } from "./posting.ts";
└  52:12 · .map(signedAmount)
packages/accounts/src/posting.ts:25:14 · export const signedAmount = (posting: Posting): Money => {
packages/reconcile/src/drift.ts
├  4:24  · import { type Posting, signedAmount } from "@ledger/accounts";
└  20:37 · const journalTotal = postings.map(signedAmount).reduce((total, amount) => total + amount);
packages/reconcile/src/matching.ts
├  1:55  · // DELIBERATELY BROKEN — the imports for `money` and `signedAmount` are
└  14:20 · const amount = signedAmount(posting);
packages/reports/src/balance.ts
├  6:3   · signedAmount,
└  34:57 · add(own.get(posting.account) ?? zero(currency), signedAmount(posting)),
packages/rules/src/builtin.ts
├  1:10  · import { signedAmount } from "@ledger/accounts";
└  26:12 · .map(signedAmount)

search_code

Finds code by what it does, for when you cannot guess what it is called. Hits come back in rank order, each carrying the file range it came from, so the next call has somewhere to go. Live answers also carry a relevance percentage per hit; it is left out below because the embedding scores behind it differ between machines and these cases are compared byte for byte.

Agent's Input

tool: Search code
workspace: fixtures/ledger
query: walking an account up through each of its ancestor accounts
snippetLines: 6

# answered in 20ms

Response

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

The compiler's own whole-program check, per project, not a per-file pass. An edit in one file usually breaks a different one, and this is the call that finds that file.

Agent's Input

tool: Diagnostics
workspace: fixtures/ledger
file: packages/reconcile/src/drift.ts

# answered in 23ms

Response

packages/reconcile/src/drift.ts · 4 problems · packages/reconcile/tsconfig.json

=== packages/reconcile/src/drift.ts ===

error ts(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 ts(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 ts(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 |

error ts(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 |

workspace_symbols

Find a declaration by name across every project the session has loaded, when you know roughly what it is called and nothing about where it lives.

Agent's Input

tool: Workspace symbols
workspace: fixtures/ledger
file: packages/importers/src/statement-parser.ts
query: Parser

# answered in 100ms

Response

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

Who imports this module. The module-level question, answered without picking a symbol inside it first.

Agent's Input

tool: File references
workspace: fixtures/ledger
file: packages/money/src/money.ts

# answered in 134ms

Response

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

Packages

Package

Role

@type-atlas/mcp

the MCP server

@type-atlas/core

headless code-intelligence API

@type-atlas/language-server

the Volar-based language server the core package drives

Development

vp install
vp run check
vp run check:distribution

CONTRIBUTING.md has the change and release process.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Exposes TypeScript Language Server Protocol functionality to AI agents, enabling them to query types at specific positions, find definitions and references, get diagnostics, run type tests, and type-check inline code just like in an IDE.
    9
    614 npm
    3
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    A TypeScript-aware MCP server that provides coding agents with repository discovery, code intelligence, and web project context for local codebases. It enables deep symbol navigation, diagnostic reporting, and structural analysis of monorepos without requiring full IDE integration.
    7
    15 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    F
    maintenance
    Bridges the Model Context Protocol with Language Server Protocol to provide AI agents with persistent access to code intelligence features including navigation, diagnostics, refactoring, and completion across 7+ programming languages.
    1,932 npm
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables AI coding agents to interact with TypeScript projects through compiler-level code intelligence, providing tools for navigation, type information, diagnostics, refactoring, and semantic search.
    29
    225 npm
    3
    Apache 2.0