@taskade/mcp-openapi-codegen
Advanced tools
+6
-0
| # @taskade/mcp-openapi-codegen | ||
| ## 0.0.2 | ||
| ### Patch Changes | ||
| - [`6b1ba50`](https://github.com/taskade/mcp/commit/6b1ba50acd2a5a2c64c37863432fe1cd1ad08d68) Thanks [@prevwong](https://github.com/prevwong)! - Temporary fix for openapi codegen | ||
| ## 0.0.1 | ||
@@ -4,0 +10,0 @@ |
+8
-1
| { | ||
| "name": "@taskade/mcp-openapi-codegen", | ||
| "version": "0.0.1", | ||
| "version": "0.0.2", | ||
| "author": "Prev Wong", | ||
| "license": "MIT", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/taskade/mcp.git" | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "type": "module", | ||
@@ -7,0 +14,0 @@ "exports": { |
+4
-2
@@ -8,6 +8,6 @@ # @taskade/mcp-openapi-codegen | ||
| - Install `@taskade/mcp-openapi-codegen` package: | ||
| - Install `@taskade/mcp-openapi-codegen` and `@readme/openapi-parser` package: | ||
| ```sh | ||
| npm install --dev @taskade/mcp-openapi-codegen | ||
| npm install --dev @taskade/mcp-openapi-codegen @readme/openapi-parser | ||
| ``` | ||
@@ -32,2 +32,4 @@ | ||
| Then run `npx tsx scripts/generate-openapi-tools.ts` | ||
| > This will generate a new `tools.generated.ts` file in the `src/` folder. | ||
@@ -34,0 +36,0 @@ |
+112
-0
@@ -174,1 +174,113 @@ import type { JSONSchema7 as IJsonSchema } from 'json-schema'; | ||
| }; | ||
| /** | ||
| * Walks the schema and flattens `allOf` so it can be expressed as plain Zod. | ||
| * | ||
| * Why: Zod represents `allOf` as `z.intersection(...)`. When an `allOf` member | ||
| * contains an `anyOf`/`oneOf` whose branches use `additionalProperties: false` | ||
| * (i.e. `.strict()`), the intersection becomes unsatisfiable — sibling properties | ||
| * coming from the other `allOf` member are rejected as unknown by the strict | ||
| * branch, but are simultaneously required. We resolve this by distributing the | ||
| * other members into each branch so each branch knows about every sibling key. | ||
| */ | ||
| export const normalizeAllOf = (schema: IJsonSchema): IJsonSchema => { | ||
| if (!schema || typeof schema !== 'object') { | ||
| return schema; | ||
| } | ||
| const next: IJsonSchema = { ...schema }; | ||
| if (next.properties) { | ||
| const props: Record<string, IJsonSchema> = {}; | ||
| for (const [k, v] of Object.entries(next.properties)) { | ||
| props[k] = normalizeAllOf(v as IJsonSchema); | ||
| } | ||
| next.properties = props; | ||
| } | ||
| if (next.items) { | ||
| next.items = Array.isArray(next.items) | ||
| ? next.items.map((i) => normalizeAllOf(i as IJsonSchema)) | ||
| : normalizeAllOf(next.items as IJsonSchema); | ||
| } | ||
| if (Array.isArray(next.anyOf)) { | ||
| next.anyOf = next.anyOf.map((s) => normalizeAllOf(s as IJsonSchema)); | ||
| } | ||
| if (Array.isArray(next.oneOf)) { | ||
| next.oneOf = next.oneOf.map((s) => normalizeAllOf(s as IJsonSchema)); | ||
| } | ||
| if (Array.isArray(next.allOf)) { | ||
| next.allOf = next.allOf.map((s) => normalizeAllOf(s as IJsonSchema)); | ||
| } | ||
| if (!Array.isArray(next.allOf) || next.allOf.length === 0) { | ||
| return next; | ||
| } | ||
| const members = next.allOf as IJsonSchema[]; | ||
| // If any member has anyOf/oneOf, distribute the other members across each branch. | ||
| const branchIdx = members.findIndex((m) => Array.isArray(m.anyOf) || Array.isArray(m.oneOf)); | ||
| if (branchIdx >= 0) { | ||
| const branchMember = members[branchIdx]; | ||
| const branchKey: 'anyOf' | 'oneOf' = Array.isArray(branchMember.anyOf) ? 'anyOf' : 'oneOf'; | ||
| const branches = branchMember[branchKey] as IJsonSchema[]; | ||
| const others = members.filter((_, i) => i !== branchIdx); | ||
| const branchSiblings: IJsonSchema = { ...branchMember }; | ||
| delete (branchSiblings as any)[branchKey]; | ||
| const distributed = branches.map((b) => | ||
| normalizeAllOf({ allOf: [...others, branchSiblings, b] }), | ||
| ); | ||
| const result: IJsonSchema = { ...next }; | ||
| delete result.allOf; | ||
| (result as any)[branchKey] = distributed; | ||
| return result; | ||
| } | ||
| // All members are plain — merge them into one object schema. | ||
| const merged = mergeObjectSchemas(members); | ||
| const result: IJsonSchema = { ...next, ...merged }; | ||
| delete result.allOf; | ||
| return result; | ||
| }; | ||
| const mergeObjectSchemas = (schemas: IJsonSchema[]): IJsonSchema => { | ||
| const properties: Record<string, IJsonSchema> = {}; | ||
| const required = new Set<string>(); | ||
| let additionalProperties: IJsonSchema['additionalProperties'] | undefined; | ||
| let type: IJsonSchema['type'] = 'object'; | ||
| for (const s of schemas) { | ||
| if (s.properties) { | ||
| for (const [k, v] of Object.entries(s.properties)) { | ||
| properties[k] = v as IJsonSchema; | ||
| } | ||
| } | ||
| if (Array.isArray(s.required)) { | ||
| s.required.forEach((r) => required.add(r)); | ||
| } | ||
| if (s.additionalProperties !== undefined) { | ||
| // false wins — if any branch is strict, the merged schema is strict. | ||
| if (s.additionalProperties === false || additionalProperties === false) { | ||
| additionalProperties = false; | ||
| } else { | ||
| additionalProperties = s.additionalProperties; | ||
| } | ||
| } | ||
| if (s.type && s.type !== 'object') { | ||
| type = s.type; | ||
| } | ||
| } | ||
| const result: IJsonSchema = { type, properties }; | ||
| if (required.size > 0) { | ||
| result.required = Array.from(required); | ||
| } | ||
| if (additionalProperties !== undefined) { | ||
| result.additionalProperties = additionalProperties; | ||
| } | ||
| return result; | ||
| }; |
+13
-3
@@ -10,2 +10,3 @@ import type { JSONSchema7 as IJsonSchema } from 'json-schema'; | ||
| isRequestBodyObject, | ||
| normalizeAllOf, | ||
| } from './openapi'; | ||
@@ -69,3 +70,5 @@ | ||
| obj.properties![param.name] = convertOpenApiSchemaToJsonSchema(param.schema); | ||
| obj.properties![param.name] = normalizeAllOf( | ||
| convertOpenApiSchemaToJsonSchema(param.schema), | ||
| ); | ||
@@ -86,4 +89,6 @@ if (param.required) { | ||
| ) { | ||
| const bodySchema = convertOpenApiSchemaToJsonSchema( | ||
| operation.requestBody.content['application/json'].schema, | ||
| const bodySchema = normalizeAllOf( | ||
| convertOpenApiSchemaToJsonSchema( | ||
| operation.requestBody.content['application/json'].schema, | ||
| ), | ||
| ); | ||
@@ -95,2 +100,7 @@ | ||
| } | ||
| if (Array.isArray(bodySchema.required) && bodySchema.required.length > 0) { | ||
| const merged = new Set([...(inputSchema.required ?? []), ...bodySchema.required]); | ||
| inputSchema.required = Array.from(merged); | ||
| } | ||
| } | ||
@@ -97,0 +107,0 @@ } |
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
24890
23.4%640
20.08%93
2.2%1
-50%