diff --git a/src/fastmcp/server/elicitation.py b/src/fastmcp/server/elicitation.py index c2a93a1f7..61fe1ca5b 100644 --- a/src/fastmcp/server/elicitation.py +++ b/src/fastmcp/server/elicitation.py @@ -304,15 +304,19 @@ def _dict_to_enum_schema( multi_select: If True, use anyOf pattern; if False, use oneOf pattern Returns: - {"oneOf": [{"const": "low", "title": "Low Priority"}, ...]} for single-select - {"anyOf": [{"const": "low", "title": "Low Priority"}, ...]} for multi-select + {"type": "string", "oneOf": [...]} for single-select + {"anyOf": [...]} for multi-select (used as array items) """ pattern_key = "anyOf" if multi_select else "oneOf" pattern = [] for value, metadata in enum_dict.items(): title = metadata.get("title", value) pattern.append({"const": value, "title": title}) - return {pattern_key: pattern} + + result: dict[str, Any] = {pattern_key: pattern} + if not multi_select: + result["type"] = "string" + return result def get_elicitation_schema(response_type: type[T]) -> dict[str, Any]: diff --git a/tests/client/test_elicitation.py b/tests/client/test_elicitation.py index b762eef26..47e962cd7 100644 --- a/tests/client/test_elicitation.py +++ b/tests/client/test_elicitation.py @@ -742,6 +742,17 @@ async def test_dict_based_titled_single_select(): return "declined" async def elicitation_handler(message, response_type, params, ctx): + # Verify schema follows SEP-1330 pattern with type: "string" + schema = params.requestedSchema + assert schema["type"] == "object" + assert "value" in schema["properties"] + value_schema = schema["properties"]["value"] + assert value_schema["type"] == "string" + assert "oneOf" in value_schema + one_of = value_schema["oneOf"] + assert {"const": "low", "title": "Low Priority"} in one_of + assert {"const": "high", "title": "High Priority"} in one_of + return ElicitResult(action="accept", content={"value": "low"}) async with Client(mcp, elicitation_handler=elicitation_handler) as client: @@ -800,14 +811,15 @@ async def test_list_dict_multi_select_titled(): return "declined" async def elicitation_handler(message, response_type, params, ctx): - # Verify schema has array with anyOf pattern + # Verify schema has array with SEP-1330 compliant items (anyOf pattern) schema = params.requestedSchema assert schema["type"] == "object" assert "value" in schema["properties"] value_schema = schema["properties"]["value"] assert value_schema["type"] == "array" - assert "anyOf" in value_schema["items"] - any_of = value_schema["items"]["anyOf"] + items_schema = value_schema["items"] + assert "anyOf" in items_schema + any_of = items_schema["anyOf"] assert {"const": "low", "title": "Low Priority"} in any_of assert {"const": "high", "title": "High Priority"} in any_of @@ -895,7 +907,7 @@ async def test_validation_allows_enum_arrays(): async def test_validation_allows_enum_arrays_with_anyof(): - """Test validation accepts arrays with anyOf enum pattern.""" + """Test validation accepts arrays with anyOf enum pattern (SEP-1330 compliant).""" schema = { "type": "object", "properties": {