generate-api-client
Create API client code in TypeScript for Axios, Fetch, or React Query from any Swagger/OpenAPI document. Customize output directory, file structure, and tags for efficient integration.
Instructions
Generate API client code from Swagger/OpenAPI document.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| clientType | No | API client technology stack | |
| excludeTags | No | Exclude tags filter | |
| filePrefix | No | File prefix | |
| fileSuffix | No | File suffix | |
| generateTypeImports | No | Whether to generate type imports | |
| groupBy | No | Grouping method | |
| headers | No | Request headers | |
| includeTags | No | Include tags filter | |
| outputDir | No | Output directory | |
| overwrite | No | Whether to overwrite existing files | |
| swaggerUrl | Yes | Swagger/OpenAPI document URL | |
| typesImportPath | No | Types import path |
Implementation Reference
- The execute method implements the handler logic for the 'generate-api-client' MCP tool. It instantiates ApiClientGenerator, calls its generate method, and formats the response for MCP.async execute(params: z.infer<typeof this.optimizedSchema>) { try { console.log(`[ApiClientGeneratorTool] 开始生成API客户端: ${params.swaggerUrl}`); // 创建生成器实例 const generator = new ApiClientGenerator(); // 记录进度的函数 let progressUpdates: { progress: number, message: string }[] = []; const progressCallback = (progress: number, message: string) => { progressUpdates.push({ progress, message }); }; // 执行生成 const result = await generator.generate({ ...params, progressCallback } as ApiClientGeneratorOptions); // 处理结果 if (result.success) { console.log(`[ApiClientGeneratorTool] 客户端生成成功,生成了 ${result.files.length} 个文件`); return { content: [ { type: 'text' as const, text: JSON.stringify({ success: true, files: result.files, warnings: result.warnings, progress: progressUpdates }, null, 2) } ] }; } else { console.error(`[ApiClientGeneratorTool] 客户端生成失败: ${result.error}`); return { content: [ { type: 'text' as const, text: JSON.stringify({ success: false, error: result.error, progress: progressUpdates }, null, 2) } ] }; } } catch (error) { console.error(`[ApiClientGeneratorTool] 执行异常:`, error); // 返回错误结果 return { content: [ { type: 'text' as const, text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) } ] }; } }
- Zod schema defining the input parameters and validation for the 'generate-api-client' tool.schema = z.object({ /** * Swagger/OpenAPI document URL */ swaggerUrl: z.string().describe('Swagger/OpenAPI document URL'), /** * Output directory */ outputDir: z.string().optional().describe('Output directory'), /** * Whether to overwrite existing files */ overwrite: z.boolean().optional().describe('Whether to overwrite existing files'), /** * File prefix */ filePrefix: z.string().optional().describe('File prefix'), /** * File suffix */ fileSuffix: z.string().optional().describe('File suffix'), /** * API client technology stack */ clientType: z.enum(['axios', 'fetch', 'react-query']).optional().describe('API client technology stack'), /** * Whether to generate type imports */ generateTypeImports: z.boolean().optional().describe('Whether to generate type imports'), /** * Types import path */ typesImportPath: z.string().optional().describe('Types import path'), /** * Grouping method */ groupBy: z.enum(['tag', 'path', 'none']).optional().describe('Grouping method'), /** * Include tags filter */ includeTags: z.array(z.string()).optional().describe('Include tags filter'), /** * Exclude tags filter */ excludeTags: z.array(z.string()).optional().describe('Exclude tags filter'), /** * Request headers */ headers: z.record(z.string()).optional().describe('Request headers') });
- src/tools/api-client-generator-tool.ts:116-123 (registration)MCP tool registration for 'generate-api-client' using server.tool with name, description, schema, and handler.server.tool( this.name, this.description, this.schema.shape, async (params) => { return await this.execute(params); } );
- src/index.ts:61-62 (registration)Invocation of the tool's register method on the MCP server during server setup in the main entry point.new TypeScriptTypesGeneratorTool().register(server); new ApiClientGeneratorTool().register(server);
- The generate method of ApiClientGenerator class, which contains the detailed logic for parsing OpenAPI spec, grouping operations, and generating TypeScript API client code files. Called by the tool handler.async generate(options: ApiClientGeneratorOptions): Promise<CodeGenerationResult> { try { // 确保选项有效 if (!this.validateOptions(options)) { return { files: [], success: false, error: 'Invalid options. swaggerUrl is required.' }; } // 设置默认值 const outputDir = options.outputDir || './generated/api'; const overwrite = options.overwrite || false; const filePrefix = options.filePrefix || ''; const fileSuffix = options.fileSuffix || ''; const clientType = options.clientType || 'axios'; const generateTypeImports = options.generateTypeImports !== false; const typesImportPath = options.typesImportPath || '../types'; const groupBy = options.groupBy || 'tag'; const useCache = options.useCache !== false; const cacheTTLMinutes = options.cacheTTLMinutes || 60; const skipValidation = options.skipValidation || false; const lazyLoading = options.lazyLoading !== false; // 创建输出目录 await this.ensureDirectoryExists(outputDir); // 解析Swagger文档 console.log(`[ApiClientGenerator] 解析Swagger文档: ${options.swaggerUrl}`); // 设置进度日志 const logProgress = (progress: number, message: string) => { console.log(`[ApiClientGenerator] 进度 ${Math.round(progress * 100)}%: ${message}`); if (options.progressCallback) { options.progressCallback(progress, message); } }; // 使用优化的解析器 const parser = new OptimizedSwaggerApiParser({ url: options.swaggerUrl, headers: options.headers, useCache, cacheTTL: cacheTTLMinutes * 60 * 1000, // 转换为毫秒 skipValidation, lazyLoading, progressCallback: logProgress }); logProgress(0.1, '开始获取API文档'); const api = await parser.fetchApi(); logProgress(0.3, 'API文档获取完成,开始获取操作列表'); const operations = await parser.getAllOperations(); if (!operations || operations.length === 0) { return { files: [], success: false, error: 'No API operations found in Swagger document' }; } logProgress(0.4, `找到 ${operations.length} 个API操作,准备生成代码`); // 过滤操作 const filteredOperations = this.filterOperations(operations, options.includeTags, options.excludeTags); logProgress(0.5, `过滤后剩余 ${filteredOperations.length} 个API操作`); // 分组操作 const groupedOperations = this.groupOperations(filteredOperations, groupBy); // 生成客户端代码 const generatedFiles: string[] = []; const warnings: string[] = []; // 获取所有用到的模式 logProgress(0.6, '加载模式定义'); const schemas = await parser.getAllSchemas(); // 为每个分组生成文件 let fileCount = 0; const totalGroups = Object.keys(groupedOperations).length; for (const [groupName, operations] of Object.entries(groupedOperations)) { try { // 格式化分组名称 const formattedGroupName = this.formatGroupName(groupName); // 生成文件名 const fileName = `${filePrefix}${formattedGroupName}${fileSuffix}.ts`; const filePath = path.join(outputDir, fileName); // 检查文件是否存在 const fileExists = await this.fileExists(filePath); if (fileExists && !overwrite) { warnings.push(`跳过已存在的文件: ${fileName}`); continue; } // 生成客户端代码 const clientCode = this.generateClientCode({ groupName: formattedGroupName, operations, schemas, clientType, generateTypeImports, typesImportPath }); // 写入文件 await fs.writeFile(filePath, clientCode, 'utf8'); generatedFiles.push(filePath); // 更新进度 fileCount++; const progress = 0.6 + (0.3 * fileCount / totalGroups); logProgress(progress, `生成文件 ${fileCount}/${totalGroups}: ${fileName}`); } catch (err) { warnings.push(`无法处理分组 ${groupName}: ${err instanceof Error ? err.message : String(err)}`); } } // 生成索引文件 if (generatedFiles.length > 0) { const indexContent = this.generateIndexFile(generatedFiles, outputDir); const indexPath = path.join(outputDir, 'index.ts'); await fs.writeFile(indexPath, indexContent, 'utf8'); generatedFiles.push(indexPath); logProgress(0.95, `已生成索引文件: ${indexPath}`); } // 生成基础客户端配置文件 if (clientType === 'axios' || clientType === 'fetch') { const configFileName = `${clientType}-client.ts`; const configFilePath = path.join(outputDir, configFileName); if (!await this.fileExists(configFilePath) || overwrite) { const configCode = this.generateClientConfigCode(clientType); await fs.writeFile(configFilePath, configCode, 'utf8'); generatedFiles.push(configFilePath); logProgress(0.98, `已生成客户端配置文件: ${configFilePath}`); } } logProgress(1.0, `代码生成完成,共生成 ${generatedFiles.length} 个文件`); return { files: generatedFiles, success: true, warnings: warnings.length > 0 ? warnings : undefined }; } catch (error) { return { files: [], success: false, error: error instanceof Error ? error.message : String(error) }; } }