From ea434033f0ba3c9f12e594cd1f45f751d4d1707d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20Gla=CC=88ser?= Date: Thu, 24 Sep 2026 14:56:31 +0200 Subject: [PATCH] Align MCP JSON-RPC error responses --- public/api/market-management-mcp.php | 49 ++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/public/api/market-management-mcp.php b/public/api/market-management-mcp.php index d00ce01..d7fb248 100644 --- a/public/api/market-management-mcp.php +++ b/public/api/market-management-mcp.php @@ -4,6 +4,19 @@ declare(strict_types=1); require_once __DIR__ . '/../../modules/shared/db.php'; require_once __DIR__ . '/../../modules/market_management/mcp.php'; +final class MarketManagementMcpJsonRpcException extends RuntimeException +{ + public function __construct(private int $rpcCode, string $message, ?Throwable $previous = null) + { + parent::__construct($message, 0, $previous); + } + + public function rpcCode(): int + { + return $this->rpcCode; + } +} + header('Content-Type: application/json; charset=utf-8'); header('Cache-Control: no-store'); @@ -18,6 +31,10 @@ try { throw new InvalidArgumentException('Ungültige JSON-RPC-Anfrage.'); } + if (array_key_exists('params', $request) && !is_array($request['params'])) { + throw new MarketManagementMcpJsonRpcException(-32602, 'Parameter müssen als Objekt oder Array übergeben werden.'); + } + $id = $request['id'] ?? null; $method = (string) ($request['method'] ?? ''); $params = is_array($request['params'] ?? null) ? $request['params'] : []; @@ -36,23 +53,35 @@ try { } elseif ($method === 'tools/call') { $tool = (string) ($params['name'] ?? ''); $arguments = is_array($params['arguments'] ?? null) ? $params['arguments'] : []; - $result = [ - 'content' => [[ - 'type' => 'text', - 'text' => json_encode(market_management_mcp_call_idempotent($pdo, $userSubject, $tool, $arguments), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR), - ]], - 'isError' => false, - ]; + if (array_key_exists('arguments', $params) && !is_array($params['arguments'])) { + throw new MarketManagementMcpJsonRpcException(-32602, 'Tool-Argumente müssen als Objekt übergeben werden.'); + } + try { + $result = [ + 'content' => [[ + 'type' => 'text', + 'text' => json_encode(market_management_mcp_call_idempotent($pdo, $userSubject, $tool, $arguments), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR), + ]], + 'isError' => false, + ]; + } catch (InvalidArgumentException $e) { + throw new MarketManagementMcpJsonRpcException(-32602, $e->getMessage(), $e); + } } else { - throw new InvalidArgumentException('Unbekannte JSON-RPC-Methode: ' . $method); + throw new MarketManagementMcpJsonRpcException(-32601, 'Unbekannte JSON-RPC-Methode: ' . $method); } echo json_encode(['jsonrpc' => '2.0', 'id' => $id, 'result' => $result], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR); } catch (Throwable $e) { - http_response_code($e instanceof RuntimeException && str_contains($e->getMessage(), 'Token') ? 401 : 400); + $isAuthError = $e instanceof RuntimeException && str_contains($e->getMessage(), 'Token'); + $isJsonRpcError = $e instanceof MarketManagementMcpJsonRpcException; + http_response_code($isJsonRpcError ? 200 : ($isAuthError ? 401 : 400)); echo json_encode([ 'jsonrpc' => '2.0', 'id' => $request['id'] ?? null, - 'error' => ['code' => -32600, 'message' => $e->getMessage()], + 'error' => [ + 'code' => $isJsonRpcError ? $e->rpcCode() : -32600, + 'message' => $e->getMessage(), + ], ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); }