npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@0xdeafcafe/tslsp-mcp

v0.1.0

Published

MCP server exposing the TypeScript language server (tsgo) — rename, references, definitions, hover, symbols, diagnostics.

Readme

tslsp-mcp

npm CI node

claude finds references by grepping. claude renames things by find-and-replacing. this is fine until your symbol is called User or get or value, at which point it confidently rewrites half your codebase and tells you it's done. thanks, gas-lightyear.

how do real editors function? they ask the typescript language server, which actually understands what's a reference vs what's just a string. tslsp-mcp gives claude that same superpower over an MCP server or a regular CLI. rename is type-aware. references are real references. moving a file rewrites every import that pointed at it. outline is the LSP's structural view, not "read 200 lines and hope."

it spawns tsgo, microsoft's native go port of tsserver, per tsconfig.json it sees, keeps it warm, and routes tool calls to the right one. one process per project, lazy-spawned, not one per request.

designed in my head, built by claudus, tested on your codebase, cheers.

you need

  • node 22+
  • a typescript project (anything with a tsconfig.json)
  • claude code, or any other MCP / skill-aware host

install

two flavours. pick whichever your agent likes — they expose the same tools.

CLI + skill

npm install -g @0xdeafcafe/tslsp-mcp
tslsp install --skills              # ~/.claude/skills/tslsp/SKILL.md
tslsp install --skills --project    # ./.claude/skills/tslsp (commit it)

the skill tells claude when to reach for tslsp instead of Grep/Edit/mv. tslsp --help lists every command; the agent can drive it raw from --help if you skip the skill.

MCP

claude mcp add -s user tslsp -- npx -y @0xdeafcafe/tslsp-mcp

-s user makes it available in every project. drop it (and run from a project dir) to scope to one repo.

prefer to run from source? clone, build, point claude at the built file:

git clone https://github.com/0xdeafcafe/tslsp-mcp.git
cd tslsp-mcp && pnpm install && pnpm run build
claude mcp add -s user tslsp node /absolute/path/to/tslsp-mcp/dist/index.js

make claude actually use it

claude won't reach for an MCP tool just because it exists. you have to tell it, and you have to be explicit about which built-in tool it replaces. tslsp install --skills drops a ready-made SKILL.md that does exactly that. if you'd rather paste it yourself, here's the block — works in ~/.claude/CLAUDE.md or a project's CLAUDE.md:

## TypeScript code intelligence (tslsp)

In any TS/JS project with a `tsconfig.json`, the `tslsp` tools are type-aware
and MUST be used instead of the built-in text tools for the operations below.
Text tools see strings; tslsp sees the program.

Names below are the MCP shape (`tslsp:foo`). With the CLI, replace `tslsp:foo`
with `tslsp foo` — same arguments, same output.

