# Snowflake MCP Server A read-only [Model Context Protocol](https://modelcontextprotocol.io/) server for Snowflake, using SSO (browser-based) authentication. Gives Claude (or any MCP client) the ability to explore your Snowflake account — list databases, schemas, tables, views, describe columns, and run SELECT queries. ## Features - SSO authentication (opens browser on first connection, then reuses the session) - Connection pooling with 30-minute timeout - Query caching (5 min TTL) - Read-only safety: only SELECT / SHOW / DESCRIBE queries are allowed - Async query support for long-running queries - Paginated results - Multiple output formats (records, columns, split, CSV) ## Quick start with uv [uv](https://docs.astral.sh/uv/) is the easiest way to run this without managing a virtualenv yourself. ### 1. Install uv (if you don't have it) ```bash # macOS / Linux curl -LsSf https://astral.sh/uv/install.sh | sh # Windows (PowerShell) powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" ``` ### 2. Configure your Snowflake details Set environment variables (recommended) or edit the defaults at the top of `snowflake_mcp_server.py`. ```bash # Required export SNOWFLAKE_ACCOUNT="your-account-id" # e.g. "xy12345.eu-west-1" export SNOWFLAKE_USER="your.email@company.com" # Optional — defaults shown export SNOWFLAKE_AUTHENTICATOR="externalbrowser" # SSO via browser export SNOWFLAKE_WAREHOUSE="" # uses account default if empty export SNOWFLAKE_ROLE="" # uses account default if empty export SNOWFLAKE_DATABASE="" # uses account default if empty export SNOWFLAKE_SCHEMA="" # uses account default if empty ``` On Windows (PowerShell): ```powershell $env:SNOWFLAKE_ACCOUNT = "your-account-id" $env:SNOWFLAKE_USER = "your.email@company.com" ``` ### 3. Run the server ```bash uv run --with snowflake-connector-python --with mcp snowflake_mcp_server.py ``` Or, if you prefer to create a project first: ```bash uv init --no-package uv add snowflake-connector-python mcp uv run snowflake_mcp_server.py ``` ### 4. Add to Claude Code **Option A — CLI (easiest):** ```bash claude mcp add --transport stdio snowflake \ --env SNOWFLAKE_ACCOUNT=your-account-id \ --env SNOWFLAKE_USER=your.email@company.com \ --env SNOWFLAKE_ROLE=YOUR_ROLE \ -- uv run --with snowflake-connector-python --with mcp /absolute/path/to/snowflake_mcp_server.py ``` **Option B — manual config:** Add to `.mcp.json` in your project root (shared with team) or `~/.claude.json` (personal): ```json { "mcpServers": { "snowflake": { "type": "stdio", "command": "uv", "args": [ "run", "--with", "snowflake-connector-python", "--with", "mcp", "/absolute/path/to/snowflake_mcp_server.py" ], "env": { "SNOWFLAKE_ACCOUNT": "your-account-id", "SNOWFLAKE_USER": "your.email@company.com", "SNOWFLAKE_ROLE": "YOUR_ROLE" } } } } ``` Verify it's registered with `claude mcp list`. ## Available tools | Tool | Description | |------|-------------| | `test_connection` | Verify connectivity and get session info | | `list_databases` | List all accessible databases | | `list_schemas` | List schemas in a database | | `list_tables` | List tables (optionally with row counts) | | `list_views` | List views in a schema | | `describe_table` | Get column-level schema for a table or view | | `describe_query` | Preview output columns without running the full query | | `read_data` | Run a SELECT query (up to 50k rows) | | `read_data_paginated` | Paginated query results with total count | | `read_data_pandas` | Results in records / columns / split / CSV format | | `execute_async` | Submit a long-running query asynchronously | | `get_query_status` | Check async query progress | | `get_async_results` | Fetch results from a completed async query | | `list_async_queries` | List all tracked async queries | ## Notes - The first connection opens your default browser for SSO login. Subsequent calls reuse the session. - All queries are validated to be read-only — DML and DDL are blocked. - Snowflake object names are case-sensitive when created with quotes. The server will automatically retry with quoted names if the unquoted version fails.