Spaces:
Running
Running
Juergen Eger commited on
Commit ·
97708fa
1
Parent(s): 11780c0
openapi template resources with more than 1 path parameter is not supported #267
Browse files
src/fastmcp/server/openapi.py
CHANGED
|
@@ -286,12 +286,14 @@ class OpenAPIResource(Resource):
|
|
| 286 |
# Find the path parameter names from the route path
|
| 287 |
param_matches = re.findall(r"\{([^}]+)\}", path)
|
| 288 |
if param_matches:
|
|
|
|
|
|
|
| 289 |
# Number of sent parameters is number of parts -1 (assuming first part is resource identifier)
|
| 290 |
expected_param_count = len(parts) -1
|
| 291 |
# Map parameters from the end of the URI to the parameters in the path
|
| 292 |
# Last parameter in URI (parts[-1]) maps to last parameter in path, and so on
|
| 293 |
for i, param_name in enumerate(param_matches):
|
| 294 |
-
if i <
|
| 295 |
param_value = parts[-1-i] # Get values from the end of parts
|
| 296 |
path_params[param_name] = param_value
|
| 297 |
|
|
|
|
| 286 |
# Find the path parameter names from the route path
|
| 287 |
param_matches = re.findall(r"\{([^}]+)\}", path)
|
| 288 |
if param_matches:
|
| 289 |
+
# Reverse sorting from creation order (traversal is backwards)
|
| 290 |
+
param_matches.sort(reverse=True)
|
| 291 |
# Number of sent parameters is number of parts -1 (assuming first part is resource identifier)
|
| 292 |
expected_param_count = len(parts) -1
|
| 293 |
# Map parameters from the end of the URI to the parameters in the path
|
| 294 |
# Last parameter in URI (parts[-1]) maps to last parameter in path, and so on
|
| 295 |
for i, param_name in enumerate(param_matches):
|
| 296 |
+
if i < expected_param_count: # Ensure we don't use resource identifier as parameter
|
| 297 |
param_value = parts[-1-i] # Get values from the end of parts
|
| 298 |
path_params[param_name] = param_value
|
| 299 |
|
tests/server/test_openapi.py
CHANGED
|
@@ -53,7 +53,7 @@ def fastapi_app(users_db: dict[int, User]) -> FastAPI:
|
|
| 53 |
|
| 54 |
@app.get("/users/{user_id}/{is_active}", tags=["users", "detail"])
|
| 55 |
async def get_user_active_state(user_id: int, is_active: bool) -> User | None:
|
| 56 |
-
"""Get a user by ID."""
|
| 57 |
user = users_db.get(user_id)
|
| 58 |
if user is not None and user.active == is_active:
|
| 59 |
return user
|
|
@@ -359,7 +359,7 @@ class TestResourceTemplates:
|
|
| 359 |
is_active = True
|
| 360 |
async with Client(fastmcp_openapi_server) as client:
|
| 361 |
resource_response = await client.read_resource(
|
| 362 |
-
f"resource://openapi/
|
| 363 |
)
|
| 364 |
assert isinstance(resource_response[0], TextResourceContents)
|
| 365 |
response_text = resource_response[0].text
|
|
|
|
| 53 |
|
| 54 |
@app.get("/users/{user_id}/{is_active}", tags=["users", "detail"])
|
| 55 |
async def get_user_active_state(user_id: int, is_active: bool) -> User | None:
|
| 56 |
+
"""Get a user by ID and filter by active state."""
|
| 57 |
user = users_db.get(user_id)
|
| 58 |
if user is not None and user.active == is_active:
|
| 59 |
return user
|
|
|
|
| 359 |
is_active = True
|
| 360 |
async with Client(fastmcp_openapi_server) as client:
|
| 361 |
resource_response = await client.read_resource(
|
| 362 |
+
f"resource://openapi/get_user_active_state_users__user_id___is_active__get/{is_active}/{user_id}"
|
| 363 |
)
|
| 364 |
assert isinstance(resource_response[0], TextResourceContents)
|
| 365 |
response_text = resource_response[0].text
|