@@ -287,50 +287,78 @@ async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
287
287
288
288
289
289
# Global exceptions handlers
290
- @app .exception_handler (RequestValidationError )
291
- async def validation_exception_handler (_request : Request , exc : RequestValidationError ):
292
- """Handle Pydantic validation errors globally.
293
-
294
- Args:
295
- _request: The FastAPI request object that triggered the validation error.
296
- exc: The Pydantic ValidationError exception containing validation failure details.
297
-
298
- Returns:
299
- JSONResponse: A 422 Unprocessable Entity response with formatted validation error details.
300
- """
301
- return JSONResponse (status_code = 422 , content = ErrorFormatter .format_validation_error (exc ))
302
290
303
291
304
292
# Register exception handler for custom ValidationError
305
293
@app .exception_handler (ValidationError )
306
- async def content_validation_exception_handler (_request : Request , exc : ValidationError ):
307
- """Handle content security validation errors with a plain message and no traceback .
294
+ async def content_validation_exception_handler (request : Request , exc : ValidationError ):
295
+ """Handle content security validation errors with a clean message format .
308
296
309
297
Args:
310
- _request : The FastAPI request object that triggered validation error.
298
+ request : The FastAPI request object that triggered validation error.
311
299
exc: The ValidationError exception containing failure details.
312
300
313
301
Returns:
314
- PlainTextResponse: Plain text error message with 400 status code.
302
+ JSONResponse: Clean error message with 400 status code.
315
303
"""
316
- return PlainTextResponse (f"mcpgateway.services.content_security.ValidationError: { exc } " , status_code = 400 )
304
+ # Determine the operation type from the request path
305
+ path = request .url .path
306
+ if "/resources" in path :
307
+ operation = "register resource"
308
+ elif "/prompts" in path :
309
+ operation = "create prompt"
310
+ elif "/tools" in path :
311
+ operation = "create tool"
312
+ else :
313
+ operation = "process request"
314
+
315
+ # Extract the actual error message and clean it up
316
+ error_msg = str (exc )
317
+ if "Content contains HTML tags that may cause display issues" in error_msg :
318
+ error_msg = "Resource content contains disallowed HTML tags"
319
+
320
+ return JSONResponse (
321
+ status_code = 400 ,
322
+ content = {"detail" : f"Failed to { operation } : { error_msg } " }
323
+ )
317
324
318
325
319
326
@app .exception_handler (RequestValidationError )
320
- async def request_validation_exception_handler (_request : Request , exc : RequestValidationError ):
327
+ async def request_validation_exception_handler (request : Request , exc : RequestValidationError ):
321
328
"""Handle FastAPI request validation errors (automatic request parsing).
322
329
323
330
This handles ValidationErrors that occur during FastAPI's automatic request
324
331
parsing before the request reaches your endpoint.
325
332
326
333
Args:
327
- _request : The FastAPI request object that triggered validation error.
334
+ request : The FastAPI request object that triggered validation error.
328
335
exc: The RequestValidationError exception containing failure details.
329
336
330
337
Returns:
331
338
JSONResponse: A 422 Unprocessable Entity response with error details.
332
339
"""
333
- if _request .url .path .startswith ("/tools" ):
340
+ # Check if this is a resource creation request with content validation error
341
+ if request .url .path .startswith ("/resources" ) and request .method == "POST" :
342
+ for error in exc .errors ():
343
+ msg = error .get ("msg" , "" )
344
+ loc = error .get ("loc" , [])
345
+ # Debug logging
346
+ logger .debug (f"Validation error - loc: { loc } , msg: { msg } " )
347
+ if len (loc ) >= 2 and loc [- 2 :] == ["body" , "content" ] and "HTML tags" in msg :
348
+ # Provide user-friendly message for HTML content validation
349
+ return JSONResponse (
350
+ status_code = 400 ,
351
+ content = {"detail" : "Failed to register resource: Resource content contains disallowed HTML tags" }
352
+ )
353
+ elif len (loc ) >= 2 and loc [- 2 :] == ["body" , "content" ] and "Content contains" in msg :
354
+ # Extract the actual error message after "Value error, "
355
+ clean_msg = msg .replace ("Value error, " , "" ) if "Value error, " in msg else msg
356
+ return JSONResponse (
357
+ status_code = 400 ,
358
+ content = {"detail" : f"Failed to register resource: { clean_msg } " }
359
+ )
360
+
361
+ if request .url .path .startswith ("/tools" ):
334
362
error_details = []
335
363
336
364
for error in exc .errors ():
@@ -348,7 +376,7 @@ async def request_validation_exception_handler(_request: Request, exc: RequestVa
348
376
349
377
response_content = {"detail" : error_details }
350
378
return JSONResponse (status_code = 422 , content = response_content )
351
- return await fastapi_default_validation_handler (_request , exc )
379
+ return await fastapi_default_validation_handler (request , exc )
352
380
353
381
354
382
@app .exception_handler (IntegrityError )
@@ -1586,15 +1614,15 @@ async def create_resource(
1586
1614
)
1587
1615
except SecurityError as e :
1588
1616
logger .warning (f"Security violation in resource creation by user { user } : { str (e )} " )
1589
- raise HTTPException (status_code = 400 , detail = "Content failed security validation " )
1617
+ raise HTTPException (status_code = 400 , detail = f"Failed to register resource: { str ( e ) } " )
1590
1618
except ValidationError as e :
1591
- raise HTTPException (status_code = 400 , detail = str (e ))
1619
+ raise HTTPException (status_code = 400 , detail = f"Failed to register resource: { str (e )} " )
1592
1620
except ResourceURIConflictError as e :
1593
1621
raise HTTPException (status_code = 409 , detail = str (e ))
1594
1622
except ResourceError as e :
1595
1623
if "Rate limit" in str (e ):
1596
1624
raise HTTPException (status_code = 429 , detail = str (e ))
1597
- raise HTTPException (status_code = 400 , detail = str (e ))
1625
+ raise HTTPException (status_code = 400 , detail = f"Failed to register resource: { str (e )} " )
1598
1626
except IntegrityError as e :
1599
1627
logger .error (f"Integrity error while creating resource: { e } " )
1600
1628
raise HTTPException (status_code = 409 , detail = ErrorFormatter .format_database_error (e ))
0 commit comments