mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-18 11:39:12 +02:00
#267 Fixed openapi template resource only supporting single param
This commit is contained in:
parent
ee68d1429d
commit
b684c0dbbf
2 changed files with 49 additions and 11 deletions
|
|
@ -278,21 +278,22 @@ class OpenAPIResource(Resource):
|
|||
if "{" in path and "}" in path:
|
||||
# Extract the resource ID from the URI (the last part after the last slash)
|
||||
parts = resource_uri.split("/")
|
||||
|
||||
if len(parts) > 1:
|
||||
# Find all path parameters in the route path
|
||||
path_params = {}
|
||||
|
||||
# Extract parameters from the URI
|
||||
param_value = parts[
|
||||
-1
|
||||
] # The last part contains the parameter value
|
||||
|
||||
# Find the path parameter name from the route path
|
||||
# Find the path parameter names from the route path
|
||||
param_matches = re.findall(r"\{([^}]+)\}", path)
|
||||
if param_matches:
|
||||
# Assume the last parameter in the URI is for the first path parameter in the route
|
||||
path_param_name = param_matches[0]
|
||||
path_params[path_param_name] = param_value
|
||||
# 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
|
||||
param_value = parts[-1-i] # Get values from the end of parts
|
||||
path_params[param_name] = param_value
|
||||
|
||||
# Replace path parameters with their values
|
||||
for param_name, param_value in path_params.items():
|
||||
|
|
|
|||
|
|
@ -50,6 +50,14 @@ def fastapi_app(users_db: dict[int, User]) -> FastAPI:
|
|||
async def get_user(user_id: int) -> User | None:
|
||||
"""Get a user by ID."""
|
||||
return users_db.get(user_id)
|
||||
|
||||
@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."""
|
||||
user = users_db.get(user_id)
|
||||
if user is not None and user.active == is_active:
|
||||
return user
|
||||
return None
|
||||
|
||||
@app.post("/users", tags=["users", "create"])
|
||||
async def create_user(user: UserCreate) -> User:
|
||||
|
|
@ -303,12 +311,17 @@ class TestResourceTemplates:
|
|||
"""
|
||||
async with Client(fastmcp_openapi_server) as client:
|
||||
resource_templates = await client.list_resource_templates()
|
||||
assert len(resource_templates) == 1
|
||||
assert len(resource_templates) == 2
|
||||
assert resource_templates[0].name == "get_user_users__user_id__get"
|
||||
assert (
|
||||
resource_templates[0].uriTemplate
|
||||
== r"resource://openapi/get_user_users__user_id__get/{user_id}"
|
||||
)
|
||||
assert resource_templates[1].name == "get_user_active_state_users__user_id___is_active__get"
|
||||
assert (
|
||||
resource_templates[1].uriTemplate
|
||||
== r"resource://openapi/get_user_active_state_users__user_id___is_active__get/{is_active}/{user_id}"
|
||||
)
|
||||
|
||||
async def test_get_resource_template(
|
||||
self,
|
||||
|
|
@ -333,6 +346,30 @@ class TestResourceTemplates:
|
|||
assert resource == response.json()
|
||||
|
||||
|
||||
async def test_get_resource_template_multi_param(
|
||||
self,
|
||||
fastmcp_openapi_server: FastMCPOpenAPI,
|
||||
api_client,
|
||||
users_db: dict[int, User],
|
||||
):
|
||||
"""
|
||||
The resource template created by the OpenAPI server should be the same as the original
|
||||
"""
|
||||
user_id = 2
|
||||
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}"
|
||||
)
|
||||
assert isinstance(resource_response[0], TextResourceContents)
|
||||
response_text = resource_response[0].text
|
||||
resource = json.loads(response_text)
|
||||
|
||||
assert resource == users_db[user_id].model_dump()
|
||||
response = await api_client.get(f"/users/{user_id}/{is_active}")
|
||||
assert resource == response.json()
|
||||
|
||||
|
||||
class TestPrompts:
|
||||
async def test_list_prompts(self, fastmcp_openapi_server: FastMCPOpenAPI):
|
||||
"""
|
||||
|
|
@ -818,7 +855,7 @@ class TestMountFastMCP:
|
|||
# Check that templates are available with prefixed URIs
|
||||
async with Client(mcp) as client:
|
||||
templates = await client.list_resource_templates()
|
||||
assert len(templates) == 1
|
||||
assert len(templates) == 2
|
||||
assert templates[0].name == "get_user_users__user_id__get"
|
||||
prefixed_template_uri = (
|
||||
r"fastapi+resource://openapi/get_user_users__user_id__get/{user_id}"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue