Skip to main content
Glama
runninghare

TypeScript Definition Finder

by runninghare

find_typescript_definition

Locate TypeScript symbol definitions in your codebase by providing the file path, symbol, and line content. Simplifies tracking down imported symbols like classes, interfaces, or variables.

Instructions

Use /ts-def to trigger this tool. This tool can find the definition of a TypeScript symbol in your codebase. When you encounter an imported symbol (e.g., 'import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"'), this tool will locate its original definition file and code. Simply provide the current file path, the symbol you want to find (e.g., 'StdioServerTransport'), and the line content containing that symbol.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
file_pathYesThe absolute path to the current typescript file (e.g., '/remote/.../src/index.ts')
line_contentYesThe entire line containing the symbol you want to find the definition of. The line content will be used to find both the line number in the file and the exact position of the symbol.
symbolYesThe TypeScript symbol (variable, class name, interface, type, etc.) you want to find the definition of. This symbol must be present in the line_content.

Implementation Reference

  • Core implementation of the tool logic. Uses TypeScript LanguageService to locate and extract the definition at the specified position in the file, with fallbacks to type definitions or quick info.
    export function findDefinition(filePath: string, column: number, line_content?: string) { let line = 0; let results: Record<string, any>[] = []; try { const fileContent = readFileSync(filePath, 'utf8'); // If pattern is provided, find the line number if (line_content) { const lines = fileContent.split('\n'); for (let i = 0; i < lines.length; i++) { if (lines[i].includes(line_content)) { line = i + 1; // Convert to 1-based line number break; } } } // Create the language service host const servicesHost: ts.LanguageServiceHost = { getScriptFileNames: () => [filePath], getScriptVersion: () => '1', getScriptSnapshot: (fileName) => { if (fileName === filePath) { return ts.ScriptSnapshot.fromString(fileContent); } if (existsSync(fileName)) { return ts.ScriptSnapshot.fromString(readFileSync(fileName, 'utf8')); } return undefined; }, getCurrentDirectory: () => process.cwd(), getCompilationSettings: () => ({ target: ts.ScriptTarget.Latest, module: ts.ModuleKind.CommonJS, esModuleInterop: true, }), getDefaultLibFileName: (options) => ts.getDefaultLibFilePath(options), fileExists: ts.sys.fileExists, readFile: ts.sys.readFile, readDirectory: ts.sys.readDirectory, }; // Create the language service const services = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); // Get source file and find position const sourceFile = services.getProgram()?.getSourceFile(filePath); if (!sourceFile) { throw new Error('Could not get source file'); } const position = sourceFile.getPositionOfLineAndCharacter(line - 1, column - 1); // Try to get definition const definitions = services.getDefinitionAtPosition(filePath, position); if (!definitions || definitions.length === 0) { // Try to get type definition instead const typeDefinitions = services.getTypeDefinitionAtPosition(filePath, position); if (!typeDefinitions || typeDefinitions.length === 0) { // Get quick info as a fallback const quickInfo = services.getQuickInfoAtPosition(filePath, position); if (quickInfo) { console.log('Quick Info:'); console.log(`Kind: ${quickInfo.kind}`); console.log(`Documentation: ${ts.displayPartsToString(quickInfo.documentation)}`); console.log(`Type: ${ts.displayPartsToString(quickInfo.displayParts)}`); } else { console.log('No definition or information found at the specified position'); } return; } logDefinitions(typeDefinitions, 'Type Definition', services, results); return; } logDefinitions(definitions, 'Definition', services, results); return results; } catch (error) { console.error('Error finding definition:', error instanceof Error ? error.message : String(error)); } }
  • Input schema and metadata for the 'find_typescript_definition' tool, including parameters: file_path, line_content, column_number.
    { "name": "find_typescript_definition", "description": "Use /ts-def to trigger this tool. This tool can find the definition of a TypeScript symbol in your codebase. When you encounter an imported symbol (e.g., 'import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\"'), this tool will locate its original definition file and code. Simply provide the current file path, the line content and the symbol's column number, and it will return the source definition location and code snippet.", "inputSchema": { "type": "object", "properties": { "file_path": { "type": "string", "description": "The absolute path to the current typescript file (e.g., '/remote/.../src/index.ts')", "required": true }, "line_content": { "type": "string", "description": "Pass the entire line of the symbol you want to find the definition of. The line content will be used to find the line number in the file instead of directly passing line number which AI Editor often has trouble with. The first line matching the content will be used.", "required": true }, "column_number": { "type": "number", "description": "The column number of the symbol (1-based indexing). For instance, you want to find the definition of StdioServerTransport, and the column number of symbol 'StdioServerTransport' in line 'import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\"' is 12, you should pass 12 as the column_number.", "required": true } }, "required": ["file_path", "line_content", "column_number"] } } ];
  • src/index.ts:94-97 (registration)
    Registration of the tool list handler, which exposes the 'find_typescript_definition' tool via ListToolsRequestSchema.
    // List tools handler this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
  • Handler dispatch within CallToolRequestSchema that validates arguments and calls the findDefinition implementation.
    // Process the tool request based on the tool name if (request.params.name === "find_typescript_definition") { if (!request.params.arguments) { throw new McpError(ErrorCode.InvalidParams, "Missing arguments"); } const { file_path, column_number, line_content } = request.params.arguments; var results = findDefinition(file_path as string, column_number as number, line_content as string); } else {
  • Supporting functions for extracting and formatting definition code snippets with context, indentation-aware block detection, and result building.
    function logDefinitions( definitions: readonly ts.DefinitionInfo[], definitionType: string, services: ts.LanguageService, resultStr: Record<string, any>[] ) { // resultStr += `\nFound ${definitions.length} ${definitionType}(s):\n`; definitions.forEach((def, index) => { // resultStr += `\n${definitionType} ${index + 1}:\n`; const result: Record<string, any> = { file: def.fileName, type: definitionType, } // resultStr += `File: ${def.fileName}\n`; // Read the file content const content = existsSync(def.fileName) ? readFileSync(def.fileName, 'utf8') : null; if (!content) { // resultStr += 'Could not read file contents\n'; return; } // Create a source file for position calculations const sourceFile = ts.createSourceFile( def.fileName, content, ts.ScriptTarget.Latest, true ); // Get start and end positions const start = sourceFile.getLineAndCharacterOfPosition(def.textSpan.start); const end = sourceFile.getLineAndCharacterOfPosition(def.textSpan.start + def.textSpan.length); result.location = `Line ${start.line + 1}, Column ${start.character + 1}`; // resultStr += `Location: Line ${start.line + 1}, Column ${start.character + 1}\n`; // Split content into lines and find the definition const lines = content.split('\n'); const startLine = start.line; let endLine = end.line; // Try to find the complete definition by looking at structure const baseIndent = getIndentation(lines[startLine]); for (let i = endLine + 1; i < lines.length; i++) { const line = lines[i]; if (line.trim() === '') continue; const indent = getIndentation(line); if (indent <= baseIndent) { break; } endLine = i; } // Add some context const contextBefore = 1; const contextAfter = 1; const displayStartLine = Math.max(0, startLine - contextBefore); const displayEndLine = Math.min(lines.length - 1, endLine + contextAfter); // resultStr += '\nDefinition:\n'; let codeSnippet = ''; for (let i = displayStartLine; i <= displayEndLine; i++) { const lineNum = (i + 1).toString().padStart(4); const marker = i === startLine ? ' >' : i > startLine && i <= endLine ? ' +' : ' '; codeSnippet += `${lineNum}${marker} ${lines[i]}\n`; } result.codeSnippet = codeSnippet; resultStr.push(result); }); } function getIndentation(line: string): number { const match = line.match(/^[\s\t]*/); return match ? match[0].length : 0; }

Other Tools

Related 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/runninghare/ts-def-mcp'

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