{"record":{"id":"18e23de7c145d9ed","repo":"mongodb/laravel-mongodb","slug":"only-read-commands-are-allowed-s","errorCode":null,"errorMessage":"Only read commands are allowed (%s).","messagePattern":"Only read commands are allowed \\((.+?)\\)\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Tools/DatabaseQuery.php","lineNumber":114,"sourceCode":"    /**\n     * @param array<string, mixed> $command\n     *\n     * @return array<int, mixed>\n     *\n     * @throws InvalidArgumentException\n     */\n    private function handleMql(array $command, Connection $connection): array\n    {\n        if ($command === []) {\n            throw new InvalidArgumentException('Please pass a valid MongoDB command');\n        }\n\n        // Allowed CRUD commands (https://www.mongodb.com/docs/manual/reference/mql/crud-commands/)\n        $allowList = ['aggregate', 'count', 'distinct', 'find'];\n        $operation = array_key_first($command);\n\n        if (! in_array($operation, $allowList, true)) {\n            throw new InvalidArgumentException(sprintf('Only read commands are allowed (%s).', implode(', ', $allowList)));\n        }\n\n        if ($operation === 'aggregate') {\n            // Check nested write ops recursively with conservative allow list\n            $this->ensureNoNestedWriteInAggregation($command['pipeline'] ?? []);\n        }\n\n        return $connection->getDatabase()->command($command)->toArray();\n    }\n\n    /**\n     * @param array<int, array<string, mixed>> $pipeline\n     *\n     * @throws InvalidArgumentException\n     */\n    private function ensureNoNestedWriteInAggregation(array $pipeline, int $level = 1): void\n    {\n        if ($level > self::MAX_NESTING_LEVEL) {","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/mongodb/laravel-mongodb/blob/0634653039468ceb0268a69192bdac64469ed043/src/Tools/DatabaseQuery.php#L96-L132","documentation":"The first key of the `command` document is not one of the four allowed read-only MQL CRUD commands: aggregate, count, distinct, find. The tool is marked read-only (#[IsReadOnly]) and intentionally refuses write or admin commands such as insert, update, delete, drop, or findAndModify.","triggerScenarios":"Passing a command whose first key is not in the allow list, e.g. {\"insert\": \"users\", ...}, {\"update\": ...}, {\"dropDatabase\": 1}, {\"dbStats\": 1}, or a mistyped operation like {\"findOne\": \"users\"} (findOne is not a command).","commonSituations":"Developer tries to mutate data through the AI tool; copy-pastes a shell helper (findOne, insertMany) as a command name; uses an aggregation-stage name ($match) at the top level instead of inside an aggregate pipeline; expects admin/diagnostic commands to be supported.","solutions":["Use one of the allowed commands: aggregate, count, distinct, or find, with the collection as the value of the first key.","For writes, execute them in your own application code (e.g. MongoDB\\Laravel facade or the MongoDB library) instead of the read-only tool.","Replace shell helpers: findOne -> find with limit 1; insertMany/updateMany -> application code.","For diagnostics like dbStats, run them via a direct MongoDB client, not this tool."],"exampleFix":"// before\n{\"connection\": \"mongodb\", \"command\": {\"insert\": \"users\", \"documents\": [{\"name\": \"Ada\"}]}}\n// after\n{\"connection\": \"mongodb\", \"command\": {\"find\": \"users\", \"filter\": {}, \"limit\": 10}}","handlingStrategy":"validation","validationCode":"$allowed = ['aggregate', 'count', 'distinct', 'find'];\nif (!isset($command[array_key_first($command)]) || !in_array(array_key_first($command), $allowed, true)) {\n    throw new \\InvalidArgumentException('Only read commands are allowed: ' . implode(', ', $allowed));\n}","typeGuard":"$isReadCommand = fn (array $c): bool => in_array(array_key_first($c), ['aggregate', 'count', 'distinct', 'find'], true);","tryCatchPattern":"try {\n    $result = $tool->handle($request);\n} catch (\\InvalidArgumentException $e) {\n    // retry with an allowed read command: aggregate/count/distinct/find\n}","preventionTips":["Restrict generated commands to aggregate, count, distinct, find.","Map shell helpers before sending: findOne -> find + limit:1.","Never send write/admin commands to a tool marked read-only."],"tags":["mcp-tool","mongodb","read-only","mql","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"0634653039468ceb0268a69192bdac64469ed043","analyzedAt":"2026-09-15T02:56:37.067Z","contentChangedAt":"2026-09-15T02:56:37.067Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}