-
Notifications
You must be signed in to change notification settings - Fork 0
Add mcp-ts-introspect: TypeScript package introspection tool #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| # TypeScript Introspect Tool | ||
|
|
||
| A command-line tool for introspecting TypeScript exports from packages, source code, or projects. Can also run as an MCP (Model Context Protocol) server. | ||
|
|
||
| Forked from https://github.com/t3ta/ts-introspect-mcp-server/tree/master/src | ||
|
|
||
| ## Usage | ||
|
|
||
| ```bash | ||
| tools mcp-ts-introspect [options] | ||
| ``` | ||
|
|
||
| ## Modes | ||
|
|
||
| The tool supports three introspection modes: | ||
|
|
||
| ### 1. Package Mode | ||
|
|
||
| Introspect TypeScript exports from npm packages: | ||
|
|
||
| ```bash | ||
| tools mcp-ts-introspect -m package -p typescript -t "Type.*" | ||
| tools mcp-ts-introspect -m package -p @types/node --limit 20 | ||
| ``` | ||
|
|
||
| ### 2. Source Mode | ||
|
|
||
| Analyze TypeScript source code directly: | ||
|
|
||
| ```bash | ||
| tools mcp-ts-introspect -m source -s "export function hello() { return 'world'; }" | ||
| ``` | ||
|
|
||
| ### 3. Project Mode | ||
|
|
||
| Analyze an entire TypeScript project: | ||
|
|
||
| ```bash | ||
| tools mcp-ts-introspect -m project --project ./my-project | ||
| tools mcp-ts-introspect -m project --search-term "^get" --limit 20 | ||
| ``` | ||
|
|
||
| ## Options | ||
|
|
||
| - `-m, --mode MODE` - Introspection mode: package, source, or project | ||
| - `-p, --package NAME` - Package name to introspect (for package mode) | ||
| - `-s, --source CODE` - TypeScript source code to analyze (for source mode) | ||
| - `--project PATH` - Project path to analyze (for project mode, defaults to current directory) | ||
| - `--search-paths PATH` - Additional paths to search for packages (can use multiple times) | ||
| - `-t, --search-term TERM` - Filter exports by search term (supports regex) | ||
| - `--cache` - Enable caching (default: true) | ||
| - `--cache-dir DIR` - Cache directory (default: .ts-morph-cache) | ||
| - `--limit NUM` - Maximum number of results to return | ||
| - `-o, --output DEST` - Output destination: file, clipboard, or stdout (default: stdout) | ||
| - `-v, --verbose` - Enable verbose logging | ||
| - `-h, --help` - Show help message | ||
| - `--mcp` - Run as MCP server | ||
|
|
||
| ## Examples | ||
|
|
||
| ### Interactive Mode | ||
|
|
||
| Run without arguments for interactive prompts: | ||
|
|
||
| ```bash | ||
| tools mcp-ts-introspect | ||
| ``` | ||
|
|
||
| ### Find specific exports in a package | ||
|
|
||
| ```bash | ||
| tools mcp-ts-introspect -m package -p typescript -t "^create" --limit 10 | ||
| ``` | ||
|
|
||
| ### Analyze source code and copy to clipboard | ||
|
|
||
| ```bash | ||
| tools mcp-ts-introspect -m source -s "$(cat myfile.ts)" -o clipboard | ||
| ``` | ||
|
|
||
| ### Analyze current project | ||
|
|
||
| ```bash | ||
| tools mcp-ts-introspect -m project --search-term "Controller$" -o exports.json | ||
| ``` | ||
|
|
||
| ## Features | ||
|
|
||
| - **Package Resolution**: Supports npm, yarn, and pnpm package managers | ||
| - **Caching**: Speeds up repeated lookups with file-based caching | ||
| - **Filtering**: Use regex patterns to filter exports by name, type, or description | ||
| - **Multiple Output Formats**: Output to stdout, clipboard, or file | ||
| - **JSDoc Support**: Extracts descriptions from JSDoc comments | ||
| - **TypeScript Support**: Full TypeScript type information extraction | ||
|
|
||
| ## MCP Server Mode | ||
|
|
||
| Run the tool as an MCP server to integrate with AI assistants: | ||
|
|
||
| ```bash | ||
| tools mcp-ts-introspect --mcp | ||
| ``` | ||
|
|
||
| ### MCP Configuration | ||
|
|
||
| Add to your Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json`): | ||
|
|
||
| ```json | ||
| { | ||
| "mcpServers": { | ||
| "ts-introspect": { | ||
| "command": "tools", | ||
| "args": ["mcp-ts-introspect", "--mcp"] | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Available MCP Tools | ||
|
|
||
| When running as an MCP server, the following tools are available: | ||
|
|
||
| 1. **introspect-package** - Introspect TypeScript exports from an npm package | ||
|
|
||
| - `packageName` (required): The npm package name | ||
| - `searchPaths`: Additional search paths | ||
| - `searchTerm`: Regex filter pattern | ||
| - `cache`: Enable caching (default: true) | ||
| - `cacheDir`: Cache directory | ||
| - `limit`: Maximum results | ||
|
|
||
| 2. **introspect-source** - Analyze TypeScript source code | ||
|
|
||
| - `sourceCode` (required): TypeScript source to analyze | ||
| - `searchTerm`: Regex filter pattern | ||
| - `limit`: Maximum results | ||
|
|
||
| 3. **introspect-project** - Analyze a TypeScript project | ||
| - `projectPath`: Path to project (defaults to current directory) | ||
| - `searchTerm`: Regex filter pattern | ||
| - `cache`: Enable caching (default: true) | ||
| - `cacheDir`: Cache directory | ||
| - `limit`: Maximum results | ||
|
|
||
| ## Notes | ||
|
|
||
| - The tool requires TypeScript declaration files (.d.ts) for package introspection | ||
| - Caching is enabled by default and stores results for 7 days | ||
| - Use verbose mode (-v) for debugging and additional logging | ||
| - When running as MCP server, logs are written to the GenesisTools log directory | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,53 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { existsSync } from "node:fs"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { mkdir } from "node:fs/promises"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { join } from "node:path"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import logger from "../logger"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { CacheEntry, ExportInfo } from "./types"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const CACHE_TTL = 7 * 24 * 60 * 60 * 1000; // 7 days | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function loadCache(cacheDir: string, key: string): Promise<ExportInfo[] | null> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const cacheFile = join(cacheDir, `${key}.json`); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!existsSync(cacheFile)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const cacheData = (await Bun.file(cacheFile).json()) as CacheEntry; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check if cache is still valid | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const age = Date.now() - cacheData.timestamp; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (age > CACHE_TTL) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info(`Cache for ${key} is expired (${Math.floor(age / 1000 / 60 / 60)} hours old)`); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+16
to
+24
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add validation for cache data structure. The 🛡️ Proposed fix with validation try {
- const cacheData = (await Bun.file(cacheFile).json()) as CacheEntry;
+ const cacheData = await Bun.file(cacheFile).json();
+
+ // Validate cache structure
+ if (!cacheData || typeof cacheData.timestamp !== "number" || !Array.isArray(cacheData.exports)) {
+ logger.warn(`Invalid cache structure for ${key}`);
+ return null;
+ }
// Check if cache is still valid
const age = Date.now() - cacheData.timestamp;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info(`Loaded cache for ${key} (${Math.floor(age / 1000 / 60)} minutes old)`); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return cacheData.exports; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.warn(`Failed to load cache for ${key}: ${error}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function saveCache(cacheDir: string, key: string, exports: ExportInfo[]): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // Ensure cache directory exists | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!existsSync(cacheDir)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await mkdir(cacheDir, { recursive: true }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const cacheFile = join(cacheDir, `${key}.json`); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const cacheEntry: CacheEntry = { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| exports, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| timestamp: Date.now(), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| await Bun.write(cacheFile, JSON.stringify(cacheEntry, null, 2)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info(`Saved cache for ${key} (${exports.length} exports)`); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.warn(`Failed to save cache for ${key}: ${error}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // Don't throw - caching is optional | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,110 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { type Symbol as MorphSymbol, Node, type SourceFile } from "ts-morph"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check if ts-morph is declared in package.json
echo "=== Checking package.json for ts-morph dependency ==="
cat package.json | jq '.dependencies["ts-morph"] // .devDependencies["ts-morph"] // "NOT FOUND"'Repository: genesiscz/GenesisTools Length of output: 131 Add The file imports 🧰 Tools🪛 GitHub Actions: CI[error] 1-1: Cannot find module 'ts-morph' or its corresponding type declarations. 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import logger from "../logger"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { ExportInfo } from "./types"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function extractExports(sourceFile: SourceFile): Promise<ExportInfo[]> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const exports: ExportInfo[] = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const exportedSymbols = sourceFile.getExportSymbols(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info(`Extracting exports from ${sourceFile.getFilePath()}, found ${exportedSymbols.length} export symbols`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const symbol of exportedSymbols) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const exportInfo = processSymbol(symbol); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (exportInfo) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exports.push(exportInfo); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return exports; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+5
to
+19
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial
♻️ Proposed refactor-export async function extractExports(sourceFile: SourceFile): Promise<ExportInfo[]> {
+export function extractExports(sourceFile: SourceFile): ExportInfo[] {Note: If you change this, callers in 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function processSymbol(symbol: MorphSymbol): ExportInfo | null { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const name = symbol.getName(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Skip default exports and internal symbols | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (name === "default" || name.startsWith("_")) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const declarations = symbol.getDeclarations(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (declarations.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const declaration = declarations[0]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const node = declaration as Node; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+34
to
+35
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Redundant type assertion.
♻️ Proposed simplification const declaration = declarations[0];
- const node = declaration as Node;
// Get type signature
- const type = symbol.getTypeAtLocation(node);
- const typeSignature = type.getText(node);
+ const type = symbol.getTypeAtLocation(declaration);
+ const typeSignature = type.getText(declaration);
// Get JSDoc description
- const description = getDescription(node);
+ const description = getDescription(declaration);
// Determine kind
- const kind = getExportKind(node);
+ const kind = getExportKind(declaration);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get type signature | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const type = symbol.getTypeAtLocation(node); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const typeSignature = type.getText(node); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get JSDoc description | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const description = getDescription(node); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Determine kind | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const kind = getExportKind(node); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!kind) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| kind, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typeSignature, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function getExportKind(node: Node): ExportInfo["kind"] | null { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (Node.isTypeAliasDeclaration(node)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "type"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (Node.isFunctionDeclaration(node)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "function"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (Node.isClassDeclaration(node)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "class"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (Node.isVariableDeclaration(node)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "const"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (Node.isExportSpecifier(node)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // For re-exports, check the original declaration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const symbol = node.getSymbol(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (symbol) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const valueDeclaration = symbol.getValueDeclaration(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (valueDeclaration) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return getExportKind(valueDeclaration); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Default to const for other types | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "const"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+58
to
+80
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing Exported interfaces will fall through to the default 🐛 Proposed fix function getExportKind(node: Node): ExportInfo["kind"] | null {
if (Node.isTypeAliasDeclaration(node)) {
return "type";
+ } else if (Node.isInterfaceDeclaration(node)) {
+ return "type";
} else if (Node.isFunctionDeclaration(node)) {📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function getDescription(node: Node): string | null { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Try to get JSDoc comments | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!("getJsDocs" in node)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const jsDocs = (node as unknown as { getJsDocs(): Array<{ getDescription(): string }> }).getJsDocs(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const jsDoc of jsDocs) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const description = jsDoc.getDescription(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (description) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return description.trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check parent node for JSDoc (useful for variable declarations) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const parent = node.getParent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (parent && "getJsDocs" in parent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const parentJsDocs = (parent as unknown as { getJsDocs(): Array<{ getDescription(): string }> }).getJsDocs(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const jsDoc of parentJsDocs) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const description = jsDoc.getDescription(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (description) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return description.trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The MCP configuration example here uses
"command": "tools", which might not work reliably with some clients like Claude Desktop. The mainREADME.mdcorrectly notes that a full, absolute path to the command is often required. It would be beneficial to update this example to reflect that best practice for a better user experience.