Skip to content

fix: add missing items property to array-type parameter schemas#83

Open
charryshun wants to merge 2 commits intoRootly-AI-Labs:mainfrom
charryshun:fix/array-schema-missing-items
Open

fix: add missing items property to array-type parameter schemas#83
charryshun wants to merge 2 commits intoRootly-AI-Labs:mainfrom
charryshun:fix/array-schema-missing-items

Conversation

@charryshun
Copy link
Copy Markdown

Summary

  • Fixes VS Code GitHub Copilot Agent Mode validation errors like tool parameters array type must have items for all 99+ generated MCP tools
  • Adds _ensure_array_items(schema) to spec_transform.py — a recursive helper that walks any schema dict and fills in "items": {} wherever "type": "array" appears without a sibling items key
  • Calls it from _filter_openapi_spec as a post-processing pass over every parameter schema and request body schema in the filtered paths
  • Adds tests/unit/test_spec_transform.py with 12 unit tests

Fixes #82

Why

The JSON Schema spec (and VS Code Copilot Agent Mode's strict validator) require every "type": "array" node to include an "items" property. The Rootly OpenAPI spec sometimes omits it, causing errors like:

Failed to validate tool mcp_rootly-mcp_createEscalationPath:
Error: tool parameters array type must have items.

Approach

The fix is entirely in the spec normalization layer (spec_transform.py), applied before FastMCP generates tools — so no MCP protocol behaviour, tool functionality, or client compatibility with Cursor/Claude Code/other clients is affected.

Missing items is filled with {} (accepts any element type), which is the minimally-restrictive JSON Schema default.

Test plan

  • 12 new unit tests in tests/unit/test_spec_transform.py — all pass
  • Full unit suite (360 tests) — no regressions
  • Covers: bare array, existing items unchanged, nested in object properties, array-of-arrays, deeply nested, allOf/anyOf/oneOf, request body schemas

🤖 Generated with Claude Code

VS Code GitHub Copilot Agent Mode strictly validates MCP tool schemas
against the JSON Schema spec and rejects any array-typed parameter that
lacks an `items` property, producing errors like:

  Failed to validate tool mcp_rootly-mcp_createEscalationPath:
  Error: tool parameters array type must have items.

Fixes Rootly-AI-Labs#82

Changes:
- Add `_ensure_array_items(schema)` to spec_transform.py — a recursive
  helper that walks any schema dict and fills in `"items": {}` wherever
  `"type": "array"` appears without a sibling `items` key. Recurses
  into object properties, array items, allOf/anyOf/oneOf, and
  additionalProperties.
- Call it from `_filter_openapi_spec` as a post-processing pass over
  every parameter schema and request body schema in the filtered paths,
  so all 99+ generated tools are covered.
- Add tests/unit/test_spec_transform.py with 12 unit tests covering
  the helper directly and its integration in _filter_openapi_spec.

No MCP protocol behaviour, tool functionality, or client compatibility
is affected — only the JSON Schema shape of the generated inputSchema.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 8, 2026

Greptile Summary

This PR adds a recursive _ensure_array_items helper to spec_transform.py that fills in "items": {} on any "type": "array" schema node missing that property, and wires it as a post-processing pass in _filter_openapi_spec. The fix is correctly scoped to the spec normalization layer and is accompanied by solid unit test coverage (12 tests).

Confidence Score: 5/5

Safe to merge — targeted spec normalization fix with no regressions and good test coverage.

All findings are P2 style suggestions (tuple-validation items list and not keyword edge cases). The core logic is correct for all realistic inputs from the Rootly OpenAPI spec, and the 12 new tests verify the main paths thoroughly.

No files require special attention.

Vulnerabilities

No security concerns identified. The change only adds a schema normalization pass over in-memory dicts before tool generation; it does not handle external input, credentials, or network calls.

Important Files Changed

Filename Overview
src/rootly_mcp_server/spec_transform.py Adds _ensure_array_items recursive helper and post-processing pass in _filter_openapi_spec; logic is correct and handles the primary cases well, with minor gaps for tuple-validation items lists and the not keyword.
tests/unit/test_spec_transform.py New test file with 12 unit tests covering bare arrays, existing items, nested objects, array-of-arrays, deep nesting, allOf/anyOf/oneOf, empty schemas, and request body integration — good coverage for the added functionality.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/rootly_mcp_server/spec_transform.py
Line: 568-570

Comment:
**Tuple-validation `items` list not recursed into**

When `items` is a JSON Schema array (tuple validation, e.g. `"items": [{"type": "string"}, {"type": "array"}]`), the current check skips recursion entirely, so any nested array schema inside that list won't receive the `items: {}` fix. This is unlikely in the Rootly spec, but worth a guard:

```suggestion
    # Recurse into items (array element schema or tuple-validation list)
    if "items" in schema:
        if isinstance(schema["items"], dict):
            _ensure_array_items(schema["items"])
        elif isinstance(schema["items"], list):
            for item_schema in schema["items"]:
                _ensure_array_items(item_schema)
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/rootly_mcp_server/spec_transform.py
Line: 572-580

Comment:
**`not` keyword not covered**

The `not` keyword (e.g. `"not": {"type": "array"}`) is a valid JSON Schema combinator and could contain an array schema without `items`. Adding it alongside `allOf`/`anyOf`/`oneOf` would make coverage complete:

```suggestion
    # Recurse into combination keywords
    for keyword in ("allOf", "anyOf", "oneOf"):
        for sub in schema.get(keyword, []):
            _ensure_array_items(sub)

    # Recurse into `not` schema
    if_not = schema.get("not")
    if isinstance(if_not, dict):
        _ensure_array_items(if_not)

    # Recurse into additionalProperties if it is a schema dict
    additional = schema.get("additionalProperties")
    if isinstance(additional, dict):
        _ensure_array_items(additional)
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix: add missing items property to array..." | Re-trigger Greptile

Comment thread src/rootly_mcp_server/spec_transform.py Outdated
Comment thread src/rootly_mcp_server/spec_transform.py
…ray_items

Address greptile review suggestions:
- Recurse into items when it is a list (JSON Schema tuple validation),
  not just when it is a dict, so nested array schemas in positional
  item validators also receive the items:{} fix.
- Recurse into the `not` keyword alongside allOf/anyOf/oneOf, covering
  the full set of JSON Schema combinators.

Add two matching unit tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@charryshun
Copy link
Copy Markdown
Author

Thanks for the review! Both suggestions were valid — applied in 6f1c14c:

  • Tuple-validation items list: _ensure_array_items now checks isinstance(schema["items"], list) and recurses into each element schema.
  • not keyword: Added recursion into schema.get("not") alongside allOf/anyOf/oneOf.

Two new unit tests cover these cases (test_tuple_validation_items_list_recursed and test_not_keyword_recursed), all 14 tests pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Tool schema validation fails in VS Code Copilot — array type missing items property

1 participant