fix(mcp): translate OpenAPI 3.0 nullable into JSON Schema
The response schemas added yesterday made every paginated list tool fail. The plugin's fields are documented as OpenAPI format and validated with a JSON Schema validator, and `nullable: true` is not a JSON Schema keyword — so it is ignored, `type: string` is enforced, and `previous: null` on the first page is rejected as *null is not of type "string"*. The failure lands after the backend has already done the work, surfaces to the caller as a bare tool retry exhaustion, and appears nowhere in the gateway's own logs. Found only because an orchestrating agent asked a question that paged. The generator now rewrites `nullable: true` into `type: [T, "null"]` wherever it inlines a schema, request bodies included. A 3.1 spec needs none of this. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+51
-34
@@ -58,13 +58,15 @@ config:
|
|||||||
type: integer
|
type: integer
|
||||||
example: 123
|
example: 123
|
||||||
next:
|
next:
|
||||||
type: string
|
type:
|
||||||
nullable: true
|
- string
|
||||||
|
- 'null'
|
||||||
format: uri
|
format: uri
|
||||||
example: http://api.example.org/accounts/?page=4
|
example: http://api.example.org/accounts/?page=4
|
||||||
previous:
|
previous:
|
||||||
type: string
|
type:
|
||||||
nullable: true
|
- string
|
||||||
|
- 'null'
|
||||||
format: uri
|
format: uri
|
||||||
example: http://api.example.org/accounts/?page=2
|
example: http://api.example.org/accounts/?page=2
|
||||||
results:
|
results:
|
||||||
@@ -93,33 +95,38 @@ config:
|
|||||||
type: string
|
type: string
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
addressline2:
|
addressline2:
|
||||||
type: string
|
type:
|
||||||
nullable: true
|
- string
|
||||||
|
- 'null'
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
city:
|
city:
|
||||||
type: string
|
type: string
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
state:
|
state:
|
||||||
type: string
|
type:
|
||||||
nullable: true
|
- string
|
||||||
|
- 'null'
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
postalcode:
|
postalcode:
|
||||||
type: string
|
type:
|
||||||
nullable: true
|
- string
|
||||||
|
- 'null'
|
||||||
maxLength: 15
|
maxLength: 15
|
||||||
country:
|
country:
|
||||||
type: string
|
type: string
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
creditlimit:
|
creditlimit:
|
||||||
type: string
|
type:
|
||||||
|
- string
|
||||||
|
- 'null'
|
||||||
format: decimal
|
format: decimal
|
||||||
pattern: ^-?\d{0,8}(?:\.\d{0,2})?$
|
pattern: ^-?\d{0,8}(?:\.\d{0,2})?$
|
||||||
nullable: true
|
|
||||||
salesrepemployeenumber:
|
salesrepemployeenumber:
|
||||||
type: integer
|
type:
|
||||||
|
- integer
|
||||||
|
- 'null'
|
||||||
maximum: 2147483647
|
maximum: 2147483647
|
||||||
minimum: -2147483648
|
minimum: -2147483648
|
||||||
nullable: true
|
|
||||||
required:
|
required:
|
||||||
- addressline1
|
- addressline1
|
||||||
- city
|
- city
|
||||||
@@ -183,33 +190,38 @@ config:
|
|||||||
type: string
|
type: string
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
addressline2:
|
addressline2:
|
||||||
type: string
|
type:
|
||||||
nullable: true
|
- string
|
||||||
|
- 'null'
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
city:
|
city:
|
||||||
type: string
|
type: string
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
state:
|
state:
|
||||||
type: string
|
type:
|
||||||
nullable: true
|
- string
|
||||||
|
- 'null'
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
postalcode:
|
postalcode:
|
||||||
type: string
|
type:
|
||||||
nullable: true
|
- string
|
||||||
|
- 'null'
|
||||||
maxLength: 15
|
maxLength: 15
|
||||||
country:
|
country:
|
||||||
type: string
|
type: string
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
creditlimit:
|
creditlimit:
|
||||||
type: string
|
type:
|
||||||
|
- string
|
||||||
|
- 'null'
|
||||||
format: decimal
|
format: decimal
|
||||||
pattern: ^-?\d{0,8}(?:\.\d{0,2})?$
|
pattern: ^-?\d{0,8}(?:\.\d{0,2})?$
|
||||||
nullable: true
|
|
||||||
salesrepemployeenumber:
|
salesrepemployeenumber:
|
||||||
type: integer
|
type:
|
||||||
|
- integer
|
||||||
|
- 'null'
|
||||||
maximum: 2147483647
|
maximum: 2147483647
|
||||||
minimum: -2147483648
|
minimum: -2147483648
|
||||||
nullable: true
|
|
||||||
required:
|
required:
|
||||||
- addressline1
|
- addressline1
|
||||||
- city
|
- city
|
||||||
@@ -304,33 +316,38 @@ config:
|
|||||||
type: string
|
type: string
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
addressline2:
|
addressline2:
|
||||||
type: string
|
type:
|
||||||
nullable: true
|
- string
|
||||||
|
- 'null'
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
city:
|
city:
|
||||||
type: string
|
type: string
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
state:
|
state:
|
||||||
type: string
|
type:
|
||||||
nullable: true
|
- string
|
||||||
|
- 'null'
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
postalcode:
|
postalcode:
|
||||||
type: string
|
type:
|
||||||
nullable: true
|
- string
|
||||||
|
- 'null'
|
||||||
maxLength: 15
|
maxLength: 15
|
||||||
country:
|
country:
|
||||||
type: string
|
type: string
|
||||||
maxLength: 50
|
maxLength: 50
|
||||||
creditlimit:
|
creditlimit:
|
||||||
type: string
|
type:
|
||||||
|
- string
|
||||||
|
- 'null'
|
||||||
format: decimal
|
format: decimal
|
||||||
pattern: ^-?\d{0,8}(?:\.\d{0,2})?$
|
pattern: ^-?\d{0,8}(?:\.\d{0,2})?$
|
||||||
nullable: true
|
|
||||||
salesrepemployeenumber:
|
salesrepemployeenumber:
|
||||||
type: integer
|
type:
|
||||||
|
- integer
|
||||||
|
- 'null'
|
||||||
maximum: 2147483647
|
maximum: 2147483647
|
||||||
minimum: -2147483648
|
minimum: -2147483648
|
||||||
nullable: true
|
|
||||||
required:
|
required:
|
||||||
- addressline1
|
- addressline1
|
||||||
- city
|
- city
|
||||||
|
|||||||
Reference in New Issue
Block a user