Skip to main content

Setup Snowflake OAuth for MCP for Claude Snowflake Connector

A step-by-step setup for connecting Claude’s web “Add custom connector” to a Snowflake account via OAuth — rewritten after finding and fixing three gaps in the original tutorial through a live end-to-end test.

Tested 2026-10-16 Result connected end-to-end, query executed successfully
✓

What changed from the original tutorial. The original said Claude’s Pro plan and this integration type didn’t work as of November 2025. Both claims turned out to be outdated. The real blocker was a specific, fixable Snowflake authentication rule — not a Claude bug — and the original left out two required Snowflake objects entirely. This version includes all of it, in the order that actually works.

0. Before you start

You need two Snowflake roles to do this setup (one person can hold both): SECURITYADMIN to create the OAuth integration, and ACCOUNTADMIN to create the role, the login, and the MCP server object. You’ll also want a real database and schema to put the MCP server in — it cannot live in a personal/workspace database.

Claude plan: a Pro plan connected successfully in testing. Treat any “only works on Business/Max” claim you read elsewhere as unconfirmed until you’ve tried it yourself.

1

Create the OAuth integration

Run as SECURITYADMIN. This is the object Claude’s connector authenticates against.

SQL · run once
-- Check nothing with this name exists yet
SHOW INTEGRATIONS LIKE '%OAUTH%';

USE ROLE SECURITYADMIN;

CREATE OR REPLACE SECURITY INTEGRATION CLAUDE_MCP_SERVER
  TYPE = OAUTH
  OAUTH_CLIENT = CUSTOM
  OAUTH_CLIENT_TYPE = 'CONFIDENTIAL'
  OAUTH_REDIRECT_URI = 'https://claude.ai/api/mcp/auth_callback'
  ENABLED = TRUE
  OAUTH_ISSUE_REFRESH_TOKENS = TRUE
  OAUTH_REFRESH_TOKEN_VALIDITY = 7776000 -- 90 days, adjust to taste
  COMMENT = 'OAuth integration for the Claude MCP connector.';

SHOW INTEGRATIONS LIKE 'CLAUDE_MCP_SERVER';
DESC SECURITY INTEGRATION CLAUDE_MCP_SERVER;

The original tutorial’s optional step 3 — pre-authorizing a role via PRE_AUTHORIZED_ROLES_LIST — is worth doing (it skips a consent click), but don’t rely on it to fix access problems. It doesn’t do what step 4 below actually fixes.

2

Create a scoped role

Give the connector the narrowest access it needs — never your own admin role. Run as ACCOUNTADMIN:

SQL · adjust the schema to whatever you’re exposing
CREATE ROLE IF NOT EXISTS CLAUDE_MCP
  COMMENT = 'Read-only role for the Claude MCP connector.';

GRANT ROLE CLAUDE_MCP TO ROLE SYSADMIN;

GRANT USAGE ON WAREHOUSE <your_warehouse> TO ROLE CLAUDE_MCP;
GRANT USAGE ON DATABASE <your_db> TO ROLE CLAUDE_MCP;
GRANT USAGE ON SCHEMA <your_db>.<your_schema> TO ROLE CLAUDE_MCP;
GRANT SELECT ON ALL TABLES IN SCHEMA <your_db>.<your_schema> TO ROLE CLAUDE_MCP;
GRANT SELECT ON FUTURE TABLES IN SCHEMA <your_db>.<your_schema> TO ROLE CLAUDE_MCP;
GRANT SELECT ON ALL VIEWS IN SCHEMA <your_db>.<your_schema> TO ROLE CLAUDE_MCP;
GRANT SELECT ON FUTURE VIEWS IN SCHEMA <your_db>.<your_schema> TO ROLE CLAUDE_MCP;
3

Create the MCP server object

!

Missing from the original tutorial entirely. The security integration alone does nothing — Claude’s connector URL points at a separate MCP SERVER object that has to exist in Snowflake. Without it, there’s nothing to connect to.

Run as SYSADMIN (or whoever owns the target schema). It must go in a real database — a personal workspace database fails with Agent Servers cannot currently be created in a personal database.

SQL
CREATE OR REPLACE MCP SERVER <your_db>.<your_schema>.CLAUDE_MCP_SERVER
  FROM SPECIFICATION $$
    tools:
      - title: "SQL Execution Tool"
        name: "sql_exec_tool"
        type: "SYSTEM_EXECUTE_SQL"
        description: "Executes SQL against this schema."
  $$;

GRANT USAGE ON MCP SERVER <your_db>.<your_schema>.CLAUDE_MCP_SERVER TO ROLE CLAUDE_MCP;

The tool type here is SYSTEM_EXECUTE_SQL — it can run any SQL, but what it can actually touch is still bounded by the role’s own grants from step 2. That’s the real access boundary, not the tool definition.

4

Create a dedicated login

!

