diff --git a/README.md b/README.md index 6e26726..7ba4323 100644 --- a/README.md +++ b/README.md @@ -48,17 +48,17 @@ openapi-mcp-generator --input path/to/openapi.json --output path/to/output/dir - ### CLI Options -| Option | Alias | Description | Default | -| ------------------- | ----- | ---------------------------------------------------------------------------------------- | --------------------------------- | -| `--input` | `-i` | Path or URL to OpenAPI specification (YAML or JSON) | **Required** | -| `--output` | `-o` | Directory to output the generated MCP project | **Required** | -| `--server-name` | `-n` | Name of the MCP server (`package.json:name`) | OpenAPI title or `mcp-api-server` | -| `--server-version` | `-v` | Version of the MCP server (`package.json:version`) | OpenAPI version or `1.0.0` | -| `--base-url` | `-b` | Base URL for API requests. Required if OpenAPI `servers` missing or ambiguous. | Auto-detected if possible | -| `--transport` | `-t` | Transport mode: `"stdio"` (default), `"web"`, or `"streamable-http"` | `"stdio"` | -| `--port` | `-p` | Port for web-based transports | `3000` | -| `--default-include` | | Default behavior for x-mcp filtering (true=include by default, false=exclude by default) | `true` | -| `--force` | | Overwrite existing files in the output directory without confirmation | `false` | +| Option | Alias | Description | Default | +| ------------------- | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | +| `--input` | `-i` | Path or URL to OpenAPI specification (YAML or JSON) | **Required** | +| `--output` | `-o` | Directory to output the generated MCP project | **Required** | +| `--server-name` | `-n` | Name of the MCP server (`package.json:name`) | OpenAPI title or `mcp-api-server` | +| `--server-version` | `-v` | Version of the MCP server (`package.json:version`) | OpenAPI version or `1.0.0` | +| `--base-url` | `-b` | Base URL for API requests. Required if OpenAPI `servers` missing or ambiguous. | Auto-detected if possible | +| `--transport` | `-t` | Transport mode: `"stdio"` (default), `"web"`, or `"streamable-http"` | `"stdio"` | +| `--port` | `-p` | Port for web-based transports | `3000` | +| `--default-include` | | Default behavior for x-mcp filtering. Accepts `true` or `false` (case-insensitive). `true` = include by default, `false` = exclude by default. | `true` | +| `--force` | | Overwrite existing files in the output directory without confirmation | `false` | ## 📦 Programmatic API @@ -194,7 +194,9 @@ paths: # no x-mcp -> included by default ``` -This uses standard OpenAPI extensions (x-… fields). See the OpenAPI Extensions guide for details: https://swagger.io/docs/specification/v3_0/openapi-extensions/ +This uses standard OpenAPI extensions (x-… fields). See the [OpenAPI Extensions guide](https://swagger.io/docs/specification/v3_0/openapi-extensions/) for details. + +Note: `x-mcp` must be a boolean or the strings `"true"`/`"false"` (case-insensitive). Other values are ignored in favor of higher-precedence or default behavior. --- diff --git a/package-lock.json b/package-lock.json index 0c9b0c2..ca49844 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "openapi-mcp-generator", - "version": "3.1.4", + "version": "3.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openapi-mcp-generator", - "version": "3.1.4", + "version": "3.2.0", "license": "MIT", "dependencies": { "@apidevtools/swagger-parser": "^10.1.1", diff --git a/src/api.ts b/src/api.ts index fda0fea..dc6868e 100644 --- a/src/api.ts +++ b/src/api.ts @@ -80,7 +80,8 @@ export async function getToolsFromOpenApi( } catch (error) { // Provide more context for the error if (error instanceof Error) { - throw new Error(`Failed to extract tools from OpenAPI: ${error.message}`); + // Preserve original stack/context + throw new Error(`Failed to extract tools from OpenAPI: ${error.message}`, { cause: error }); } throw error; } diff --git a/src/index.ts b/src/index.ts index 10d9304..d588a24 100644 --- a/src/index.ts +++ b/src/index.ts @@ -75,7 +75,7 @@ program ) .option( '--default-include ', - 'Default behavior for x-mcp filtering (default: true = include by default, false = exclude by default)', + 'Default behavior for x-mcp filtering (true|false, case-insensitive). Default: true (include by default), false = exclude by default', (val) => { const parsed = normalizeBoolean(val); if (typeof parsed === 'boolean') return parsed; @@ -83,7 +83,8 @@ program `Invalid value for --default-include: "${val}". Expected true/false (case-insensitive). Using default: true.` ); return true; - } + }, + true ) .option('--force', 'Overwrite existing files without prompting') .version(pkg.version) // Match package.json version diff --git a/src/parser/extract-tools.ts b/src/parser/extract-tools.ts index 9fd5bf5..6371623 100644 --- a/src/parser/extract-tools.ts +++ b/src/parser/extract-tools.ts @@ -43,8 +43,17 @@ export function extractToolsFromApi( continue; } } catch (error) { + const loc = operation.operationId || `${method} ${path}`; + const extVal = + (operation as any)['x-mcp'] ?? (pathItem as any)['x-mcp'] ?? (api as any)['x-mcp']; + let extPreview: string; + try { + extPreview = JSON.stringify(extVal); + } catch { + extPreview = String(extVal); + } console.warn( - `Error evaluating x-mcp extension for operation ${operation.operationId || `${method} ${path}`}:`, + `Error evaluating x-mcp extension for operation ${loc} (x-mcp=${extPreview}):`, error ); if (!defaultInclude) { diff --git a/src/types/index.ts b/src/types/index.ts index d3b5b4b..e36eb3b 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -29,7 +29,11 @@ export interface CliOptions { transport?: TransportType; /** Server port (for web and streamable-http transports) */ port?: number; - /** Default behavior for x-mcp filtering (default: true = include by default) */ + /** + * Default behavior for x-mcp filtering. + * true (default) = include by default when x-mcp is missing or invalid; + * false = exclude by default unless x-mcp explicitly enables. + */ defaultInclude?: boolean; } diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index 6e36dca..4058c6d 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -119,7 +119,9 @@ export function normalizeBoolean(value: unknown): boolean | undefined { if (typeof value === 'boolean') return value; if (typeof value === 'string') { const normalized = value.trim().toLowerCase(); - return normalized === 'true' ? true : normalized === 'false' ? false : undefined; + if (['true', '1', 'yes', 'on'].includes(normalized)) return true; + if (['false', '0', 'no', 'off'].includes(normalized)) return false; + return undefined; } return undefined; }