From 78f270cdeff52c11c58dc640dee8fa0c727c266e Mon Sep 17 00:00:00 2001 From: Vincent <0426vincent@gmail.com> Date: Sat, 1 Nov 2025 22:41:07 -0700 Subject: [PATCH 1/3] fix: Support string enum for elicitation --- src/mcp/server/elicitation.py | 7 ++++- tests/server/fastmcp/test_elicitation.py | 34 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/mcp/server/elicitation.py b/src/mcp/server/elicitation.py index 49195415b..ab2c9ad6a 100644 --- a/src/mcp/server/elicitation.py +++ b/src/mcp/server/elicitation.py @@ -4,6 +4,7 @@ import types from collections.abc import Sequence +from enum import Enum, StrEnum from typing import Generic, Literal, TypeVar, Union, get_args, get_origin from pydantic import BaseModel @@ -46,7 +47,7 @@ class AcceptedUrlElicitation(BaseModel): # Primitive types allowed in elicitation schemas -_ELICITATION_PRIMITIVE_TYPES = (str, int, float, bool) +_ELICITATION_PRIMITIVE_TYPES = (str, int, float, bool, StrEnum) def _validate_elicitation_schema(schema: type[BaseModel]) -> None: @@ -99,6 +100,10 @@ def _is_primitive_field(annotation: type) -> bool: arg is types.NoneType or arg in _ELICITATION_PRIMITIVE_TYPES or _is_string_sequence(arg) for arg in args ) + # Handle Enum types + if issubclass(annotation, str) and issubclass(annotation, Enum): + return True + return False diff --git a/tests/server/fastmcp/test_elicitation.py b/tests/server/fastmcp/test_elicitation.py index 597b29178..6ca0a63ba 100644 --- a/tests/server/fastmcp/test_elicitation.py +++ b/tests/server/fastmcp/test_elicitation.py @@ -2,6 +2,7 @@ Test the elicitation feature using stdio transport. """ +from enum import StrEnum from typing import Any import pytest @@ -147,6 +148,39 @@ async def elicitation_callback( assert "Validation failed as expected" in result.content[0].text assert field_name in result.content[0].text + # Test valid Enum types (should not fail validation) + class Status(StrEnum): + ACTIVE = "active" + INACTIVE = "inactive" + + class ValidStrEnumSchema(BaseModel): + status: Status = Field(description="Status using StrEnum") + + def create_valid_validation_tool(name: str, schema_class: type[BaseModel]): + @mcp.tool(name=name, description=f"Tool testing {name}") + async def tool(ctx: Context[ServerSession, None]) -> str: + # This should succeed without validation error + result = await ctx.elicit(message="Test valid schema", schema=schema_class) + return f"Success: {result.action}" + + return tool + + create_valid_validation_tool("valid_strenum", ValidStrEnumSchema) + + async def enum_callback(context: RequestContext[ClientSession, None], params: ElicitRequestParams): + # Return the required status field + return ElicitResult(action="accept", content={"status": "active"}) + + async with create_connected_server_and_client_session( + mcp._mcp_server, elicitation_callback=enum_callback + ) as client_session: + await client_session.initialize() + + result = await client_session.call_tool("valid_strenum", {}) + assert len(result.content) == 1 + assert isinstance(result.content[0], TextContent) + assert "Success: accept" == result.content[0].text + @pytest.mark.anyio async def test_elicitation_with_optional_fields(): From 97b156ddabccc9c8a03a51a494ed764f813c3d43 Mon Sep 17 00:00:00 2001 From: Vincent <0426vincent@gmail.com> Date: Sat, 1 Nov 2025 23:03:23 -0700 Subject: [PATCH 2/3] fix: Remove StrEnum due to versioning --- src/mcp/server/elicitation.py | 4 ++-- tests/server/fastmcp/test_elicitation.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mcp/server/elicitation.py b/src/mcp/server/elicitation.py index ab2c9ad6a..2cfcbcb3c 100644 --- a/src/mcp/server/elicitation.py +++ b/src/mcp/server/elicitation.py @@ -4,7 +4,7 @@ import types from collections.abc import Sequence -from enum import Enum, StrEnum +from enum import Enum from typing import Generic, Literal, TypeVar, Union, get_args, get_origin from pydantic import BaseModel @@ -47,7 +47,7 @@ class AcceptedUrlElicitation(BaseModel): # Primitive types allowed in elicitation schemas -_ELICITATION_PRIMITIVE_TYPES = (str, int, float, bool, StrEnum) +_ELICITATION_PRIMITIVE_TYPES = (str, int, float, bool, Enum) def _validate_elicitation_schema(schema: type[BaseModel]) -> None: diff --git a/tests/server/fastmcp/test_elicitation.py b/tests/server/fastmcp/test_elicitation.py index 6ca0a63ba..5d3b1a29a 100644 --- a/tests/server/fastmcp/test_elicitation.py +++ b/tests/server/fastmcp/test_elicitation.py @@ -2,7 +2,7 @@ Test the elicitation feature using stdio transport. """ -from enum import StrEnum +from enum import Enum from typing import Any import pytest @@ -149,7 +149,7 @@ async def elicitation_callback( assert field_name in result.content[0].text # Test valid Enum types (should not fail validation) - class Status(StrEnum): + class Status(str, Enum): ACTIVE = "active" INACTIVE = "inactive" From d04ba8c5faa88177beb9f2755726f2b973893e2a Mon Sep 17 00:00:00 2001 From: Vincent <0426vincent@gmail.com> Date: Fri, 19 Dec 2025 10:14:51 -0800 Subject: [PATCH 3/3] fix: Add explicit type check --- src/mcp/server/elicitation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mcp/server/elicitation.py b/src/mcp/server/elicitation.py index 2cfcbcb3c..553766811 100644 --- a/src/mcp/server/elicitation.py +++ b/src/mcp/server/elicitation.py @@ -101,7 +101,7 @@ def _is_primitive_field(annotation: type) -> bool: ) # Handle Enum types - if issubclass(annotation, str) and issubclass(annotation, Enum): + if isinstance(annotation, type) and issubclass(annotation, str) and issubclass(annotation, Enum): # type: ignore[arg-type] return True return False