This is the step that actually matters. Claude’s web connector always requests OAuth scope session:role:all — there’s no field in the UI to ask for anything narrower. Snowflake rejects that request outright if the authenticating user holds any of its default-blocked roles (ACCOUNTADMIN, SECURITYADMIN, ORGADMIN, GLOBALORGADMIN) anywhere in their grants — even if that role is never the one selected. PRE_AUTHORIZED_ROLES_LIST from step 1 does not fix this; it only skips the consent screen for roles already on the list.

The fix: create a user that holds only the scoped role from step 2, and sign in as that user — never your own admin login — when you reach the OAuth consent screen in step 7.

This has to be a TYPE = PERSON user, not SERVICE — the OAuth login is an interactive username/password flow, and service accounts can’t hold a password.

SQL · run as ACCOUNTADMIN
CREATE USER IF NOT EXISTS CLAUDE_MCP_USER
  TYPE = PERSON
  LOGIN_NAME = 'CLAUDE_MCP_USER'
  DISPLAY_NAME = 'Claude MCP connector'
  DEFAULT_WAREHOUSE = <your_warehouse>
  DEFAULT_ROLE = CLAUDE_MCP
  MUST_CHANGE_PASSWORD = FALSE
  PASSWORD = '<pick your own password — do not paste it anywhere outside Snowflake>'
  COMMENT = 'Dedicated login for the Claude MCP OAuth flow. Holds CLAUDE_MCP only.';

GRANT ROLE CLAUDE_MCP TO USER CLAUDE_MCP_USER;
GRANT USAGE ON WAREHOUSE <your_warehouse> TO ROLE CLAUDE_MCP;

-- Confirm nothing but CLAUDE_MCP shows up here before using this login:
SHOW GRANTS TO USER CLAUDE_MCP_USER;

Note: if your account enforces MFA on password logins for PERSON users, this login will also be prompted for MFA during the OAuth consent step. Decide ahead of time whether that’s acceptable for how this connector gets used, or give this user its own exempted authentication policy.

5

Get the client ID and secret

SELECT SYSTEM$SHOW_OAUTH_CLIENT_SECRETS('CLAUDE_MCP_SERVER');

Copy the OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET straight from the result cell. Don’t paste them into Slack, Jira, a chat with an AI assistant, or anywhere else outside Snowflake and Claude’s own connector form — they can only be re-shown by re-running this query, not recovered if lost, but should be rotated if they ever land somewhere they shouldn’t.

6

Add the connector in Claude

  1. Click “+” → “Add custom connector”.
  2. Server URL:
    https://<org>-<account>.snowflakecomputing.com/api/v2/databases/<DB>/schemas/<SCHEMA>/mcp-servers/CLAUDE_MCP_SERVER
    Get <org> and <account> with:
    SELECT CURRENT_ORGANIZATION_NAME(), CURRENT_ACCOUNT_NAME();
  3. Under advanced settings, paste the Client ID and Client Secret from step 5.
7

Connect — as the right user

!

If your browser is already signed into Snowflake as your own (admin-holding) account, clicking Connect may silently reuse that session via SSO instead of prompting fresh — and you’ll hit the exact “role ALL blocked” error from step 4 again. Open a private/incognito window, or explicitly log out of Snowflake first, before clicking Connect.

Click Connect. On the Snowflake sign-in screen, log in as CLAUDE_MCP_USER — not your own account — with the password from step 4. The connector should authorize successfully.


Troubleshooting — errors we actually hit, in order

ErrorCauseFix
The role ALL requested has been explicitly blocked for use with this application by an administrator. Authenticating user holds an admin role (even unused) somewhere in their grants. Sign in as the dedicated step 4 user instead. Use a private window so an existing admin session isn’t silently reused.
Agent Servers cannot currently be created in a personal database. Tried to create the MCP SERVER object in a personal/workspace database. Create it in a real database and schema (step 3).
warehouse is required but not specified in user default warehouse or tool configuration. The connector’s role/user has no warehouse to run queries on. Grant USAGE ON WAREHOUSE to the role and set DEFAULT_WAREHOUSE on the dedicated user (step 4).

Tearing it down

For a throwaway test setup, in this order:

USE ROLE ACCOUNTADMIN;

DROP SECURITY INTEGRATION IF EXISTS CLAUDE_MCP_SERVER;
DROP MCP SERVER IF EXISTS <your_db>.<your_schema>.CLAUDE_MCP_SERVER;
DROP USER IF EXISTS CLAUDE_MCP_USER;
DROP ROLE IF EXISTS CLAUDE_MCP;

In Snowsight, Ctrl+Enter only runs the statement the cursor is in — run each line separately, or use “Run All” from the dropdown by the play button, rather than assuming a multi-statement paste executed in full.

Verified end-to-end on 2026-10-16 against a non-production Snowflake account, including a live query through the connector.