Skip to main content
Glama
blakeyoder

TypeScript Definitions MCP Server

by blakeyoder
mcp-server.ts13.1 kB
import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, Tool, } from "@modelcontextprotocol/sdk/types.js"; import * as ts from "typescript"; import { TypeIndexer } from "./type-indexer.js"; import { TypeValidator } from "./type-validator.js"; import { WorkspaceDetector } from "./workspace-detector.js"; import { ProjectConfig } from "./types.js"; // Define proper tool argument types interface ToolArguments { lookup_type: { typeName: string; packageName?: string }; validate_type_usage: { code: string; expectedType?: string }; find_interfaces: { pattern: string }; get_package_types: { packageName: string }; validate_interface_implementation: { implementation: string; interfaceName: string; interfaceDefinition: string; }; check_type_compatibility: { sourceType: string; targetType: string }; reinitialize_indexer: { workingDir?: string }; } export class TypeScriptDefinitionsMCPServer { private server: Server; private typeIndexer: TypeIndexer; private typeValidator: TypeValidator; private config: ProjectConfig; constructor(workingDir?: string) { this.config = WorkspaceDetector.detectProjectConfig(workingDir); this.typeIndexer = new TypeIndexer(this.config); this.typeValidator = new TypeValidator(this.getCompilerOptions()); this.server = new Server({ name: "@claude-code/typescript-definitions-mcp", version: "0.1.0", }); this.setupToolHandlers(); } private getCompilerOptions(): ts.CompilerOptions { // This would ideally read from the project's tsconfig return { target: ts.ScriptTarget.ES2020, module: ts.ModuleKind.CommonJS, lib: ["ES2020", "DOM"], declaration: true, esModuleInterop: true, skipLibCheck: true, strict: true, moduleResolution: ts.ModuleResolutionKind.NodeJs, allowSyntheticDefaultImports: true, resolveJsonModule: true }; } // Type-safe argument validation private validateArgs<T>(args: unknown): T { if (!args || typeof args !== 'object') { throw new Error('Invalid arguments: expected object'); } return args as T; } private setupToolHandlers(): void { this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "lookup_type", description: "Look up TypeScript type definitions by name and optional package", inputSchema: { type: "object", properties: { typeName: { type: "string", description: "The name of the type to look up" }, packageName: { type: "string", description: "Optional package name to filter results" } }, required: ["typeName"] } }, { name: "validate_type_usage", description: "Validate TypeScript code for type correctness", inputSchema: { type: "object", properties: { code: { type: "string", description: "The TypeScript code to validate" }, expectedType: { type: "string", description: "Optional expected type to validate against" } }, required: ["code"] } }, { name: "find_interfaces", description: "Find interfaces matching a pattern", inputSchema: { type: "object", properties: { pattern: { type: "string", description: "Pattern to match interface names (supports wildcards with *)" } }, required: ["pattern"] } }, { name: "get_package_types", description: "Get all type definitions from a specific package", inputSchema: { type: "object", properties: { packageName: { type: "string", description: "Name of the package to get types from" } }, required: ["packageName"] } }, { name: "validate_interface_implementation", description: "Validate if code correctly implements an interface", inputSchema: { type: "object", properties: { implementation: { type: "string", description: "The implementation code to validate" }, interfaceName: { type: "string", description: "Name of the interface being implemented" }, interfaceDefinition: { type: "string", description: "The interface definition" } }, required: ["implementation", "interfaceName", "interfaceDefinition"] } }, { name: "check_type_compatibility", description: "Check if two types are compatible/assignable", inputSchema: { type: "object", properties: { sourceType: { type: "string", description: "The source type" }, targetType: { type: "string", description: "The target type" } }, required: ["sourceType", "targetType"] } }, { name: "get_project_info", description: "Get information about the current TypeScript project", inputSchema: { type: "object", properties: {}, additionalProperties: false } }, { name: "reinitialize_indexer", description: "Reinitialize the type indexer (useful after package installations)", inputSchema: { type: "object", properties: { workingDir: { type: "string", description: "Optional working directory to reinitialize from" } }, additionalProperties: false } } ] as Tool[] }; }); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case "lookup_type": { const lookupArgs = this.validateArgs<ToolArguments["lookup_type"]>(args); return await this.handleLookupType(lookupArgs.typeName, lookupArgs.packageName); } case "validate_type_usage": { const validateArgs = this.validateArgs<ToolArguments["validate_type_usage"]>(args); return await this.handleValidateTypeUsage(validateArgs.code, validateArgs.expectedType); } case "find_interfaces": { const interfaceArgs = this.validateArgs<ToolArguments["find_interfaces"]>(args); return await this.handleFindInterfaces(interfaceArgs.pattern); } case "get_package_types": { const packageArgs = this.validateArgs<ToolArguments["get_package_types"]>(args); return await this.handleGetPackageTypes(packageArgs.packageName); } case "validate_interface_implementation": { const implArgs = this.validateArgs<ToolArguments["validate_interface_implementation"]>(args); return await this.handleValidateInterfaceImplementation( implArgs.implementation, implArgs.interfaceName, implArgs.interfaceDefinition ); } case "check_type_compatibility": { const compatArgs = this.validateArgs<ToolArguments["check_type_compatibility"]>(args); return await this.handleCheckTypeCompatibility( compatArgs.sourceType, compatArgs.targetType ); } case "get_project_info": return await this.handleGetProjectInfo(); case "reinitialize_indexer": { const reinitArgs = this.validateArgs<ToolArguments["reinitialize_indexer"]>(args); return await this.handleReinitializeIndexer(reinitArgs.workingDir); } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [ { type: "text", text: `Error: ${errorMessage}` } ], isError: true }; } }); } private async handleLookupType(typeName: string, packageName?: string) { const results = await this.typeIndexer.findType(typeName, packageName); return { content: [ { type: "text", text: JSON.stringify({ query: { typeName, packageName }, results, count: results.length }, null, 2) } ] }; } private async handleValidateTypeUsage(code: string, expectedType?: string) { const result = this.typeValidator.validateTypeUsage(code, expectedType); return { content: [ { type: "text", text: JSON.stringify(result, null, 2) } ] }; } private async handleFindInterfaces(pattern: string) { const results = await this.typeIndexer.findInterfaces(pattern); return { content: [ { type: "text", text: JSON.stringify({ pattern, results, count: results.length }, null, 2) } ] }; } private async handleGetPackageTypes(packageName: string) { const results = await this.typeIndexer.getPackageTypes(packageName); return { content: [ { type: "text", text: JSON.stringify({ packageName, results, count: results.length }, null, 2) } ] }; } private async handleValidateInterfaceImplementation( implementation: string, interfaceName: string, interfaceDefinition: string ) { const result = this.typeValidator.validateInterfaceImplementation( implementation, interfaceName, interfaceDefinition ); return { content: [ { type: "text", text: JSON.stringify(result, null, 2) } ] }; } private async handleCheckTypeCompatibility(sourceType: string, targetType: string) { const result = this.typeValidator.checkTypeCompatibility(sourceType, targetType); return { content: [ { type: "text", text: JSON.stringify({ sourceType, targetType, ...result }, null, 2) } ] }; } private async handleGetProjectInfo() { const packages = WorkspaceDetector.getInstalledPackages(this.config.rootPath); return { content: [ { type: "text", text: JSON.stringify({ config: this.config, installedPackages: packages.length, packagesWithTypes: packages.filter(p => p.hasTypes).length, packages: packages.slice(0, 20) // Limit to first 20 for readability }, null, 2) } ] }; } private async handleReinitializeIndexer(workingDir?: string) { try { if (workingDir) { this.config = WorkspaceDetector.detectProjectConfig(workingDir); this.typeIndexer = new TypeIndexer(this.config); } await this.typeIndexer.initialize(); return { content: [ { type: "text", text: JSON.stringify({ message: "Type indexer reinitialized successfully", config: this.config }, null, 2) } ] }; } catch (error) { throw new Error(`Failed to reinitialize indexer: ${error instanceof Error ? error.message : String(error)}`); } } async initialize(): Promise<void> { await this.typeIndexer.initialize(); } async run(): Promise<void> { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error("TypeScript Definitions MCP Server running on stdio"); } }

Implementation Reference

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/blakeyoder/typescript-definitions-mcp'

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