From 87c63ec343a1a51e8ce67ddf4763eb6384eb05c0 Mon Sep 17 00:00:00 2001 From: Juergen Eger <11678629+jeger-at@users.noreply.github.com> Date: Tue, 29 Apr 2025 08:04:04 +0000 Subject: [PATCH] openapi template resources with more than 1 path parameter is not supported #267 --- src/fastmcp/server/openapi.py | 4 +++- tests/server/test_openapi.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/fastmcp/server/openapi.py b/src/fastmcp/server/openapi.py index 88539ff65..a2dd3e21e 100644 --- a/src/fastmcp/server/openapi.py +++ b/src/fastmcp/server/openapi.py @@ -286,12 +286,14 @@ class OpenAPIResource(Resource): # Find the path parameter names from the route path param_matches = re.findall(r"\{([^}]+)\}", path) if param_matches: + # Reverse sorting from creation order (traversal is backwards) + param_matches.sort(reverse=True) # Number of sent parameters is number of parts -1 (assuming first part is resource identifier) expected_param_count = len(parts) -1 # Map parameters from the end of the URI to the parameters in the path # Last parameter in URI (parts[-1]) maps to last parameter in path, and so on for i, param_name in enumerate(param_matches): - if i < len(expected_param_count): # Ensure we don't use resource identifier as parameter + if i < expected_param_count: # Ensure we don't use resource identifier as parameter param_value = parts[-1-i] # Get values from the end of parts path_params[param_name] = param_value diff --git a/tests/server/test_openapi.py b/tests/server/test_openapi.py index 5d0506648..091b158db 100644 --- a/tests/server/test_openapi.py +++ b/tests/server/test_openapi.py @@ -53,7 +53,7 @@ def fastapi_app(users_db: dict[int, User]) -> FastAPI: @app.get("/users/{user_id}/{is_active}", tags=["users", "detail"]) async def get_user_active_state(user_id: int, is_active: bool) -> User | None: - """Get a user by ID.""" + """Get a user by ID and filter by active state.""" user = users_db.get(user_id) if user is not None and user.active == is_active: return user @@ -359,7 +359,7 @@ class TestResourceTemplates: is_active = True async with Client(fastmcp_openapi_server) as client: resource_response = await client.read_resource( - f"resource://openapi/get_user_users__user_type__user_id__get/{user_id}/{is_active}" + f"resource://openapi/get_user_active_state_users__user_id___is_active__get/{is_active}/{user_id}" ) assert isinstance(resource_response[0], TextResourceContents) response_text = resource_response[0].text