| Task                            | DO use                   | DO NOT use                              |
| ------------------------------- | ------------------------ | --------------------------------------- |
| Find every usage of a symbol    | `tslsp:references`       | `Grep`, `Glob`                          |
| Search for a symbol by name     | `tslsp:find_symbol`      | `Grep`                                  |
| Jump to a definition            | `tslsp:definition`       | `Grep` + `Read`                         |
| Jump to a value's *type*        | `tslsp:type_definition`  | `Grep` + `Read`                         |
| Find concrete implementations   | `tslsp:implementation`   | `Grep`                                  |
| Rename a symbol                 | `tslsp:rename`           | `Edit`, `MultiEdit`, find-and-replace   |
| Rename/move a file or folder    | `tslsp:rename_file`      | `mv` / `git mv` (won't update imports)  |
| Type / JSDoc for a symbol       | `tslsp:hover`            | `Read`                                  |
| Outline a file before reading   | `tslsp:outline`          | `Read` on the whole file                |
| Type errors after an edit       | `tslsp:diagnostics`      | `Bash` running `tsc` ad-hoc             |
| Trace callers / callees         | `tslsp:call_hierarchy`   | repeated `references` calls             |
| Organize imports / quick-fix    | `tslsp:code_action`      | manual edit                             |

Hard rules:

1. NEVER rename a TypeScript identifier with `Edit` or `MultiEdit`. Use
   `tslsp:rename`. Pass `dry_run: true` first when the symbol has many call
   sites; review the preview, then apply. This applies to every identifier —
   slice keys (`features.fooUi`), property names, enum members, the lot. If
   you find yourself string-editing a symbol "just for a couple of files"
   you have already failed the rule. For bulk renames (e.g. renaming a whole
   feature), enumerate symbols via `tslsp:outline` on each file in the folder
   first, then call `tslsp:rename` once per symbol — cheaper in tokens than
   grep+Read+Edit and safer (no false positives in comments / strings /
   unrelated identifiers).
2. NEVER `mv` or `git mv` a TypeScript file or folder. Use `tslsp:rename_file`
   — it walks every import that references the file and rewrites them. After
   the move you can still use `tslsp:rename` for any identifier inside.
3. NEVER `Grep` for a symbol name to find usages or definitions. Use
   `tslsp:references` or `tslsp:definition`. Grep matches strings in
   comments, in unrelated identifiers, in `.md` files — it lies.
4. Before reading a large file, call `tslsp:outline` first and use the line
   numbers to `Read` only the slices you need.
5. After non-trivial edits to a TS file, call `tslsp:diagnostics` on it to
   confirm it still type-checks before claiming the change is done.

Locator ergonomics: every position-taking tool accepts `{ symbol: "name" }`
(workspace search), `{ file, line, symbol }` (line scan), or full
`{ file, line, character }`. Use the cheapest form you have. Ambiguous
name-only queries return the candidate list; pick by file or line and re-call.

Batch: most read-only tools accept `symbols: ["a","b","c"]` (or `files: [...]`).
tslsp fans the requests out in parallel and labels each block with
`=== name ===`. One call beats N round-trips.

Fall back to the built-in text tools only for: string literals, comments,
non-TS files (Markdown, YAML, configs), or projects without a `tsconfig.json`.

tools

| tool | what it does | | ----------------- | ----------------------------------------------------------------------------------------------------- | | find_symbol | workspace symbol search by name. returns path:line kind name. | | references | every reference to a symbol. takes a locator or a symbols: [...] batch. | | definition | jump to where a symbol is defined. batches via symbols. | | type_definition | jump to a value's type declaration (vs. its value declaration). batches via symbols. | | implementation | concrete implementations of an interface/abstract member. batches via symbols. | | rename | type-aware rename across every file. dry_run: true previews without writing. | | rename_file | move a file or folder; updates every import that referenced it. folders walked recursively. | | hover | type signature + JSDoc for a symbol. batches via symbols. | | outline | indented declaration outline. files: [...] batches. | | diagnostics | type errors. file, files: [...], or omit (aggregate across every open file). | | call_hierarchy | callers and callees of a function. direction: incoming / outgoing / both. | | code_action | list quick-fixes / refactors / organize-imports; pass apply: N to apply by index. |

symbol locator

every position-taking tool takes one of three shapes, in priority order:

{ file, line, character }   // explicit LSP position
{ file, line, symbol }      // server scans the line for the identifier
{ symbol }                  // workspace symbol search; errors with candidates if ambiguous

LLMs know line numbers and symbol names but not character columns. modes 2 and 3 cover the gap.

batching

most read-only tools take an array variant. fanned out in parallel, results labeled:

tslsp:hover         { symbols: ["User", "Repository", "AuthService"] }
tslsp:outline       { files: ["src/api.ts", "src/db.ts"] }
tslsp:diagnostics   { files: ["src/a.ts", "src/b.ts"] }
tslsp hover       --symbols User,Repository,AuthService
tslsp outline     src/api.ts src/db.ts
tslsp diagnostics --files src/a.ts,src/b.ts

one tool call, N parallel LSP queries, one return.

CLI

tslsp find-symbol User                          # positional == --query
tslsp references --symbol User
tslsp definition --symbol User
tslsp rename --symbol oldName --new-name newName --dry-run
tslsp rename-file src/old.ts src/new.ts --dry-run
tslsp rename-file src/components src/widgets   # folders supported
tslsp hover --symbol User
tslsp outline src/api.ts
tslsp diagnostics --file src/x.ts
tslsp call-hierarchy --symbol handleRequest --direction incoming
tslsp code-action --file src/x.ts --kind source.organizeImports
tslsp code-action --file src/x.ts --kind source.organizeImports --apply 0

tslsp --help                  # all commands
tslsp <command> --help        # per-command flags
tslsp install --skills        # drop SKILL.md into ~/.claude/skills/tslsp/
tslsp mcp                     # start the MCP server over stdio

how it works

claude → stdio → tslsp-mcp → tsgo (project A)
                           → tsgo (project B)
                           → ...

on first tool call against a file, it walks up to the nearest tsconfig.json, spawns tsgo there, opens a seed file so the workspace symbol index populates, and caches the process. subsequent calls reuse it. when you edit files via rename or rename_file, it pushes didClose/didOpen + workspace/didChangeWatchedFiles (and didRenameFiles for moves) so the index reprojects.

gotchas

  • pins @typescript/native-preview to a specific dev build. tsgo moves fast and dev builds shift. bump the version in package.json deliberately.
  • if you have an older homebrew-installed tsgo on your PATH, the MCP ignores it and uses the npm-pinned one. earlier versions had behavior we explicitly don't want.
  • rename and rename_file write to disk. dry_run: true previews first; git diff is your friend either way.
  • one tsgo process per tsconfig.json root. monorepos with many tsconfigs spawn many tsgos lazily; first hit per project pays project-load cost (~50ms on small, more on large).
  • the CLI spawns a fresh tsgo per invocation. fine for one-off calls; for a tight refactor loop, the MCP server (warm process) is faster.
  • set TSLSP_VERBOSE=1 (or TSLSP_MCP_VERBOSE=1) to forward tsgo's stderr.