diff --git a/src/fastmcp/utilities/openapi.py b/src/fastmcp/utilities/openapi.py index 0cae85cb2..59d558f72 100644 --- a/src/fastmcp/utilities/openapi.py +++ b/src/fastmcp/utilities/openapi.py @@ -302,11 +302,17 @@ class OpenAPIParser( # Extract parameter info - handle both 3.0 and 3.1 parameter models param_in = parameter.param_in # Both use param_in - param_location = self._convert_to_parameter_location(param_in) + # Handle enum or string parameter locations + from enum import Enum + + param_in_str = ( + param_in.value if isinstance(param_in, Enum) else param_in + ) + param_location = self._convert_to_parameter_location(param_in_str) param_schema_obj = parameter.param_schema # Both use param_schema # Skip duplicate parameters (same name and location) - param_key = (parameter.name, param_in) + param_key = (parameter.name, param_in_str) if param_key in seen_params: continue seen_params[param_key] = True diff --git a/tests/server/openapi/test_openapi_path_parameters.py b/tests/server/openapi/test_openapi_path_parameters.py index 078e61a58..7f977ea50 100644 --- a/tests/server/openapi/test_openapi_path_parameters.py +++ b/tests/server/openapi/test_openapi_path_parameters.py @@ -455,3 +455,31 @@ async def test_array_query_parameter_exploded_format(mock_client): json=None, timeout=None, ) + + +def test_parameter_location_enum_handling(): + """Test that ParameterLocation enum values are handled correctly (issue #950).""" + from enum import Enum + + # Create a mock ParameterLocation enum like the one from openapi_pydantic + class MockParameterLocation(Enum): + PATH = "path" + QUERY = "query" + HEADER = "header" + COOKIE = "cookie" + + # Test the enum handling logic directly (reproduces the fix in openapi.py) + test_cases = [ + (MockParameterLocation.PATH, "path"), + (MockParameterLocation.QUERY, "query"), + (MockParameterLocation.HEADER, "header"), + (MockParameterLocation.COOKIE, "cookie"), + ("path", "path"), # Also test that strings work + ("query", "query"), + ] + + for param_in, expected_str in test_cases: + # This is the enum handling logic from the fix + param_in_str = param_in.value if isinstance(param_in, Enum) else param_in + assert param_in_str == expected_str + assert isinstance(param_in_str, str)