mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-14 23:21:35 +00:00
Align preview HTTP method order with register_tools_from_openapi
The preview endpoint and register_tools_from_openapi both use order-dependent collision disambiguation (_2, _3 suffixes). When the iteration order differs, two operations on the same path with sanitized names that collide get different suffixes in preview vs registration, so the dashboard shows names that don't match what actually got registered. Also adds a regression test that fails on the swapped order. Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
This commit is contained in:
parent
b47d25318d
commit
56ef1ed003
2 changed files with 91 additions and 1 deletions
|
|
@ -990,7 +990,7 @@ if MCP_AVAILABLE:
|
|||
tools: List[dict] = []
|
||||
used_names: set = set()
|
||||
for path, path_item in paths.items():
|
||||
for method in ("get", "post", "put", "patch", "delete"):
|
||||
for method in ("get", "post", "put", "delete", "patch"):
|
||||
operation = path_item.get(method)
|
||||
if operation is None:
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -1447,3 +1447,93 @@ class TestPreviewOpenAPITools:
|
|||
), f"preview tool name {name!r} violates ^[a-zA-Z0-9_-]+$"
|
||||
assert "actions_download-job-logs-for-workflow-run" in names
|
||||
assert "pulls_list-files" in names
|
||||
|
||||
async def test_preview_method_order_matches_registration(self, monkeypatch):
|
||||
"""Preview must iterate HTTP methods in the same order as
|
||||
register_tools_from_openapi, otherwise collision-disambiguation
|
||||
suffixes (_2, _3, ...) get assigned to different operations and the
|
||||
dashboard shows names that differ from what's actually registered.
|
||||
"""
|
||||
from litellm.proxy._experimental.mcp_server import (
|
||||
openapi_to_mcp_generator,
|
||||
)
|
||||
|
||||
spec = {
|
||||
"paths": {
|
||||
"/items/{id}": {
|
||||
"delete": {
|
||||
"operationId": "items/delete",
|
||||
"summary": "Delete item",
|
||||
},
|
||||
"patch": {
|
||||
"operationId": "items.delete",
|
||||
"summary": "Soft-delete item",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async def fake_load_spec(spec_path): # noqa: ANN001
|
||||
return spec
|
||||
|
||||
monkeypatch.setattr(
|
||||
openapi_to_mcp_generator,
|
||||
"load_openapi_spec_async",
|
||||
fake_load_spec,
|
||||
raising=False,
|
||||
)
|
||||
|
||||
payload = NewMCPServerRequest(
|
||||
server_name="collision_openapi_mcp",
|
||||
spec_path="https://example.invalid/openapi.json",
|
||||
transport="http",
|
||||
)
|
||||
request = _build_request()
|
||||
from litellm.proxy._types import LitellmUserRoles
|
||||
|
||||
result = await rest_endpoints.test_tools_list(
|
||||
request,
|
||||
payload,
|
||||
user_api_key_dict=UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN),
|
||||
)
|
||||
assert result.get("error") is None, result
|
||||
preview_summary_to_name = {t["description"]: t["name"] for t in result["tools"]}
|
||||
|
||||
registered_summary_to_name: dict = {}
|
||||
|
||||
def fake_create_tool_function(
|
||||
path, method, operation, base_url
|
||||
): # noqa: ANN001
|
||||
def _f():
|
||||
return None
|
||||
|
||||
return _f
|
||||
|
||||
monkeypatch.setattr(
|
||||
openapi_to_mcp_generator,
|
||||
"create_tool_function",
|
||||
fake_create_tool_function,
|
||||
)
|
||||
|
||||
class _StubRegistry:
|
||||
def register_tool(
|
||||
self, name, description, input_schema, handler
|
||||
): # noqa: ANN001
|
||||
registered_summary_to_name[description] = name
|
||||
|
||||
monkeypatch.setattr(
|
||||
openapi_to_mcp_generator,
|
||||
"global_mcp_tool_registry",
|
||||
_StubRegistry(),
|
||||
)
|
||||
|
||||
openapi_to_mcp_generator.register_tools_from_openapi(
|
||||
spec, base_url="https://example.invalid"
|
||||
)
|
||||
|
||||
assert preview_summary_to_name == registered_summary_to_name, (
|
||||
f"preview {preview_summary_to_name} != "
|
||||
f"registered {registered_summary_to_name} — method iteration "
|
||||
"order is out of sync, so collision suffixes (_2, _3, ...) "
|
||||
"land on different operations"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue