Skip to main content
Glama
SiroSuzume

MCP ts-morph Refactoring Tools

by SiroSuzume

find_unused_exports_by_tsmorph

Find exported symbols unreferenced outside their declaring file. Identifies dead code candidates across TypeScript projects using ts-morph static analysis.

Instructions

[ts-morph] List exports that have no references outside their declaring file across the project. Read-only.

When to use

  • Hunting for dead code candidates after a refactor or migration.

  • Auditing a module's surface area: which exports does nobody actually consume?

  • Pre-deletion safety check before manually removing exports — combine with find_references_by_tsmorph to double-confirm.

When NOT to use

  • You want a single symbol's references — use find_references_by_tsmorph.

  • Single-file unused locals — tsc --noUnusedLocals is faster.

Detection scope

Reports:

  • export function/class/const/let/var/enum/interface/type ... (inline export keyword)

  • export default function/class ... and export default <Identifier>

  • export = <Identifier> (CommonJS)

Detection algorithm

For each candidate identifier, findReferencesAsNodes() is run and the following references are excluded before deciding "unused":

  • References inside the SAME file as the declaration (internal use does not count).

  • References inside any ExportDeclaration (pure re-export sites like export { x } from "./y" or export *). This means a symbol re-exported only via a barrel — with nothing actually consuming the barrel — IS reported as unused.

  • References in node_modules.

If 0 references remain, the export is reported.

Known limitations (this tool returns CANDIDATES, not verdicts)

Static analysis cannot see:

  • Dynamic require() / import() resolved from runtime strings.

  • File-system / convention based routing (Next.js page.tsx, Remix routes, etc.). Pass these as entryPoints.

  • Symbols looked up via reflection or string keys.

  • Pure local re-exports (export { x } without from) where x is declared by a separate const x = ... in the same file — this form is not enumerated.

  • Mixed function + namespace declarations may be partially missed.

Default exports are high false-positive

export default <Identifier> / export = <Identifier> (shown with the [default] tag) are prone to FALSE POSITIVES: findReferencesAsNodes runs on the local identifier and often fails to connect to import Foo from "./mod" default-import sites. A default export reported here with textHits well above 0 is almost certainly actually used. Treat [default] candidates as low confidence and always confirm with find_references_by_tsmorph.

Always verify a candidate with find_references_by_tsmorph before deletion.

Options

  • tsconfigPath: absolute path to tsconfig.json.

  • entryPoints: list of absolute file paths whose exports should be skipped (treat as public API). Reference sites IN these files still count as "used" automatically.

  • excludeFilePatterns: substrings; any file whose absolute path includes() a pattern is not scanned. Use this for test files (e.g. ".test."), generated dirs, etc.

  • maxResults: cap on number of reported entries. Default 100. When reached, scanning stops and truncated becomes true — narrow scope with the filters above and retry.

Output modes (responseFormat)

  • "list" (default): one line per candidate (format below).

  • "summary": aggregate counts for the WHOLE project — total, delete-safety split (deletable vs unexport-only), default-export count, and breakdowns by kind and by directory. On large repos the per-line list easily blows past the response size limit, so start with "summary" to see where dead code clusters, then narrow with entryPoints / excludeFilePatterns and switch to "list" for exact locations. (summary scans the whole project regardless of maxResults.)

Result format (list mode)

A bullet list of candidates with file:line:column, symbol name, declaration kind, a [default] tag for default exports, textHits=N, and sameFileRefs=N.

sameFileRefs — decides delete vs. unexport (read this first)

Every reported export is, by definition, unreferenced OUTSIDE its declaring file. sameFileRefs tells you whether it is still used INSIDE that file (declaration itself and re-export sites excluded), which determines the safe action:

  • sameFileRefs=0: not used anywhere, including its own file → truly dead, safe to delete the whole declaration (combine with textHits=0 for highest confidence).

  • sameFileRefs=1+: used within its own file → only the export keyword is unnecessary. Remove export, but KEEP the declaration — deleting it breaks the in-file references.

Deleting every reported declaration blindly will break the build: the majority are often sameFileRefs=1+ (over-exported but internally used).

textHits — text-occurrence triage hint

textHits is the number of word-boundary occurrences of the export's name in OTHER source files (declaring file excluded — so it says nothing about same-file usage; use sameFileRefs for that):

  • textHits=0: no OTHER file mentions the name. Does NOT by itself mean deletable — still check sameFileRefs.

  • textHits=1+: the name appears as a string literal, JSX tag, dynamic import().then(m => m.X), or comment. Verify with find_references_by_tsmorph before deleting. Short names (e.g. a, id) match incidentally — discount accordingly.

Trailing line reports Scanned files: N and Truncated: bool.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
tsconfigPathYesAbsolute path to the project's tsconfig.json.
entryPointsNoAbsolute file paths to treat as public API. Exports declared here are skipped.
excludeFilePatternsNoSubstrings; files whose absolute path includes any of these are not scanned.
maxResultsNoCap on reported entries (list mode). Default 100. Ignored intent in "summary" mode, which scans the whole project.
responseFormatNo"list" (default): one line per candidate. "summary": aggregate counts (delete-safety / kind / directory) for the WHOLE project — use this first on large repos to avoid huge output, then narrow with entryPoints/excludeFilePatterns and switch to "list".list
expandNamespaceImportsNoDefault true. Inject synthetic named imports into files containing `import * as ns from "./mod"` so that exports of the target module register as 'used' even when consumed only via `{ ...ns }` spread or other escaping patterns. Set to false if you want raw findReferences semantics.
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Despite no annotations, the description thoroughly discloses behavioral traits: read-only, detection algorithm, exclusions, limitations, false positive handling, output modes, and interpretation of sameFileRefs and textHits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with sections, bullet points, and clear hierarchy. Every sentence provides useful information without unnecessary fluff, balancing detail with readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (6 params, no output schema), the description covers all necessary aspects: algorithm, limitations, result interpretation, and practical usage advice. It compensates for missing output schema by explaining the result format in detail.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema coverage, the description still adds significant value by explaining parameter behavior in context (e.g., responseFormat usage recommendation, maxResults defaults, expandNamespaceImports effect).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: list exports with no external references across a project. It uses specific verbs and resources, distinguishing it from siblings like find_references_by_tsmorph.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit 'When to use' and 'When NOT to use' sections with specific scenarios and alternatives (e.g., tsc --noUnusedLocals). Offers clear guidance on combining with find_references_by_tsmorph.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/SiroSuzume/mcp-ts-morph'

If you have feedback or need assistance with the MCP directory API, please join our Discord server