From 9ff21437a03a28cfa33394bb330a4a41768f8c1c Mon Sep 17 00:00:00 2001 From: Dan Lynn Date: Sun, 19 Apr 2026 17:36:18 +0000 Subject: [PATCH] fix(mcp): coerce stringified arrays/objects in tool args When a tool schema declares `type: array` or `type: object` and the model emits the value as a JSON string (common with complex oneOf discriminated unions), the MCP server rejects it with -32602 "expected array, received string". Extend `_coerce_value` to attempt `json.loads` for these types and replace the string with the parsed value before dispatch. Root cause confirmed via live testing: `add_reminders.reminders` uses a oneOf discriminated union (relative/absolute/location) that triggers model output drift. Sending a real array passes validation; sending a string reproduces the exact error. Co-Authored-By: Claude Sonnet 4.6 --- model_tools.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/model_tools.py b/model_tools.py index bee80f49b..2b7767fda 100644 --- a/model_tools.py +++ b/model_tools.py @@ -418,6 +418,31 @@ def _coerce_value(value: str, expected_type): return _coerce_number(value, integer_only=(expected_type == "integer")) if expected_type == "boolean": return _coerce_boolean(value) + if expected_type == "array": + return _coerce_json(value, list) + if expected_type == "object": + return _coerce_json(value, dict) + return value + + +def _coerce_json(value: str, expected_python_type: type): + """Parse *value* as JSON when the schema expects an array or object. + + Handles model output drift where a complex oneOf/discriminated-union schema + causes the LLM to emit the array/object as a JSON string instead of a native + structure. Returns the original string if parsing fails or yields the wrong + Python type. + """ + try: + parsed = json.loads(value) + except (ValueError, TypeError): + return value + if isinstance(parsed, expected_python_type): + logger.debug( + "coerce_tool_args: coerced string to %s via json.loads", + expected_python_type.__name__, + ) + return parsed return value