-
Notifications
You must be signed in to change notification settings - Fork 74
Description
Laravel Package Version
0.5.3
Laravel Version
12.49.0
PHP Version
8.4
Database Driver & Version
No response
Description
Current Behavior
Currently, any exceptions thrown is either caught by this package or bobbles up to Laravel\Mcp\Server where they are converted to a proper response. See
Lines 204 to 220 in 592140d
| } catch (Throwable $e) { | |
| report($e); | |
| $config = Container::getInstance()->make('config'); | |
| if ($config->get('app.debug', false)) { | |
| throw $e; | |
| } | |
| $jsonRpcResponse = JsonRpcResponse::error( | |
| $request->id ?? null, | |
| -32603, | |
| 'Something went wrong while processing the request.', | |
| ); | |
| $this->transport->send($jsonRpcResponse->toJson()); | |
| } |
Currently only ValidationException's are caught and converted to well structured Tool Execution Errors while any other exception is converted to a generic protocol error:
mcp/src/Server/Methods/CallTool.php
Lines 51 to 56 in 592140d
| try { | |
| // @phpstan-ignore-next-line | |
| $response = Container::getInstance()->call([$tool, 'handle']); | |
| } catch (ValidationException $validationException) { | |
| $response = Response::error(ValidationMessages::from($validationException)); | |
| } |
Lines 202 to 220 in 592140d
| } catch (JsonRpcException $e) { | |
| $this->transport->send($e->toJsonRpcResponse()->toJson()); | |
| } catch (Throwable $e) { | |
| report($e); | |
| $config = Container::getInstance()->make('config'); | |
| if ($config->get('app.debug', false)) { | |
| throw $e; | |
| } | |
| $jsonRpcResponse = JsonRpcResponse::error( | |
| $request->id ?? null, | |
| -32603, | |
| 'Something went wrong while processing the request.', | |
| ); | |
| $this->transport->send($jsonRpcResponse->toJson()); | |
| } |
The Problem
The generic error message provides no context about what actually went wrong, causing client retry loops and little way for the AI/user to resolve any issues.
Possible solutions
The solution is to render the exception to a proper response - question is just how.
MCP Rendering
Laravels exception rendering capabilities already allows for HTML and JSON rendering depending on the Accept header. We could extend this with a "plain text" rendering used for MCPs.
That would be a big task, since basically all existing exception rendering should not just deal with html and json, but also plaintext.
Rely on JSON
Any exception rendering to JSON is already "safe" in the sense that it should not contain any sensitive data.
Because of that, then we could render the exception and map any 5xx server errors to Protocol Errors and any 4xx errors to Tool Execution Errors - in both cases including the rendered json in the response message.
Steps To Reproduce
Try to throw these different types of exceptions within an MCP tool:
throw ValidationException::withMessages(['field' => 'Example message']);
throw new AuthorizationException('Not allowed');
throw new Exception('Something went wrong');