> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Integrating Google ADK Agent With Snowflake MCP

> Guide to adapting a Google ADK churn-detection LLM agent to use Snowflake via the MCP Toolbox, including environment setup and toolbox adapter configuration

This lesson shows how to adapt a churn-detection LLM agent to work with Snowflake through the MCP Toolbox. The agent logic and instructions stay the same as other warehouse integrations — the key change is pointing the MCP Toolbox at the Snowflake adapter and ensuring the toolbox can authenticate using `SNOWFLAKE_*` environment variables.

Ensure you have a `.env` file (or environment variables) with the required keys for KodeKey and Snowflake: `KODEKEY_BASE_URL`, `KODEKEY_API_KEY`, and `SNOWFLAKE_ACCOUNT`, `SNOWFLAKE_USER`, `SNOWFLAKE_PASSWORD` (or PAT), `SNOWFLAKE_DATABASE`, `SNOWFLAKE_SCHEMA`, `SNOWFLAKE_WAREHOUSE`, `SNOWFLAKE_ROLE`. If you use a custom toolbox path, set `TOOLBOX_BIN`. The MCP Toolbox reads the `SNOWFLAKE_*` variables to authenticate when launched.

## Consolidated example script

The script below is a cleaned and consolidated example that highlights the important pieces and where they belong:

```python theme={null}
# churn_agent_snowflake.py
import asyncio
import os
import warnings
from dotenv import load_dotenv

# Load environment variables from .env (if present).
load_dotenv()

# Suppress ADK experimental feature warnings (MCP support is labeled experimental in some ADK versions).
# Filter before ADK imports so the first warning fired at import time is ignored.
warnings.filterwarnings("ignore", message=r".*\[EXPERIMENTAL\].*")

# ADK imports
from google.adk.agents import LlmAgent
from google.adk.models.lite_llm import LiteLlm
from google.adk.runners import InMemoryRunner
from google.genai import types

# MCP-specific imports
from google.adk.tools.mcp_tool.mcp_toolset import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
from mcp import StdioServerParameters

# -------------------------
# Model configuration
# -------------------------
# Example: Claude via KodeKey. Replace model name and keys with your provider values.
MODEL = LiteLlm(
    model="openai/claude-haiku-4-5-20251001",
    api_base=os.environ["KODEKEY_BASE_URL"],
    api_key=os.environ["KODEKEY_API_KEY"],
)

# Path to the MCP Toolbox binary (TOOLBOX_BIN env overrides the default here).
TOOLBOX = os.environ.get("TOOLBOX_BIN", "./toolbox")

# Fully qualified Snowflake table name (database.schema.table) used by the agent instruction.
TABLE = (
    f"{os.environ['SNOWFLAKE_DATABASE']}"
    f".{os.environ['SNOWFLAKE_SCHEMA']}.customer_features"
)

# -------------------------
# MCP Toolbox setup
# -------------------------
# The only substantive change vs other warehouse demonstrations: choose the "snowflake"
# prebuilt config/adapter in your MCP server/toolbox args. The toolbox process reads
# Create stdio connection params for the MCP server/toolbox.
conn_params = StdioConnectionParams()

# Server parameters: include the args to select the Snowflake adapter/config.
# Replace the ... with adapter-specific flags required by your toolbox version.
server_params = StdioServerParameters(...)  # e.g., server_params = StdioServerParameters(adapter="snowflake", ...)

# Construct the McpToolset that exposes a SQL tool backed by Snowflake.
# The constructor args depend on toolbox version and prebuilt configs; the key is to
# reference the Snowflake adapter in the server params above.
snowflake_tools = McpToolset(...)

# -------------------------
# Agent configuration
# -------------------------
agent = LlmAgent(
    name="churn_agent",
    model=MODEL,
    instruction=(
        "You help a customer-success team spot churn risk. The data lives in "
        f"the Snowflake table {TABLE} - one row per customer with columns: "
        "customer_id, region, plan_tier, tenure_months, usage_last_30d, "
        "usage_delta_30d, support_tickets_90d, upgrade_eligible. Use the SQL "
        "tool to fetch the customer the user refers to. Do NOT query the `churned` "
        "column. Interpret the signals: low usage_last_30d or a sharply "
        "negative usage_delta_30d means disengagement; high support_tickets_90d "
        "means friction; short tenure_months is riskier. State the risk level "
        "(low/medium/high), cite the signals, and suggest one retention action."
    ),
    tools=[snowflake_tools],
)

# -------------------------
# Runner / session / example query
# -------------------------
async def main():
    # In-memory runner for quick demos. Create a session for user "me".
    runner = InMemoryRunner(agent=agent, app_name="churn")
    session = await runner.session_service.create_session(app_name="churn", user_id="me")

    # Example user query referencing a specific customer ID.
    msg = types.Content(
        role="user",
        parts=[types.Part(text="Is customer 23e950bd-4270-4f47-b49b-bfda0135ef3a at risk?")]
    )

    # Send the message; ADK versions may expose slightly different service APIs.
    response = await runner.session_service.create_message(session.session_id, content=msg)

    # Print the response (field access may vary by ADK response object structure).
    print(response)

if __name__ == "__main__":
    asyncio.run(main())
```

