{"slug": "how-to-connect-an-ai-agent-to-your-data-warehouse", "title": "How to Connect an AI Agent to Your Data Warehouse", "summary": "A developer proposes replacing text-to-SQL for AI agents with a semantic layer exposed via the Model Context Protocol (MCP), arguing that direct SQL generation leads to inconsistent results, no access control, and no audit trail. The approach defines business metrics in YAML, allowing agents to query governed definitions instead of raw tables, ensuring consistency and governance. The tutorial claims setup can be completed in under 30 minutes using open-source engines like Cube.", "body_md": "Most teams connecting AI agents to their data warehouse start with text-to-SQL. The agent generates SQL from natural language, runs it against the warehouse, and returns results. It works until it doesn't: hallucinated JOINs, inconsistent aggregations, no access control, no audit trail.\n\nThere's a better approach. Define your business metrics in a semantic layer, expose them via [MCP](https://bonnard.dev/glossary/mcp) (Model Context Protocol), and let any AI agent query governed definitions instead of raw tables. Then add one tool so the agent can chart the result in Claude or ChatGPT. This tutorial shows how to set it up in under 30 minutes.\n\nThe agent sees column names but not business logic. It doesn't know that your company excludes refunds from revenue. It doesn't know that `status = 'completed'`\n\nmeans something different in `orders`\n\nthan in `subscriptions`\n\n. It doesn't know that marketing and finance defined \"active user\" differently three years ago and never reconciled.\n\nSo the agent writes plausible SQL and returns plausible numbers. Ask the same question twice with different phrasing and you get different answers. Ask two different agents and you get two different numbers. Neither matches the number your finance team reports.\n\nBeyond consistency, there's no row-level security. No multi-tenancy. No audit trail showing which agent queried what, when, and for whom. In production, with real customers, that's a non-starter.\n\n[Text-to-SQL](https://bonnard.dev/glossary/text-to-sql) gives you speed. It doesn't give you trust.\n\nInstead of letting agents write arbitrary SQL, define your metrics once in YAML: cubes, measures, dimensions, access rules. Then expose those definitions via MCP so agents query governed metrics, not raw tables.\n\nThe difference: every agent gets the same answer because the metric definition is fixed. `total_revenue`\n\nisn't a column the agent interprets. It's a pre-defined calculation with agreed-upon filters and aggregations. When your finance team updates the revenue definition to exclude trial conversions, that change propagates to every consumer instantly. No agent retrained. No dashboard patched. One diff in your schema repo.\n\nThis architecture also decouples the query interface from the warehouse dialect. Swap BigQuery for Snowflake and your agents don't notice. The semantic layer abstracts the SQL generation, so consumers stay stable while infrastructure evolves underneath.\n\n| Approach | Governance | Consistency | Multi-tenant | Access Control | Setup Time |\n|---|---|---|---|---|---|\n| Direct SQL | None | Varies by query | Manual | Manual | Minutes |\n| Text-to-SQL | None | Varies by prompt | Manual | Manual | Hours |\n| Semantic Layer via MCP | Full | Guaranteed | Built-in | Row-level | Under 30 min |\n\nThe [semantic layer](https://bonnard.dev/semantic-layer) is the control plane between your warehouse and every consumer, whether that's a human analyst, a React component, or an AI agent.\n\nStand up a semantic layer that connects to your warehouse and exposes metrics over MCP. Open-source engines like [Cube](https://cube.dev) connect to [BigQuery](https://bonnard.dev/integrations/bigquery), [Snowflake](https://bonnard.dev/integrations/snowflake), [Redshift](https://bonnard.dev/integrations/redshift), [Databricks](https://bonnard.dev/integrations/databricks), [PostgreSQL](https://bonnard.dev/integrations/postgres) (including Supabase, Neon, and RDS), and [DuckDB](https://bonnard.dev/integrations/duckdb) (including MotherDuck). You configure your warehouse connection in a config file or pass credentials via environment variables.\n\nIf you want to explore without connecting your own warehouse, point the semantic layer at a sample PostgreSQL database with orders, customers, and products data so you can follow along with the rest of this tutorial. A few thousand rows across three tables is enough to test aggregations, filters, and multi-dimensional queries.\n\nCreate a cube that maps to a table in your warehouse and defines the metrics your agents will query.\n\n```\ncubes:\n  - name: orders\n    sql_table: public.orders\n    measures:\n      - name: total_revenue\n        sql: amount\n        type: sum\n      - name: count\n        type: count\n    dimensions:\n      - name: status\n        sql: status\n        type: string\n      - name: created_at\n        sql: created_at\n        type: time\n```\n\n**Measures** are the numbers you aggregate: sums, counts, averages. **Dimensions** are the columns you filter and group by: status, date, category. One definition. Every tool, dashboard, and AI agent that queries `total_revenue`\n\ngets the same number.\n\nYou can also define `pre_aggregations`\n\nin the same file to cache expensive computations. For example, a daily rollup of `total_revenue`\n\nby `status`\n\ncan cut query times from seconds to single-digit milliseconds. The semantic layer rebuilds these rollups on a configurable schedule and invalidates stale caches automatically.\n\nSchemas are version-controlled alongside your application code. Review metric changes in pull requests. Roll back a bad definition with `git revert`\n\n. Your data contracts get the same CI/CD workflow as your product.\n\nTo control what's exposed to specific consumers, define a view:\n\n```\nviews:\n  - name: order_metrics\n    cubes:\n      - join_path: orders\n        includes:\n          - total_revenue\n          - count\n          - status\n          - created_at\n```\n\nViews act as a curated interface. Your agents see `order_metrics`\n\nwith four fields instead of navigating the full schema.\n\nDeploy your schema so the semantic layer serves it over an MCP endpoint, then add the MCP server URL to your client's config:\n\n```\n{\n  \"mcpServers\": {\n    \"semantic-layer\": {\n      \"type\": \"http\",\n      \"url\": \"https://your-semantic-layer.example.com/mcp\"\n    }\n  }\n}\n```\n\nPaste this into your MCP client's config file and restart. For Claude Desktop, that's `~/Library/Application Support/Claude/claude_desktop_config.json`\n\n. For Cursor, it's `.cursor/mcp.json`\n\nin your project root. Claude Code reads from `.mcp.json`\n\nin your project directory.\n\nThe MCP server handles tool discovery, schema introspection, and query execution over HTTP. Your agent sees available metrics the same way it sees any other MCP tool. No custom integration code required.\n\nFor customer-facing use cases, scope each connection to a specific tenant's data with row-level security defined in the schema, so a customer's agent sees only that customer's rows.\n\nOnce connected, your AI agent can discover and query your metrics using natural language. Behind the scenes, the agent calls MCP tools.\n\nAsk: \"What's our total revenue this quarter?\"\n\nThe agent calls `explore_schema`\n\nto discover available metrics, then calls `query`\n\nwith the right measures and time filters. The response comes back as structured data, not raw SQL results.\n\nAsk: \"Break down order count by status for the last 30 days.\"\n\nSame flow. The agent uses `query`\n\nwith `count`\n\nas the measure, `status`\n\nas the dimension, and a date filter on `created_at`\n\n.\n\nA semantic layer typically exposes a handful of MCP tools:\n\n`explore_schema`\n\n`query`\n\n`sql_query`\n\n`describe_field`\n\nEvery query runs through the semantic layer. The agent never touches raw tables. Read more about the architecture in our [agentic analytics](https://bonnard.dev/agentic-analytics) guide.\n\nA governed query returns rows. The agent usually needs to show the user a chart, not a wall of numbers. Leaving the model to draw HTML puts the most important part of the answer in its hands to improvise.\n\n[ @bonnard/mcp-charts](https://www.npmjs.com/package/@bonnard/mcp-charts) fixes that. It adds a\n\n`visualize`\n\ntool to your MCP server in a few lines:\n\n```\nnpm install @bonnard/mcp-charts\njs\nimport { addCharts } from \"@bonnard/mcp-charts\";\n\n// your data, your connection. Bonnard never touches the database\naddCharts(server, { runSql });\n```\n\nThe agent calls `visualize`\n\nwith a query, your `runSql`\n\nreturns the rows, and Bonnard infers the chart from the typed result, then renders an interactive widget in Claude or ChatGPT. It renders line, bar, area, pie, scatter, funnel, waterfall, and table, with bar variants for stacked, grouped, horizontal, and 100% stacked. The chart comes from your query result, not from tokens the model invents. Same data, same chart, every time. Full walkthrough: [MCP Charts](https://bonnard.dev/blog/mcp-charts).\n\nYou started with a warehouse and an AI agent that writes its own SQL. Now you have governed metrics defined in YAML, exposed via MCP, queryable from any AI tool your team or customers use. Setup took under 30 minutes.\n\nThe shift from raw SQL to governed metrics pays off immediately: consistent numbers across every consumer, row-level access control per tenant, and a full audit trail for every query. As your team adds more agents and surfaces, the semantic layer scales with you. No duplicate logic. No drift between dashboards and AI answers.\n\nGive the agent a way to chart what it queries: `npm install @bonnard/mcp-charts`\n\n, call `addCharts(server, { runSql })`\n\n, and interactive charts render in Claude and ChatGPT. The repo is on [GitHub](https://github.com/bonnard-data/mcp-charts). Read the [MCP Charts guide](https://bonnard.dev/blog/mcp-charts) to go deeper.\n\n`visualize`\n\ntool so agents chart query results in Claude and ChatGPTNo. A semantic layer with MCP support works with any MCP-compatible AI agent out of the box. Your agent discovers available metrics through the MCP protocol at runtime. There is no fine-tuning, prompt engineering, or model modification required.\n\nA semantic layer connects to BigQuery, Snowflake, Redshift, Databricks, PostgreSQL (including Supabase, Neon, and RDS), and DuckDB (including MotherDuck). For charting the agent's results, `@bonnard/mcp-charts`\n\nships native adapters for Postgres, BigQuery, Snowflake, Databricks, and DuckDB, or you pass your own `runSql`\n\n. Bonnard never touches your database.\n\nText-to-SQL lets an AI agent generate arbitrary SQL from natural language. It has no governance, no consistency guarantees, and no access control. A semantic layer defines metrics once in YAML and exposes them as governed APIs. Every consumer gets the same answer because the calculation is fixed, not interpreted per query. And when the agent charts the result, `@bonnard/mcp-charts`\n\nrenders from the query result, not from tokens the model invents.\n\nInstall [ @bonnard/mcp-charts](https://www.npmjs.com/package/@bonnard/mcp-charts) and call\n\n`addCharts(server, { runSql })`\n\non your MCP server. That registers a `visualize`\n\ntool. The agent calls it with a query, your callback returns the rows, and an interactive chart renders in Claude or ChatGPT. No frontend code.Under 30 minutes for most teams. Stand up a semantic layer, connect your warehouse, define a few metrics in YAML, and deploy it over MCP. Add charts with `npm install @bonnard/mcp-charts`\n\nand one `addCharts`\n\ncall. The tutorial above walks through each step with working code examples.", "url": "https://wpnews.pro/news/how-to-connect-an-ai-agent-to-your-data-warehouse", "canonical_source": "https://dev.to/maxbonnard/how-to-connect-an-ai-agent-to-your-data-warehouse-ack", "published_at": "2026-07-16 15:25:39+00:00", "updated_at": "2026-07-16 15:38:04.241979+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-agents", "ai-infrastructure", "developer-tools", "large-language-models"], "entities": ["Cube", "BigQuery", "Snowflake", "Redshift", "Databricks", "PostgreSQL", "DuckDB", "MotherDuck"], "alternates": {"html": "https://wpnews.pro/news/how-to-connect-an-ai-agent-to-your-data-warehouse", "markdown": "https://wpnews.pro/news/how-to-connect-an-ai-agent-to-your-data-warehouse.md", "text": "https://wpnews.pro/news/how-to-connect-an-ai-agent-to-your-data-warehouse.txt", "jsonld": "https://wpnews.pro/news/how-to-connect-an-ai-agent-to-your-data-warehouse.jsonld"}}