Skip to main content
Glama
tuskermanshu

Swagger MCP Server

by tuskermanshu

generate-api-client

Generate API client code from Swagger/OpenAPI documents for Axios, Fetch, or React Query with configurable options for file structure and filtering.

Instructions

Generate API client code from Swagger/OpenAPI document.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
swaggerUrlYesSwagger/OpenAPI document URL
outputDirNoOutput directory
overwriteNoWhether to overwrite existing files
filePrefixNoFile prefix
fileSuffixNoFile suffix
clientTypeNoAPI client technology stack
generateTypeImportsNoWhether to generate type imports
typesImportPathNoTypes import path
groupByNoGrouping method
includeTagsNoInclude tags filter
excludeTagsNoExclude tags filter
headersNoRequest headers

Implementation Reference

  • Main handler logic for the generate-api-client tool. Instantiates ApiClientGenerator, calls generate(), handles progress and results, returns structured response.
    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 input schema defining parameters for the generate-api-client tool, including swaggerUrl, outputDir, clientType, etc.
    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')
    });
  • Registration of the 'generate-api-client' tool on the MCP server 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:62-62 (registration)
    Call to register the ApiClientGeneratorTool (including generate-api-client) in the main MCP server setup.
    new ApiClientGeneratorTool().register(server);
  • Core helper: ApiClientGenerator.generate() method that fetches/parses OpenAPI spec, groups operations, generates TypeScript API client code files for axios/fetch/react-query.
    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)
        };
      }
    }
Behavior2/5

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

No annotations are provided, so the description carries full burden. It mentions generation but doesn't disclose behavioral traits like whether this creates files locally, requires network access for the Swagger URL, has rate limits, or what happens on failure. The description is minimal and lacks essential operational context for a code generation tool.

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?

The description is a single, efficient sentence with zero waste. It's appropriately sized and front-loaded, clearly stating the core purpose without unnecessary elaboration.

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

Completeness2/5

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

Given the tool's complexity (12 parameters, no annotations, no output schema), the description is inadequate. It doesn't explain what the generated output looks like, how files are structured, error handling, or dependencies. For a code generation tool with many configuration options, more context is needed to guide effective use.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents all 12 parameters thoroughly. The description adds no additional parameter semantics beyond what's in the schema (e.g., it doesn't explain relationships between parameters like 'filePrefix' and 'fileSuffix', or clarify the 'clientType' enum options). Baseline 3 is appropriate when schema does the heavy lifting.

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

Purpose4/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: 'Generate API client code from Swagger/OpenAPI document.' It specifies the verb ('Generate') and resource ('API client code'), but doesn't differentiate from siblings like 'generate-api-client-optimized' or 'generate-typescript-types', which would require more specificity about what makes this tool unique.

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

Usage Guidelines2/5

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

No guidance is provided on when to use this tool versus alternatives. With siblings like 'generate-api-client-optimized', 'generate-typescript-types', and various 'parse-swagger' tools, the description offers no context about differences, prerequisites, or appropriate scenarios for this specific tool.

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/tuskermanshu/swagger-mcp-server'

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