Problem
GitHub Copilot (via its Neural Link bridge) crashes when listing neo.mjs-neural-link tools:
Failed to validate tool mcp_neo_mjs-neura_call_method: Error: tool parameters array type must have items. Please open an issue for the MCP server or extension which provides this tool
Claude Desktop / Cursor tolerate the malformed schema; Copilot's validator is strictly draft-compliant and rejects any {"type":"array"} lacking items.
Architectural Reality
Three-stage pipeline produces the defect:
ai/mcp/server/neural-link/openapi.yaml at CallMethodRequest.properties.args (and three /data/store/inspect response properties) declares type: array with no items — permitted by OpenAPI 3.x but ambiguous.
ai/mcp/validation/OpenApiValidator.mjs:115-116 fallback produces z.array(z.any()) (correct Zod behavior).
zod-to-json-schema with target: 'openApi3' serializes z.array(z.any()) as {"type":"array"} — silently strips items. Verified: zodToJsonSchema(z.array(z.any()), {target:'openApi3'}) === {"type":"array"}
zodToJsonSchema(z.array(z.unknown()), {target:'openApi3'}) === {"type":"array","items":{}}
This is orthogonal to prior fixes:
- #10043 (closed) removed the hardcoded
z.array(z.string()) regression.
- #9837 (open) covers nested array schemas.
- This ticket covers arrays with no
items at all — the residual third case.
Blast Radius (audited)
Only neural-link/openapi.yaml is affected. Four locations:
.components.schemas.CallMethodRequest.properties.args — breaks call_method on Copilot
/data/store/inspect response: .properties.filters, .properties.sorters, .properties.items — breaks inspect_store output schema (if validated)
The other four MCP servers are clean.
Proposed Fix (Two Layers)
Layer 1 — defense-in-depth in ai/mcp/validation/OpenApiValidator.mjs:116:
- zodSchema = z.array(z.any());
+ zodSchema = z.array(z.unknown());
z.unknown() round-trips through zod-to-json-schema as items: {}, forcing a compliant emission regardless of YAML quality.
Layer 2 — source-of-truth in ai/mcp/server/neural-link/openapi.yaml:
CallMethodRequest.args → add items: {} (heterogeneous method args, intentionally untyped)
/data/store/inspect response filters, sorters, items → add items: {type: object}
Avoided "Gold Standards" / Traps
- Rejected: Forcing
z.array(z.string()) fallback. That was the regression #10043 fixed — would break typed args.
- Rejected: Post-processing the emitted JSON Schema to inject
items: {}. Adds a second serialization layer; z.unknown() achieves the same outcome natively in Zod.
- Rejected: Silently widening every array on the YAML side. We want the YAML to remain the source of intent; Layer 1 exists as safety net, not primary contract.
Verification
Permanent Playwright regression test (per AGENTS.md §10 rule 3) that calls listTools on the neural-link server and asserts every array-typed schema node includes an items property.
Origin Session ID
97343e6e-9d1c-4170-b3a5-6e58d41511b6
Problem
GitHub Copilot (via its Neural Link bridge) crashes when listing
neo.mjs-neural-linktools:Claude Desktop / Cursor tolerate the malformed schema; Copilot's validator is strictly draft-compliant and rejects any
{"type":"array"}lackingitems.Architectural Reality
Three-stage pipeline produces the defect:
ai/mcp/server/neural-link/openapi.yamlatCallMethodRequest.properties.args(and three/data/store/inspectresponse properties) declarestype: arraywith noitems— permitted by OpenAPI 3.x but ambiguous.ai/mcp/validation/OpenApiValidator.mjs:115-116fallback producesz.array(z.any())(correct Zod behavior).zod-to-json-schemawithtarget: 'openApi3'serializesz.array(z.any())as{"type":"array"}— silently stripsitems. Verified:zodToJsonSchema(z.array(z.any()), {target:'openApi3'}) === {"type":"array"} // bug zodToJsonSchema(z.array(z.unknown()), {target:'openApi3'}) === {"type":"array","items":{}} // fixThis is orthogonal to prior fixes:
z.array(z.string())regression.itemsat all — the residual third case.Blast Radius (audited)
Only
neural-link/openapi.yamlis affected. Four locations:.components.schemas.CallMethodRequest.properties.args— breakscall_methodon Copilot/data/store/inspectresponse:.properties.filters,.properties.sorters,.properties.items— breaksinspect_storeoutput schema (if validated)The other four MCP servers are clean.
Proposed Fix (Two Layers)
Layer 1 — defense-in-depth in
ai/mcp/validation/OpenApiValidator.mjs:116:- zodSchema = z.array(z.any()); + zodSchema = z.array(z.unknown());z.unknown()round-trips throughzod-to-json-schemaasitems: {}, forcing a compliant emission regardless of YAML quality.Layer 2 — source-of-truth in
ai/mcp/server/neural-link/openapi.yaml:CallMethodRequest.args→ additems: {}(heterogeneous method args, intentionally untyped)/data/store/inspectresponsefilters,sorters,items→ additems: {type: object}Avoided "Gold Standards" / Traps
z.array(z.string())fallback. That was the regression #10043 fixed — would break typed args.items: {}. Adds a second serialization layer;z.unknown()achieves the same outcome natively in Zod.Verification
Permanent Playwright regression test (per
AGENTS.md§10 rule 3) that callslistToolson the neural-link server and asserts every array-typed schema node includes anitemsproperty.Origin Session ID
97343e6e-9d1c-4170-b3a5-6e58d41511b6