## What changed for Snowflake (MCP specifics)

* The core agent, model, and instruction text remain the same as other warehouse integrations (BigQuery, Databricks, etc.).
* The MCP Toolbox is started with arguments that select the Snowflake adapter/prebuilt configuration. That change is effectively a single adapter/arg swap in the toolbox/server parameters.
* The toolbox process reads the `SNOWFLAKE_*` environment variables for authentication; by calling `load_dotenv()` and passing `os.environ` into the toolbox subprocess environment, the toolbox can authenticate with Snowflake automatically.

## Environment variables

| Variable | Use / Purpose |
| - | - |
| `KODEKEY_BASE_URL` | KodeKey API base URL for Claude or other model endpoints |
| `KODEKEY_API_KEY` | API key used by the model provider |
| `SNOWFLAKE_ACCOUNT` | Snowflake account identifier |
| `SNOWFLAKE_USER` | Snowflake user name |
| `SNOWFLAKE_PASSWORD` | Snowflake password or Personal Access Token (PAT) |
| `SNOWFLAKE_DATABASE` | Database name (used to construct `TABLE`) |
| `SNOWFLAKE_SCHEMA` | Schema name (used to construct `TABLE`) |
| `SNOWFLAKE_WAREHOUSE` | Warehouse used for queries |
| `SNOWFLAKE_ROLE` | Role used for the session |
| `TOOLBOX_BIN` | (Optional) Path to the MCP Toolbox binary if not `./toolbox` |

Do not commit credentials to source control. Use environment variables, secrets managers, or CI/CD vaults for production deployments. If you are sharing logs, sanitize `SNOWFLAKE_PASSWORD` and API keys.

## UI screenshots referenced in this lesson

