[PR #300] fix: handle list-valued JSON Schema array items (tuple validation) #247

Open
opened 2026-10-18 21:12:59 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/mcpo/pull/300
Author: @SaurabhMaydeo
Created: 6/26/2026
Status: 🔄 Open

Base: dev ← Head: fix/array-tuple-items


📝 Commits (1)

  • 3ac6764 fix: handle list-valued JSON Schema array items (tuple validation)

📊 Changes

2 files changed (+102 additions, -2 deletions)

View changed files

📝 src/mcpo/tests/test_main.py (+61 -0)
📝 src/mcpo/utils/main.py (+41 -2)

📄 Description

Pull Request Checklist

  • Target branch: targets the dev branch.
  • Description: provided below.
  • Changelog: entry added below (Keep a Changelog format).
  • Dependencies: no new dependencies.
  • Testing: unit tests added and run — full suite passes (32 passed).
  • Code review: self-reviewed.
  • Prefix: title uses the fix: prefix.

Changelog Entry

Description

_process_schema_property assumed a property's items is always a single schema object. JSON Schema also allows items to be a list of schemas (tuple validation in Draft-07; Draft 2020-12 calls it prefixItems). When an MCP server emits that form, the list was passed into the recursive call and prop_schema.get("type") raised AttributeError: 'list' object has no attribute 'get'. Because this happens while building the route, the whole tool's endpoint failed to mount.

Reproduced with @brave/brave-search-mcp-server (#296). Minimal repro:

_process_schema_property({}, {"type": "array",
    "items": [{"type": "string"}, {"type": "integer"}]}, "test", "prop", True)
# before: AttributeError: 'list' object has no attribute 'get'
# after:  typing.List[typing.Union[str, int]]

The fix handles list-valued items (and the 2020-12 prefixItems form) by building List[Union[...]] over the element schemas, mirroring how the function already handles anyOf and multi-type type lists. Non-object elements (e.g. boolean sub-schemas) and empty tuples fall back to List[Any] instead of crashing. This is a deliberate approximation — it does not model positional or fixed-length tuple semantics; the goal is to stop the mount-time crash and keep OpenAPI generation working. Happy to collapse it to a plain List[Any] if you'd prefer the smaller change.

Added

  • Regression tests in src/mcpo/tests/test_main.py for tuple-validation arrays: list items, prefixItems, single element, empty list, and a non-object (boolean) element.

Changed

  • None.

Deprecated

  • None.

Removed

  • None.

Fixed

  • AttributeError: 'list' object has no attribute 'get' when a tool's input schema uses list-valued items / prefixItems (tuple validation), which previously stopped the tool's endpoint from mounting (#296).

Security

  • None.

Breaking Changes

  • None. The new code path only runs for tuple-style schemas; the existing single-object items path is unchanged.

Additional Information

  • Closes #296. The approach matches the isinstance(items_schema, list) guard suggested by the reporter in that issue.
  • Scope: src/mcpo/utils/main.py (the array branch of _process_schema_property) plus tests in src/mcpo/tests/test_main.py. Behavior-preserving for all existing schemas.

Screenshots or Videos

  • N/A — logic fix; covered by unit tests (pytest src/mcpo/tests/ → 32 passed).

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/mcpo/pull/300 **Author:** [@SaurabhMaydeo](https://github.com/SaurabhMaydeo) **Created:** 6/26/2026 **Status:** 🔄 Open **Base:** `dev` ← **Head:** `fix/array-tuple-items` --- ### 📝 Commits (1) - [`3ac6764`](https://github.com/open-webui/mcpo/commit/3ac676403e24766d9d01042297c634a9fde41263) fix: handle list-valued JSON Schema array items (tuple validation) ### 📊 Changes **2 files changed** (+102 additions, -2 deletions) <details> <summary>View changed files</summary> 📝 `src/mcpo/tests/test_main.py` (+61 -0) 📝 `src/mcpo/utils/main.py` (+41 -2) </details> ### 📄 Description # Pull Request Checklist - [x] **Target branch:** targets the `dev` branch. - [x] **Description:** provided below. - [x] **Changelog:** entry added below (Keep a Changelog format). - [x] **Dependencies:** no new dependencies. - [x] **Testing:** unit tests added and run — full suite passes (32 passed). - [x] **Code review:** self-reviewed. - [x] **Prefix:** title uses the `fix:` prefix. # Changelog Entry ### Description `_process_schema_property` assumed a property's `items` is always a single schema object. JSON Schema also allows `items` to be a list of schemas (tuple validation in Draft-07; Draft 2020-12 calls it `prefixItems`). When an MCP server emits that form, the list was passed into the recursive call and `prop_schema.get("type")` raised `AttributeError: 'list' object has no attribute 'get'`. Because this happens while building the route, the whole tool's endpoint failed to mount. Reproduced with `@brave/brave-search-mcp-server` (#296). Minimal repro: ```python _process_schema_property({}, {"type": "array", "items": [{"type": "string"}, {"type": "integer"}]}, "test", "prop", True) # before: AttributeError: 'list' object has no attribute 'get' # after: typing.List[typing.Union[str, int]] ``` The fix handles list-valued `items` (and the 2020-12 `prefixItems` form) by building `List[Union[...]]` over the element schemas, mirroring how the function already handles `anyOf` and multi-type `type` lists. Non-object elements (e.g. boolean sub-schemas) and empty tuples fall back to `List[Any]` instead of crashing. This is a deliberate approximation — it does not model positional or fixed-length tuple semantics; the goal is to stop the mount-time crash and keep OpenAPI generation working. Happy to collapse it to a plain `List[Any]` if you'd prefer the smaller change. ### Added - Regression tests in `src/mcpo/tests/test_main.py` for tuple-validation arrays: list `items`, `prefixItems`, single element, empty list, and a non-object (boolean) element. ### Changed - None. ### Deprecated - None. ### Removed - None. ### Fixed - `AttributeError: 'list' object has no attribute 'get'` when a tool's input schema uses list-valued `items` / `prefixItems` (tuple validation), which previously stopped the tool's endpoint from mounting (#296). ### Security - None. ### Breaking Changes - None. The new code path only runs for tuple-style schemas; the existing single-object `items` path is unchanged. --- ### Additional Information - Closes #296. The approach matches the `isinstance(items_schema, list)` guard suggested by the reporter in that issue. - Scope: `src/mcpo/utils/main.py` (the `array` branch of `_process_schema_property`) plus tests in `src/mcpo/tests/test_main.py`. Behavior-preserving for all existing schemas. ### Screenshots or Videos - N/A — logic fix; covered by unit tests (`pytest src/mcpo/tests/` → 32 passed). --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
open-webui/mcpo#247
No description provided.