From bc4ee55ac2b11a34b555d70a831f08edf7601e63 Mon Sep 17 00:00:00 2001 From: Jack Thomson Date: Thu, 31 Jul 2025 11:22:16 +0100 Subject: [PATCH 1/5] handle schemas with one type array --- package-lock.json | 4 ++-- src/parser/extract-tools.ts | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3ea9773..d5a35d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "openapi-mcp-generator", - "version": "3.1.2", + "version": "3.1.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openapi-mcp-generator", - "version": "3.1.2", + "version": "3.1.4", "license": "MIT", "dependencies": { "@apidevtools/swagger-parser": "^10.1.1", diff --git a/src/parser/extract-tools.ts b/src/parser/extract-tools.ts index f50232e..992f259 100644 --- a/src/parser/extract-tools.ts +++ b/src/parser/extract-tools.ts @@ -203,6 +203,10 @@ export function mapOpenApiSchemaToJsonSchema( } else if (!jsonSchema.type) { jsonSchema.type = 'null'; } + } else { + if (Array.isArray(jsonSchema.type) && jsonSchema.type.length === 1) { + jsonSchema.type = jsonSchema.type[0]; + } } // Recursively process object properties From cf1a795beea6a989d88717ff7456e7cb36af9944 Mon Sep 17 00:00:00 2001 From: Jack Thomson Date: Fri, 1 Aug 2025 02:52:47 +0100 Subject: [PATCH 2/5] Add simplifyTypes flag for CLI --- src/generator/server-code.ts | 2 +- src/index.ts | 1 + src/parser/extract-tools.ts | 21 ++++++++++++--------- src/types/index.ts | 2 ++ 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/generator/server-code.ts b/src/generator/server-code.ts index 3059591..c89340c 100644 --- a/src/generator/server-code.ts +++ b/src/generator/server-code.ts @@ -25,7 +25,7 @@ export function generateMcpServerCode( serverVersion: string ): string { // Extract tools from API - const tools = extractToolsFromApi(api); + const tools = extractToolsFromApi(api, options.simplifyTypes); // Determine base URL const determinedBaseUrl = determineBaseUrl(api, options.baseUrl); diff --git a/src/index.ts b/src/index.ts index a528160..b261f4f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -73,6 +73,7 @@ program (val) => parseInt(val, 10) ) .option('--force', 'Overwrite existing files without prompting') + .option('--simplifyTypes', 'Flatten single-element type arrays in the JSON schema to their single value') .version(pkg.version) // Match package.json version .action((options) => { runGenerator(options).catch((error) => { diff --git a/src/parser/extract-tools.ts b/src/parser/extract-tools.ts index 992f259..55e309e 100644 --- a/src/parser/extract-tools.ts +++ b/src/parser/extract-tools.ts @@ -4,7 +4,7 @@ import { OpenAPIV3 } from 'openapi-types'; import type { JSONSchema7, JSONSchema7TypeName } from 'json-schema'; import { generateOperationId } from '../utils/code-gen.js'; -import { McpToolDefinition } from '../types/index.js'; +import { CliOptions, McpToolDefinition } from '../types/index.js'; /** * Extracts tool definitions from an OpenAPI document @@ -12,7 +12,7 @@ import { McpToolDefinition } from '../types/index.js'; * @param api OpenAPI document * @returns Array of MCP tool definitions */ -export function extractToolsFromApi(api: OpenAPIV3.Document): McpToolDefinition[] { +export function extractToolsFromApi(api: OpenAPIV3.Document, simplifyTypes?: string): McpToolDefinition[] { const tools: McpToolDefinition[] = []; const usedNames = new Set(); const globalSecurity = api.security || []; @@ -46,7 +46,7 @@ export function extractToolsFromApi(api: OpenAPIV3.Document): McpToolDefinition[ // Generate input schema and extract parameters const { inputSchema, parameters, requestBodyContentType } = - generateInputSchemaAndDetails(operation); + generateInputSchemaAndDetails(operation, simplifyTypes); // Extract parameter details for execution const executionParameters = parameters.map((p) => ({ name: p.name, in: p.in })); @@ -80,7 +80,7 @@ export function extractToolsFromApi(api: OpenAPIV3.Document): McpToolDefinition[ * @param operation OpenAPI operation object * @returns Input schema, parameters, and request body content type */ -export function generateInputSchemaAndDetails(operation: OpenAPIV3.OperationObject): { +export function generateInputSchemaAndDetails(operation: OpenAPIV3.OperationObject, simplifyTypes?: string): { inputSchema: JSONSchema7 | boolean; parameters: OpenAPIV3.ParameterObject[]; requestBodyContentType?: string; @@ -96,7 +96,7 @@ export function generateInputSchemaAndDetails(operation: OpenAPIV3.OperationObje allParameters.forEach((param) => { if (!param.name || !param.schema) return; - const paramSchema = mapOpenApiSchemaToJsonSchema(param.schema as OpenAPIV3.SchemaObject); + const paramSchema = mapOpenApiSchemaToJsonSchema(param.schema as OpenAPIV3.SchemaObject, undefined, simplifyTypes); if (typeof paramSchema === 'object') { paramSchema.description = param.description || paramSchema.description; } @@ -158,7 +158,8 @@ export function generateInputSchemaAndDetails(operation: OpenAPIV3.OperationObje */ export function mapOpenApiSchemaToJsonSchema( schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject, - seen: WeakSet = new WeakSet() + seen: WeakSet = new WeakSet(), + simplifyTypes?: string ): JSONSchema7 | boolean { // Handle reference objects if ('$ref' in schema) { @@ -204,7 +205,7 @@ export function mapOpenApiSchemaToJsonSchema( jsonSchema.type = 'null'; } } else { - if (Array.isArray(jsonSchema.type) && jsonSchema.type.length === 1) { + if (Array.isArray(jsonSchema.type) && jsonSchema.type.length === 1 && simplifyTypes) { jsonSchema.type = jsonSchema.type[0]; } } @@ -217,7 +218,8 @@ export function mapOpenApiSchemaToJsonSchema( if (typeof propSchema === 'object' && propSchema !== null) { mappedProps[key] = mapOpenApiSchemaToJsonSchema( propSchema as OpenAPIV3.SchemaObject, - seen + seen, + simplifyTypes ); } else if (typeof propSchema === 'boolean') { mappedProps[key] = propSchema; @@ -235,7 +237,8 @@ export function mapOpenApiSchemaToJsonSchema( ) { jsonSchema.items = mapOpenApiSchemaToJsonSchema( jsonSchema.items as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject, - seen + seen, + simplifyTypes ); } return jsonSchema; diff --git a/src/types/index.ts b/src/types/index.ts index c945341..ccb0dd6 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -29,6 +29,8 @@ export interface CliOptions { transport?: TransportType; /** Server port (for web and streamable-http transports) */ port?: number; + /** Flatten single-element type arrays in the JSON schema to their single value */ + simplifyTypes?: string; } /** From 55971cef1a17c3263a3b8429936414910c5f123d Mon Sep 17 00:00:00 2001 From: Jack Thomson Date: Fri, 8 Aug 2025 14:09:06 +0100 Subject: [PATCH 3/5] format --- src/index.ts | 5 ++++- src/parser/extract-tools.ts | 22 +++++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/index.ts b/src/index.ts index b261f4f..65ad715 100644 --- a/src/index.ts +++ b/src/index.ts @@ -73,7 +73,10 @@ program (val) => parseInt(val, 10) ) .option('--force', 'Overwrite existing files without prompting') - .option('--simplifyTypes', 'Flatten single-element type arrays in the JSON schema to their single value') + .option( + '--simplifyTypes', + 'Flatten single-element type arrays in the JSON schema to their single value' + ) .version(pkg.version) // Match package.json version .action((options) => { runGenerator(options).catch((error) => { diff --git a/src/parser/extract-tools.ts b/src/parser/extract-tools.ts index 55e309e..b9cface 100644 --- a/src/parser/extract-tools.ts +++ b/src/parser/extract-tools.ts @@ -12,7 +12,10 @@ import { CliOptions, McpToolDefinition } from '../types/index.js'; * @param api OpenAPI document * @returns Array of MCP tool definitions */ -export function extractToolsFromApi(api: OpenAPIV3.Document, simplifyTypes?: string): McpToolDefinition[] { +export function extractToolsFromApi( + api: OpenAPIV3.Document, + simplifyTypes?: string +): McpToolDefinition[] { const tools: McpToolDefinition[] = []; const usedNames = new Set(); const globalSecurity = api.security || []; @@ -45,8 +48,10 @@ export function extractToolsFromApi(api: OpenAPIV3.Document, simplifyTypes?: str operation.description || operation.summary || `Executes ${method.toUpperCase()} ${path}`; // Generate input schema and extract parameters - const { inputSchema, parameters, requestBodyContentType } = - generateInputSchemaAndDetails(operation, simplifyTypes); + const { inputSchema, parameters, requestBodyContentType } = generateInputSchemaAndDetails( + operation, + simplifyTypes + ); // Extract parameter details for execution const executionParameters = parameters.map((p) => ({ name: p.name, in: p.in })); @@ -80,7 +85,10 @@ export function extractToolsFromApi(api: OpenAPIV3.Document, simplifyTypes?: str * @param operation OpenAPI operation object * @returns Input schema, parameters, and request body content type */ -export function generateInputSchemaAndDetails(operation: OpenAPIV3.OperationObject, simplifyTypes?: string): { +export function generateInputSchemaAndDetails( + operation: OpenAPIV3.OperationObject, + simplifyTypes?: string +): { inputSchema: JSONSchema7 | boolean; parameters: OpenAPIV3.ParameterObject[]; requestBodyContentType?: string; @@ -96,7 +104,11 @@ export function generateInputSchemaAndDetails(operation: OpenAPIV3.OperationObje allParameters.forEach((param) => { if (!param.name || !param.schema) return; - const paramSchema = mapOpenApiSchemaToJsonSchema(param.schema as OpenAPIV3.SchemaObject, undefined, simplifyTypes); + const paramSchema = mapOpenApiSchemaToJsonSchema( + param.schema as OpenAPIV3.SchemaObject, + undefined, + simplifyTypes + ); if (typeof paramSchema === 'object') { paramSchema.description = param.description || paramSchema.description; } From 7608c2f0c5f907ca7f74adc1feff454c278bd6f8 Mon Sep 17 00:00:00 2001 From: Jaytee-eq Date: Fri, 8 Aug 2025 14:12:10 +0100 Subject: [PATCH 4/5] Update package-lock.json --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d5a35d6..3ea9773 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "openapi-mcp-generator", - "version": "3.1.4", + "version": "3.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openapi-mcp-generator", - "version": "3.1.4", + "version": "3.1.2", "license": "MIT", "dependencies": { "@apidevtools/swagger-parser": "^10.1.1", From 1d6b893e377266d420db327db724f8c351a5c6f1 Mon Sep 17 00:00:00 2001 From: Jack Thomson Date: Fri, 8 Aug 2025 15:06:41 +0100 Subject: [PATCH 5/5] add cli option to README --- README.md | 1 + src/index.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bbbaff2..9494d86 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ openapi-mcp-generator --input path/to/openapi.json --output path/to/output/dir - | `--transport` | `-t` | Transport mode: `"stdio"` (default), `"web"`, or `"streamable-http"` | `"stdio"` | | `--port` | `-p` | Port for web-based transports | `3000` | | `--force` | | Overwrite existing files in the output directory without confirmation | `false` | +| `--simplifyTypes` | `-st` | Flatten single-element type arrays in the JSON schema to their single value | `false` | ## 📦 Programmatic API diff --git a/src/index.ts b/src/index.ts index 65ad715..27328dd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -74,7 +74,7 @@ program ) .option('--force', 'Overwrite existing files without prompting') .option( - '--simplifyTypes', + '-st, --simplifyTypes', 'Flatten single-element type arrays in the JSON schema to their single value' ) .version(pkg.version) // Match package.json version