Repository navigation
Conversation
…259) Add a --read-only flag (FIREBOLT_MCP_READ_ONLY). With it set, firebolt_query accepts only a single SELECT or WITH statement and declares readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false. MCP clients that cache read-only tool results can then replay dashboard queries instead of re-running them on the engine. The statement check is defence in depth on top of the Firebolt role's grants: it skips comments, literals and quoted identifiers, rejects a second statement, a non-SELECT/WITH lead, and bare write/DDL keywords (catching data-modifying CTEs). firebolt_connect, firebolt_connect_core, firebolt_docs_overview, firebolt_docs_llm and firebolt_docs_search never write, so they declare readOnlyHint unconditionally. Without the flag firebolt_query is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scanWords did not recognise $$...$$ or $tag$...$tag$ literals, so a `--`, `/*` or quote inside one was read as a real comment or quote. A statement such as `SELECT $$ -- $$; DROP TABLE t` hid the second statement from the check and passed in read-only mode. Skip dollar-quoted literals like other strings and reject unterminated ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 6886a78. Configure here.
Firebolt unquoted identifiers cannot contain `$`, so `LIKE$$ -- $$` is a keyword followed by a literal. The scanner treated `$` as an identifier character, read `LIKE$$` as one word, and then took the `--` inside the literal as a comment, hiding a following write. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for this contribution! We've reviewed this PR, but we're not sure yet whether we should merge it into We need some time to decide on the right approach here, and we'll follow up on this PR once we have. |
@kop we are running it on companywide mcp gateway(obot). and publishing it as "connector" in claude.ai admin panel on organization wide. that is the use case. we are not running this per laptop |

Summary
Adds an opt-in
--read-onlyflag (FIREBOLT_MCP_READ_ONLY). With it set,firebolt_query:readOnlyHint: true,destructiveHint: false,idempotentHint: true,openWorldHint: false. MCP clients that cache results of read-only tools (for example, claude.ai artifacts) can then replay a query instead of running it on the engine again.SELECTorWITHstatement. Anything else is rejected with abad requesterror before a connection is acquired.Without the flag,
firebolt_querybehaves exactly as before: no annotations, no statement check.firebolt_connect,firebolt_connect_core,firebolt_docs_overview,firebolt_docs_llmandfirebolt_docs_searchnever write, so they now always declarereadOnlyHint: true.Statement check
This is defence in depth and is not a security boundary. The flag is meant for service accounts whose role already cannot write. The scanner:
E'...'backslash escapes), dollar-quoted literals ($$...$$and$tag$...$tag$) and quoted identifiers;$as a possible dollar-quote opener, even directly after a keyword (LIKE$$...$$), because Firebolt unquoted identifiers cannot contain$;;(trailing comments are allowed);SELECTorWITH;WITH x AS (...) INSERT ....It errs on the side of rejecting.
SHOW,EXPLAIN, pipe syntax that starts withFROM, and unquoted identifiers that match a write keyword are all rejected. The README documents this.Tests
SELECT $$ -- $$; DROP TABLE tandSELECT 'a' LIKE$$ -- $$; DROP TABLE t) and their variants. Each fails against the scanner as it was before its fix.tools/listround-trip over streamable HTTP confirms the annotations survive registration and serialization.🤖 Generated with Claude Code
Note
Medium Risk
Read-only mode changes query acceptance and MCP caching semantics for
firebolt_query; misconfiguration could block legitimate SQL or give clients a false sense of safety if relied on without DB-level grants.Overview
Adds an opt-in
--read-onlyflag (FIREBOLT_MCP_READ_ONLY) that wires through server config intofirebolt_queryviaWithReadOnly().When enabled,
firebolt_queryadvertises full MCP read-only hints (readOnlyHint,destructiveHint: false,idempotentHint,openWorldHint: false) and runs a pre-connection SQL guard that allows only oneSELECTorWITHstatement and rejects write/DDL keywords, multi-statement batches, and conservative cases likeSHOW/EXPLAIN. Default behavior is unchanged (no annotations, no validation).Connect and docs tools (
firebolt_connect,firebolt_connect_core, docs overview/LLM/search) now always setreadOnlyHint: truethrough sharedReadOnlyAnnotations(). README documents the mode and its limits (defence in depth, not a security boundary).Tests cover allow/reject matrices for the scanner, annotation presence, default write passthrough, and a streamable HTTP
tools/listround-trip for annotation serialization.Reviewed by Cursor Bugbot for commit a94c60b. Bugbot is set up for automated code reviews on this repo. Configure here.