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.
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.
Create the OAuth integration
Run as SECURITYADMIN. This is the object Claude’s connector authenticates against.
-- 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.
Create a scoped role
Give the connector the narrowest access it needs — never your own admin role. Run as ACCOUNTADMIN:
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;
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.
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.
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.
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.
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.
Add the connector in Claude
- Click “+” → “Add custom connector”.
- 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(); - Under advanced settings, paste the Client ID and Client Secret from step 5.
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
| Error | Cause | Fix |
|---|---|---|
| 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.