{"slug": "test-snowflake-sql-locally-with-your-ai-agent", "title": "Test Snowflake SQL Locally with Your AI Agent", "summary": "LocalStack published a walkthrough showing how an AI agent can build and verify a Snowflake SQL report entirely against a local emulator instead of a paid cloud warehouse. The company gave Claude Code access to the LocalStack MCP server and its Snowflake client tool, then had it load three CSV files from a SaaS billing dataset — plans.csv with four subscription tiers, customers.csv with 39 customers, and payments.csv with 495 invoice rows — and produce a quarterly \"Revenue by Plan\" report. Claude Code started the emulator, found and fixed two problems in its first query, and checked its results against the raw data, all locally at the endpoint snowflake.localhost.localstack.cloud:4566.", "body_md": "## \n\nDeveloping SQL against a real Snowflake warehouse can be slow and expensive. Every time you test a query, a warehouse starts and you pay for the compute. Building a report often takes many test runs, so the time and cost quickly add up. Worse, SQL errors can be hard to spot. A query may return a believable number that reaches a dashboard before anyone checks it against the raw data.\n\nWe gave [Claude Code](https://www.claude.com/product/claude-code) access to the [LocalStack MCP server](https://github.com/localstack/localstack-mcp-server) and its Snowflake client tool. We then gave it CSV files with a SaaS company’s billing data and asked it to build a quarterly “Revenue by Plan” report using a local Snowflake emulator. It also had to verify every number.\n\nClaude Code started the emulator, loaded the CSV files, and wrote the report. It found two problems in its first query, fixed them, and checked the results against the raw data. All this happened locally, without using a real Snowflake warehouse. Here is what happened and how you can try it yourself.\n\n## \n\n[LocalStack for Snowflake](https://docs.localstack.cloud/snowflake/) is a local emulator that supports the Snowflake protocol. After starting the emulator, you can point a client to `snowflake.localhost.localstack.cloud:4566` and run DDL, DML, and queries as you would with a real Snowflake account.\n\nThe LocalStack MCP server connects your AI agent to the emulator. This blog uses two tools from the LocalStack MCP server:\n\n- `localstack-management` starts, stops, and checks the LocalStack container. The agent uses it to start the Snowflake emulator.\n- `localstack-snowflake-client` runs SQL.`check-connection` checks whether the emulator is available.`execute` runs a query string or a`.sql` file. You can also provide a database, schema, warehouse, and role for each call.\n\nBehind the scenes, the client tool uses the [Snowflake CLI](https://docs.snowflake.com/en/developer-guide/snowflake-cli/index) (`snow`) and manages the LocalStack connection profile. The Snowflake CLI is the only Snowflake-side tool you need to install. When the agent runs a query, it receives the results as text. It can read those results and decide what to do next, just as you would when working in a SQL console.\n\n## \n\n- [Docker](https://docs.docker.com/get-docker/) , running.\n- A valid `LOCALSTACK_AUTH_TOKEN` , available with a[free LocalStack account](https://www.localstack.cloud/start-snowflake-trial) . LocalStack for Snowflake is a licensed emulator, so check that your plan includes it.\n- The [Snowflake CLI](https://docs.snowflake.com/en/developer-guide/snowflake-cli/installation/installation) (`snow` ) on your`PATH` .\n- [Node.js](https://nodejs.org/) , to run the MCP server through`npx` .\n- [Claude Code](https://www.claude.com/product/claude-code) , or any other MCP client.\n\n## \n\nThe MCP server ships with a wizard that writes the client configuration for you:\n\nThe wizard checks if Docker is available and reads `LOCALSTACK_AUTH_TOKEN` from your environment. If the token is missing, it asks you to enter it. The wizard then finds your installed MCP clients and configures the ones you choose.\n\nThe LocalStack tools will be available the next time you start your agent. You do not need to start the emulator yourself. The agent will do that in Step 3.\n\n## \n\nThe dataset contains three CSV files similar to those exported from a billing system:\n\nDownload them into a `data` folder:\n\n`plans.csv` contains four subscription tiers:\n\n`customers.csv` contains 39 customers. Each customer has a `plan_id`, a `status` (`active` or `churned`), a `signup_date`, and a `churn_date`. The `churn_date` is blank for active customers.\n\n`payments.csv` contains 495 rows. Each row represents a paid monthly invoice and includes a `payment_date` and an `amount`. Some customers made payments before leaving partway through the quarter. This detail becomes important later.\n\n## \n\nOpen Claude Code in the folder that contains your `data` directory. Select your model (e.g., `claude-opus-5`) and use the following prompt. The key requirement is verification: the agent must check the report before calling it complete.\n\nStep 4 is important. An agent that only writes a query may return incorrect results without noticing. Asking it to compare the results with the raw data helps it find and fix its own mistakes.\n\n## \n\nThe agent first started the emulator and checked the connection:\n\nNext, it created a database, a schema, and one table for each CSV file. It uploaded the files to an internal stage and loaded them with `COPY INTO`:\n\nThe three tables contained 4, 39, and 495 rows. The agent checked that these row counts and the total payment amount matched the original CSV files.\n\nThe agent also handled two details. The emulator compresses uploaded files, so `COPY` had to use the `.gz` filename. It also used `EMPTY_FIELD_AS_NULL` to load blank `churn_date` values as `NULL`.\n\n## \n\nThe first query joined the three tables and grouped the results by plan. It ran without errors and returned numbers that looked reasonable:\n\nHowever, checking the results against the raw tables revealed errors in both money columns.\n\nActive MRR was about 12 times too high. MRR should count each customer once. However, joining the `PAYMENTS` table created one row per payment. As a result, the query counted each customer’s monthly price once for every invoice they had paid.\n\nCollected revenue had a different problem. The query filtered for customers with `status = 'active'`. This filter is correct for MRR, but not for collected revenue. It excluded seven customers who paid during Q2 and later churned, leaving out $3,279 in revenue.\n\nNeither problem caused an error, and the results still looked believable. That made both bugs easy to miss.\n\n## \n\nThe fix was to calculate MRR and collected revenue separately. The agent used one CTE for each calculation, then joined both results to the plan list. It calculated MRR from `CUSTOMERS` only, which prevented duplicate customer counts. It calculated revenue from `PAYMENTS` without a status filter, so payments from churned customers were included:\n\nThe corrected report:\n\n| Plan | Active MRR | Active customers | Collected (Q2 2026) | \n|---|---|---|---|\n| Starter | $290 | 10 | $899 | \n| Pro | $792 | 8 | $2,574 | \n| Business | $1,794 | 6 | $6,279 | \n| Enterprise | $2,997 | 3 | $10,989 | \n| **Total** | **$5,873** | **27** | **$20,741** | \n\nThe agent then verified the results. It calculated every value again using correlated subqueries instead of joins and arithmetic instead of `SUM`. It compared the two sets of results one value at a time.\n\nIt also checked the totals directly against the raw `PAYMENTS` table without any joins. This check would reveal any missing or duplicate rows. All checks passed:\n\n## \n\nThe full session took about **nine minutes** with `claude-opus-5` and cost **$2.80** in model usage. This included creating the report, verifying the results, and saving the SQL. The agent made 42 tool calls, including 27 calls to the Snowflake client.\n\nBecause everything ran locally, there was no Snowflake compute cost. Running the same queries on a real account would have used billable compute. The missing-revenue bug could also have gone unnoticed until someone questioned the numbers later.\n\n## \n\nThe Snowflake client tool in the LocalStack MCP server lets an agent complete common data tasks. It can start the emulator, create schemas, load CSV files, run queries, and read the results. Because everything runs locally, the agent can test and verify queries many times without Snowflake compute costs.\n\nThe two bugs in this example were common: a join duplicated values, and a filter removed valid rows. Both produced believable but incorrect results. Verifying the report against the raw data exposed them before the report was used. If you build reports or data transformations for Snowflake, local verification can help you find these problems early.\n\n## \n\n- [LocalStack for Snowflake](https://docs.localstack.cloud/snowflake/) : getting started, configuration, and the local emulator.\n- [Snowflake feature coverage](https://docs.localstack.cloud/snowflake/feature-coverage/) : what the emulator supports.\n- [LocalStack MCP server](https://github.com/localstack/localstack-mcp-server) : the server, its tools, and setup.\n- [Model Context Protocol](https://modelcontextprotocol.io/) : how agents talk to tools.\n- [LocalStack Slack Community](https://localstack.cloud/slack) : join for questions and discussion.", "url": "https://wpnews.pro/news/test-snowflake-sql-locally-with-your-ai-agent", "canonical_source": "https://blog.localstack.cloud/test-snowflake-sql-locally-with-your-ai-agent/", "published_at": "2026-09-29 00:00:00+00:00", "updated_at": "2026-10-08 09:17:02.056171+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "agent-protocols", "ai-products"], "entities": ["LocalStack", "Claude Code", "Snowflake", "LocalStack MCP server", "LocalStack for Snowflake", "Snowflake CLI", "Docker", "Anthropic"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/test-snowflake-sql-locally-with-your-ai-agent", "markdown": "https://wpnews.pro/news/test-snowflake-sql-locally-with-your-ai-agent.md", "text": "https://wpnews.pro/news/test-snowflake-sql-locally-with-your-ai-agent.txt", "jsonld": "https://wpnews.pro/news/test-snowflake-sql-locally-with-your-ai-agent.jsonld"}}