diff --git a/litellm/proxy/_experimental/mcp_server/openapi_to_mcp_generator.py b/litellm/proxy/_experimental/mcp_server/openapi_to_mcp_generator.py index 96ab4423d9..9312764aa8 100644 --- a/litellm/proxy/_experimental/mcp_server/openapi_to_mcp_generator.py +++ b/litellm/proxy/_experimental/mcp_server/openapi_to_mcp_generator.py @@ -42,6 +42,80 @@ def _sanitize_path_parameter_value(param_value: Any, param_name: str) -> str: return quote(value_str, safe="") +async def _invoke_openapi_operation( + *, + method: str, + base_url: str, + path: str, + headers: Dict[str, str], + path_params: list, + query_params: list, + body_params: list, + provided_params: Dict[str, Any], +) -> str: + """Execute the OpenAPI operation using provided parameters.""" + + url = base_url + path + + # Replace path parameters with sanitized values + for param_name in path_params: + param_value = provided_params.get(param_name, "") + if param_value: + try: + safe_value = _sanitize_path_parameter_value(param_value, param_name) + except ValueError as exc: + return "Invalid path parameter: " + str(exc) + url = url.replace("{" + param_name + "}", safe_value) + + # Build query params + params: Dict[str, Any] = {} + for param_name in query_params: + param_value = provided_params.get(param_name, "") + if param_value: + params[param_name] = param_value + + # Build request body + json_body = None + if body_params: + body_value = provided_params.get("body", {}) + if isinstance(body_value, dict): + json_body = body_value + elif body_value: + import json as json_module + + try: + json_body = ( + json_module.loads(body_value) + if isinstance(body_value, str) + else {"data": body_value} + ) + except Exception: + json_body = {"data": body_value} + + async with httpx.AsyncClient() as client: + method_lower = method.lower() + if method_lower == "get": + response = await client.get(url, params=params, headers=headers) + elif method_lower == "post": + response = await client.post( + url, params=params, json=json_body, headers=headers + ) + elif method_lower == "put": + response = await client.put( + url, params=params, json=json_body, headers=headers + ) + elif method_lower == "delete": + response = await client.delete(url, params=params, headers=headers) + elif method_lower == "patch": + response = await client.patch( + url, params=params, json=json_body, headers=headers + ) + else: + return f"Unsupported HTTP method: {method}" + + return response.text + + def load_openapi_spec(filepath: str) -> Dict[str, Any]: """Load OpenAPI specification from JSON file.""" with open(filepath, "r") as f: @@ -160,59 +234,19 @@ def create_tool_function( func_code = f''' async def tool_function({params_str}) -> str: """Dynamically generated tool function.""" - url = base_url + path - - # Replace path parameters - path_param_names = {path_params} - for param_name in path_param_names: - param_value = locals().get(param_name, "") - if param_value: - # url = url.replace("{{" + param_name + "}}", str(param_value)) - try: - safe_value = _sanitize_path_parameter_value(param_value, param_name) - except ValueError as exc: - return "Invalid path parameter: " + str(exc) - url = url.replace("{{" + param_name + "}}", safe_value) - - # Build query params - query_param_names = {query_params} - params = {{}} - for param_name in query_param_names: - param_value = locals().get(param_name, "") - if param_value: - params[param_name] = param_value - - # Build request body - body_param_names = {body_params} - json_body = None - if body_param_names: - body_value = locals().get("body", {{}}) - if isinstance(body_value, dict): - json_body = body_value - elif body_value: - # If it's a string, try to parse as JSON - import json as json_module - try: - json_body = json_module.loads(body_value) if isinstance(body_value, str) else {{"data": body_value}} - except: - json_body = {{"data": body_value}} - - # Make HTTP request - async with httpx.AsyncClient() as client: - if "{method.lower()}" == "get": - response = await client.get(url, params=params, headers=headers) - elif "{method.lower()}" == "post": - response = await client.post(url, params=params, json=json_body, headers=headers) - elif "{method.lower()}" == "put": - response = await client.put(url, params=params, json=json_body, headers=headers) - elif "{method.lower()}" == "delete": - response = await client.delete(url, params=params, headers=headers) - elif "{method.lower()}" == "patch": - response = await client.patch(url, params=params, json=json_body, headers=headers) - else: - return "Unsupported HTTP method: {method}" - - return response.text + provided_params = {{}} + for param_name in {all_params}: + provided_params[param_name] = locals().get(param_name, "") + return await _invoke_openapi_operation( + method="{method}", + base_url=base_url, + path=path, + headers=headers, + path_params={path_params}, + query_params={query_params}, + body_params={body_params}, + provided_params=provided_params, + ) ''' # Execute the function code to create the actual function @@ -222,7 +256,7 @@ async def tool_function({params_str}) -> str: "base_url": base_url, "path": path, "method": method, - "_sanitize_path_parameter_value": _sanitize_path_parameter_value, + "_invoke_openapi_operation": _invoke_openapi_operation, } exec(func_code, local_vars)