swagger-tools/CLAUDE.md
rimskij a4fc2df4ea feat: add TypeScript generation options to generate-types tool
Add configurable options for customizing TypeScript output:
- enumAsUnion/enumAsEnum: control enum generation style
- interfacePrefix/interfaceSuffix: naming conventions for interfaces
- indentation: 2 spaces, 4 spaces, or tab

Includes validation for mutually exclusive options and valid
TypeScript identifier prefixes/suffixes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 15:42:39 +01:00

5.3 KiB

swagger-tools

MCP server for parsing, validating, and querying OpenAPI/Swagger specifications.

Quick Start

npm install
npm run build
npm start

MCP Configuration

Add to ~/.claude.json:

{
  "mcpServers": {
    "swagger-tools": {
      "command": "node",
      "args": ["/Users/rimskij/projects/swagger-tools/dist/index.js"]
    }
  }
}

Restart Claude Code after configuration.

Available Tools

Tool Purpose Key Parameters
parse-spec Parse spec, show metadata path
validate-spec Validate against schema path
query-endpoints Search/filter endpoints path, method?, pathPattern?, tag?
get-schema Get schema details path, schemaName
generate-types Generate TypeScript path, schemas?, options?

Usage Examples

# Natural language - Claude calls the right tool
"Parse the API spec at ./api.yaml"
"Show me all POST endpoints in api.yaml"
"Generate TypeScript types from https://petstore.swagger.io/v2/swagger.json"
"Is api.yaml valid?"
"What does the User schema look like?"

Key Features

Broken $ref Fallback

When specs have broken $ref pointers, parser falls back to non-dereferenced mode:

// In lib/parser.ts
try {
  spec = await SwaggerParser.dereference(specPath);  // Try first
} catch {
  spec = await SwaggerParser.parse(specPath);        // Fallback
}

.NET Name Sanitization

Converts .NET-style schema names to valid TypeScript:

// In tools/generate.ts - sanitizeName()
"Namespace.Type"            "Type"
"Generic`1[Inner]"          "Generic_Inner"
"Company.Api.V5.ViewModel"  "ViewModel"

TypeScript Generation Options

The generate-types tool supports customization via options:

Option Type Description
enumAsUnion boolean Generate enums as union types (default)
enumAsEnum boolean Generate enums as TypeScript enums
interfacePrefix string Prefix for interface names (e.g., "I")
interfaceSuffix string Suffix for interface names (e.g., "Type")
indentation '2'|'4'|'tab' Indentation style (default: '2')

Example:

{
  "name": "generate-types",
  "arguments": {
    "path": "api.yaml",
    "options": {
      "enumAsEnum": true,
      "interfacePrefix": "I",
      "indentation": "4"
    }
  }
}

Project Structure

src/
├── index.ts              # Entry point - registers tools, starts stdio server
├── tools/                # Tool implementations
│   ├── parse.ts          # parseSpec() → metadata extraction
│   ├── validate.ts       # validateSpec() → error collection
│   ├── query.ts          # queryEndpoints() → filtering logic
│   ├── schema.ts         # getSchema() → schema lookup
│   └── generate.ts       # generateTypes() → TS code generation + sanitizeName()
├── lib/                  # Shared utilities
│   ├── parser.ts         # SwaggerParser wrapper (dereference with fallback)
│   ├── validator.ts      # SwaggerParser.validate() wrapper
│   └── types.ts          # TypeScript interfaces
└── utils/
    └── format.ts         # Human-readable output formatting

Code Patterns

Tool Structure

Each tool exports:

export const toolName = 'tool-name';
export const toolDescription = '...';
export const toolSchema = { param: z.string() };
export async function toolHandler({ param }) { ... }

Return Format

Tools return MCP-compatible responses:

return {
  content: [{ type: 'text', text: humanReadable }],
  structuredContent: { success: true, data: ... }
};

Error Handling

Wrap in try/catch, return error in both content and structuredContent:

catch (err) {
  return {
    content: [{ type: 'text', text: `Error: ${err.message}` }],
    structuredContent: { success: false, error: err.message }
  };
}

Development

npm run build      # Compile TypeScript
npm run typecheck  # Type check only
npm run dev        # Run with tsx (hot reload)

Testing

# List tools
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node dist/index.js

# Local spec
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"parse-spec","arguments":{"path":"test/fixtures/petstore.yaml"}}}' | node dist/index.js

# Remote URL
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"parse-spec","arguments":{"path":"https://petstore.swagger.io/v2/swagger.json"}}}' | node dist/index.js

# Enterprise API with broken refs
echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"parse-spec","arguments":{"path":"https://projects.moravia.com/api/swagger/v5/swagger.json"}}}' | node dist/index.js

Adding New Tools

  1. Create src/tools/newtool.ts following existing pattern
  2. Export name, description, schema, handler
  3. Import and register in src/index.ts:
    server.tool(name, description, schema, handler);
    
  4. Rebuild: npm run build

Dependencies

Package Version Purpose
@modelcontextprotocol/sdk ^1.0.0 MCP protocol
@apidevtools/swagger-parser ^10.1.0 OpenAPI parsing
zod ^3.23.0 Schema validation