![A Databricks web UI showing the Catalog Explorer with a selected table named "support\_tickets." The right pane displays sample rows and columns (ticket\_id, customer\_id, category, priority, sentiment, resolution\_hours, resolved, created\_date) from the support tickets dataset.](https://mintcdn.com/kodekloud-c4ac6d9a/YiW0Xl5gQ25uff6L/images/AI-Agents-For-Data-Analytics/Building-Agent-With-Snowflake/Demo-Integrating-Google-ADK-Agent-With-Snowflake-MCP/databricks-catalog-support-tickets-table.jpg?fit=max\&auto=format\&n=YiW0Xl5gQ25uff6L\&q=85\&s=db01c1b0f6ab4873de51115c69fe25b1)

In Databricks demos we typically expose the support tickets dataset (joined to `customer_features`) so the agent can distinguish friction (support issues) from disengagement signals.

![A screenshot of the Snowflake web UI showing the Database Explorer on the left and a data preview of a table named "CUSTOMER\_FEATURES" on the right, with columns like CUSTOMER\_ID, REGION, UPGRADE\_ELIGIBLE, and usage/support metrics. The table displays rows of customer records and attributes.](https://mintcdn.com/kodekloud-c4ac6d9a/YiW0Xl5gQ25uff6L/images/AI-Agents-For-Data-Analytics/Building-Agent-With-Snowflake/Demo-Integrating-Google-ADK-Agent-With-Snowflake-MCP/snowflake-customer-features-table-preview.jpg?fit=max\&auto=format\&n=YiW0Xl5gQ25uff6L\&q=85\&s=dfc584108bdd1ee940b3f754090a9023)

The `CUSTOMER_FEATURES` table contains the per-customer signals referenced in the agent instruction. The `TABLE` variable in the script points to this fully qualified table (database.schema.table).

![A screenshot of the Snowflake web UI showing the Database Explorer/Horizon Catalog on the left and a data preview of a BILLING\_ACCOUNTS table on the right, listing customer IDs, plan tiers, monthly revenue, contract start/end dates, and payment status.](https://mintcdn.com/kodekloud-c4ac6d9a/YiW0Xl5gQ25uff6L/images/AI-Agents-For-Data-Analytics/Building-Agent-With-Snowflake/Demo-Integrating-Google-ADK-Agent-With-Snowflake-MCP/snowflake-database-explorer-billing-preview.jpg?fit=max\&auto=format\&n=YiW0Xl5gQ25uff6L\&q=85\&s=1a45dd9104c0dfdf432d55aaf415e7d1)

Billing and plan-tier data (from a separate table) can be surfaced to improve retention recommendations — e.g., prioritize enterprise accounts or those that are upgrade-eligible.

## Running the script

Execute the demo locally:

```bash theme={null}
python churn_agent_snowflake.py
```

A successful run typically prints a structured agent reply describing:

* Risk level (low / medium / high)
* The signals the model cited (e.g., low recent usage, negative usage trend, high support tickets)
* Positive indicators (e.g., plan tier, upgrade eligibility)
* A recommended retention action

Example (cleaned) response excerpt:

* Risk level: medium
* Signals:
  1. Low tenure (e.g., 2 months)
  2. Declining engagement (usage\_delta\_30d: -15%)
  3. Moderate recent usage (usage\_last\_30d: 85) — combined with the negative trend suggests waning adoption
* Positive indicators:
  * Low support friction (2 tickets in 90 days)
  * Enterprise plan tier
  * Upgrade eligible
* Recommended Retention Action:
  Schedule a proactive business-review call within 1–2 weeks to investigate the usage decline and present a tailored success plan; given enterprise status and upgrade eligibility, position the discussion as value-driven rather than purely reactive.

## Cleanup warnings you may see

You might see a non-fatal cleanup warning in some ADK/toolbox versions when the MCP stdio session is torn down. Example:

Warning: Error during MCP session cleanup for stdio\_session: Attempted to exit cancel scope in a different task than it was entered in

This usually appears during subprocess/session cleanup and does not necessarily indicate the agent failed. If the agent produced the expected output, the run was successful.

## Summary and best practices

* The agent logic and instructions are portable across warehouses; only the MCP Toolbox adapter/args change to target a different warehouse (Snowflake in this demo).
* Make sure `SNOWFLAKE_*` environment variables are available to the toolbox subprocess so it can authenticate and expose the SQL tool.
* Use the MCP prebuilt Snowflake configuration or the proper adapter flag in `StdioServerParameters` when constructing `McpToolset`.
* Keep secrets out of source control; use environment management or secret stores for production.

## Links and references

* [Snowflake Documentation](https://docs.snowflake.com/)
* [Google ADK / Agents (reference)](https://developers.google.com/genai)
* If you use KodeKey or another inference proxy, consult the provider docs for `api_base` and key usage.

> **[Watch Video](https://learn.kodekloud.com/user/courses/ai-agents-for-data-analytics/module/432d3dee-4625-4352-92e7-0e247db776ea/lesson/0b085679-ad20-42e5-8b2b-368db9e65d29)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.