|
3 | 3 | from typing import Annotated, Any |
4 | 4 |
|
5 | 5 | from fastapi import APIRouter, Depends, HTTPException, Request, status |
6 | | -from llama_stack_client import APIConnectionError |
| 6 | +from llama_stack_api.common.errors import ToolGroupNotFoundError |
| 7 | +from llama_stack_client import APIConnectionError, NotFoundError |
7 | 8 |
|
8 | 9 | from authentication import get_auth_dependency |
9 | 10 | from authentication.interface import AuthTuple |
|
17 | 18 | ConflictResponse, |
18 | 19 | ForbiddenResponse, |
19 | 20 | InternalServerErrorResponse, |
20 | | - NotFoundResponse, |
21 | 21 | ServiceUnavailableResponse, |
22 | 22 | UnauthorizedResponse, |
23 | 23 | ) |
|
39 | 39 | 401: UnauthorizedResponse.openapi_response(examples=UNAUTHORIZED_OPENAPI_EXAMPLES), |
40 | 40 | 403: ForbiddenResponse.openapi_response(examples=["endpoint"]), |
41 | 41 | 409: ConflictResponse.openapi_response(examples=["mcp server"]), |
42 | | - 500: InternalServerErrorResponse.openapi_response(examples=["configuration"]), |
| 42 | + 500: InternalServerErrorResponse.openapi_response( |
| 43 | + examples=["configuration", "mcp server registration"] |
| 44 | + ), |
43 | 45 | 503: ServiceUnavailableResponse.openapi_response( |
44 | 46 | examples=["llama stack", "kubernetes api"] |
45 | 47 | ), |
@@ -109,10 +111,7 @@ async def register_mcp_server_handler( |
109 | 111 | except Exception as e: # pylint: disable=broad-exception-caught |
110 | 112 | configuration.remove_mcp_server(body.name) |
111 | 113 | logger.error("Failed to register MCP toolgroup: %s", e) |
112 | | - error_response = InternalServerErrorResponse( |
113 | | - response="Failed to register MCP server", |
114 | | - cause=str(e), |
115 | | - ) |
| 114 | + error_response = InternalServerErrorResponse.mcp_server_registration_failed() |
116 | 115 | raise HTTPException(**error_response.model_dump()) from e |
117 | 116 |
|
118 | 117 | logger.info("Dynamically registered MCP server: %s at %s", body.name, body.url) |
@@ -178,8 +177,7 @@ async def list_mcp_servers_handler( |
178 | 177 | delete_responses: dict[int | str, dict[str, Any]] = { |
179 | 178 | 200: MCPServerDeleteResponse.openapi_response(), |
180 | 179 | 401: UnauthorizedResponse.openapi_response(examples=UNAUTHORIZED_OPENAPI_EXAMPLES), |
181 | | - 403: ForbiddenResponse.openapi_response(examples=["endpoint"]), |
182 | | - 404: NotFoundResponse.openapi_response(examples=["mcp server"]), |
| 180 | + 403: ForbiddenResponse.openapi_response(examples=["endpoint", "mcp server static"]), |
183 | 181 | 500: InternalServerErrorResponse.openapi_response(examples=["configuration"]), |
184 | 182 | 503: ServiceUnavailableResponse.openapi_response( |
185 | 183 | examples=["llama stack", "kubernetes api"] |
@@ -218,46 +216,30 @@ async def delete_mcp_server_handler( |
218 | 216 | check_configuration_loaded(configuration) |
219 | 217 |
|
220 | 218 | if not configuration.is_dynamic_mcp_server(name): |
221 | | - found = any(s.name == name for s in configuration.mcp_servers) |
222 | | - if found: |
223 | | - response = ForbiddenResponse( |
224 | | - response="Cannot delete statically configured MCP server", |
225 | | - cause=f"MCP server '{name}' was configured in lightspeed-stack.yaml " |
226 | | - "and cannot be removed via the API.", |
227 | | - ) |
228 | | - else: |
229 | | - response = NotFoundResponse(resource="MCP server", resource_id=name) |
230 | | - raise HTTPException(**response.model_dump()) |
| 219 | + static_mcp_names = {s.name for s in configuration.mcp_servers} |
| 220 | + if name in static_mcp_names: |
| 221 | + response = ForbiddenResponse.mcp_server_static_config(name) |
| 222 | + raise HTTPException(**response.model_dump()) |
231 | 223 |
|
232 | 224 | try: |
233 | 225 | client = AsyncLlamaStackClientHolder().get_client() |
234 | 226 | await client.toolgroups.unregister( # pyright: ignore[reportDeprecated] |
235 | 227 | toolgroup_id=name |
236 | 228 | ) |
237 | 229 | except APIConnectionError as e: |
238 | | - logger.error("Failed to unregister MCP toolgroup from Llama Stack: %s", e) |
| 230 | + logger.error("Failed to connect to Llama Stack: %s", e) |
239 | 231 | svc_response = ServiceUnavailableResponse( |
240 | 232 | backend_name="Llama Stack", cause=str(e) |
241 | 233 | ) |
242 | 234 | raise HTTPException(**svc_response.model_dump()) from e |
243 | | - except Exception as e: # pylint: disable=broad-exception-caught |
244 | | - logger.warning( |
245 | | - "Llama Stack toolgroup unregister failed for '%s', " |
246 | | - "proceeding with local removal: %s", |
247 | | - name, |
248 | | - e, |
249 | | - ) |
| 235 | + except (ToolGroupNotFoundError, NotFoundError): |
| 236 | + logger.warning("MCP server not found, treating as already deleted.") |
250 | 237 |
|
251 | 238 | try: |
252 | 239 | configuration.remove_mcp_server(name) |
| 240 | + local_deleted = True |
253 | 241 | except ValueError as e: |
254 | 242 | logger.error("Failed to remove MCP server from configuration: %s", e) |
255 | | - response = NotFoundResponse(resource="MCP server", resource_id=name) |
256 | | - raise HTTPException(**response.model_dump()) from e |
| 243 | + local_deleted = False |
257 | 244 |
|
258 | | - logger.info("Dynamically unregistered MCP server: %s", name) |
259 | | - |
260 | | - return MCPServerDeleteResponse( |
261 | | - name=name, |
262 | | - message=f"MCP server '{name}' unregistered successfully", |
263 | | - ) |
| 245 | + return MCPServerDeleteResponse(deleted=local_deleted, name=name) |
0 commit comments