Using MCP Servers with Snowflake: A Practitioner’s Guide

Written by

in

Your data team ships a Cortex-powered analytics agent. Works beautifully. Then the platform team wants to plug in Cursor. The ML team asks about GPT-4o. A product manager hears about Claude Desktop and sends a Slack message. Suddenly you’re the person maintaining four different Snowflake connectors, each with its own auth token, its own privilege model, and its own way of quietly breaking on a Tuesday morning.

The Snowflake-managed MCP server is the solution to that maintenance sprawl. Generally available since November 2025, it gives every AI client — Claude, Cursor, ChatGPT, any LangChain agent — one governed, OAuth-secured endpoint into your Snowflake account. You define which tools are visible, which roles can invoke them, and the MCP server enforces that contract for every client simultaneously. No custom connectors. No separately rotated tokens. No over-privileged service accounts.

This guide covers the architecture, the full setup sequence, the tool types you can expose, and — more importantly — the gotchas that aren’t in the quickstart.

TL;DR

  • → The Snowflake-managed MCP server is a first-class Snowflake object (CREATE MCP SERVER) that exposes Cortex Analyst, Cortex Search, Cortex Agents, SQL execution, and custom UDFs/stored procedures as MCP-callable tools through a single HTTPS endpoint.
  • → It implements MCP spec revision 2025-11-25 and as of August 20, 2026, returns tools/call responses as a Server-Sent Events (SSE) stream — your client must send Accept: application/json, text/event-stream.
  • → Authentication uses Snowflake OAuth by default; you can bind to an external IdP (Okta, Entra ID) by setting OAUTH_AUTHORIZATION_SERVER at the schema, database, or account level.
  • → USAGE on the MCP server is not the same as access to its tools. Each tool requires its own privilege grant — USAGE on the Agent, SELECT on the Semantic View, USAGE on the Search Service, etc.
  • → Claude and ChatGPT always request session:role:all, which maps to the user’s DEFAULT_ROLE — set that role explicitly and ensure the user has a DEFAULT_WAREHOUSE set, or the session will fail to initialize.
  • → Each MCP server supports a maximum of 50 tools; responses are truncated at 250 KB; and MCP server objects are not replicated in failover groups — recreate them on the secondary account manually.
  • → There is no separate billing line for the MCP server itself — you pay the underlying Cortex AI token costs and warehouse compute that the tools trigger.

What the MCP Server Actually Is

Model Context Protocol is an open standard for how AI clients discover and invoke tools on external systems. Think of it as the HTTP of agent integrations: one protocol that every compliant client understands, instead of bespoke connectors for every combination of agent and data source. Every major AI IDE (Cursor, Windsurf), every frontier model host (Claude, GPT-4o), and a growing ecosystem of agent frameworks already speak MCP natively.

The Snowflake-managed MCP server sits inside your Snowflake account as a native database object — not external middleware you run and scale yourself. Snowflake hosts it, routes requests through your existing RBAC policies, and wires it to your Cortex resources. When a client connects, it gets a tool list scoped to whatever the connecting user’s role is allowed to see. When it calls a tool, Snowflake enforces the same governance controls as any other query against that resource.

The contrast with the old approach is stark. If you previously connected Claude Desktop to Snowflake via a custom Python script, and then wanted Cursor to have access, you’d write a second connector — different auth mechanism, different privilege model, a second thing to break. The MCP server collapses all of that into one object you configure once.

The Five Tool Types You Can Expose

The MCP server spec lists five tool types, and choosing the right one for each use case is non-obvious. Here’s what each actually does and when to reach for it.

CORTEX_AGENT_RUN — the recommended default

Snowflake’s own documentation is explicit: for business data applications that need governed orchestration, expose a Cortex Agent as the client-facing tool, not Cortex Analyst or Cortex Search directly. The agent orchestrates sub-tools internally, the external MCP client sends one message and gets one response, and you configure the agent’s resource access once in the agent definition rather than per-tool in every MCP server spec. The response payload includes intermediate reasoning traces, tool calls, and citations — which can exceed 200 KB for agent calls with large search results. Use max_results on the agent’s search resources to keep payloads sane.

CORTEX_ANALYST_MESSAGE — natural language to SQL

Directly exposes a Cortex Analyst semantic view. The client sends a natural language question, Analyst generates a SQL statement, and that SQL is returned to the client (not executed). The client then decides what to do with the SQL. This is the right tool when the MCP client has its own execution layer, or when you want the human to review the generated SQL before it runs. If you want Analyst results without a round trip, use a Cortex Agent with an Analyst tool configured internally.

CORTEX_SEARCH_SERVICE_QUERY — vector search over docs

Exposes a Cortex Search service. The client passes a query string and optional column filters; the search service returns ranked results. This is the RAG retrieval leg — pair it with an agent or with the client’s own synthesis layer. If you’ve already built a Cortex Search service for a RAG pipeline, adding it to an MCP server is one additional block in the spec YAML.

SYSTEM_EXECUTE_SQL — raw SQL execution

The most powerful and most dangerous tool type. The client passes arbitrary SQL, and Snowflake executes it. Set read_only: true in the config unless you genuinely need writes, and always set a query_timeout. If you expose this tool directly without a Cortex Agent in front of it, your governance boundary is the MCP client’s prompt discipline — which is not a governance boundary at all. Treat this as an escape hatch for internal tooling, not a default for agent access.

GENERIC — UDFs and stored procedures

Wraps any Python UDF or stored procedure as an MCP-callable tool. You define an input_schema in JSON Schema format, and the MCP client passes arguments that Snowflake validates before execution. This is where custom domain logic — a pricing calculator, a compliance checker, a data quality scorer — becomes available to any AI client without duplicating the logic into a prompt or a custom API endpoint.

Setup: From Zero to Working Connection

The full sequence is four steps: create the OAuth security integration, create the MCP server object, grant privileges, and connect the client. The OAuth step is where most teams get tripped up, so it gets most of the space below.

Step 1 — Create the OAuth security integration

CREATE OR REPLACE SECURITY INTEGRATION snowflake_mcp_oauth
  TYPE = OAUTH
  OAUTH_CLIENT = CUSTOM
  ENABLED = TRUE
  OAUTH_CLIENT_TYPE = 'CONFIDENTIAL'
  -- Claude.ai uses this callback; Claude Desktop uses a localhost URI
  OAUTH_REDIRECT_URI = 'https://claude.ai/api/mcp/auth_callback'
  OAUTH_USE_SECONDARY_ROLES = NONE     -- recommended for MCP
  ALLOWED_ROLES_LIST = ('mcp_access_role');

-- Retrieve the client ID and secret for client configuration
SELECT SYSTEM$SHOW_OAUTH_CLIENT_SECRETS('SNOWFLAKE_MCP_OAUTH');

The OAUTH_USE_SECONDARY_ROLES = NONE setting is Snowflake’s explicit recommendation for MCP. With IMPLICIT, the session inherits the user’s default secondary roles, which can silently grant broader access than you intended. Keep it NONE and scope the mcp_access_role exactly to what the agent needs.

Step 2 — Create the MCP server object

-- Recommended pattern: expose a Cortex Agent as the single client-facing tool
CREATE OR REPLACE MCP SERVER analytics_db.agents_schema.business_mcp
  FROM SPECIFICATION $$
  tools:
    - title: "Business Data Agent"
      name: "business_data_agent"
      type: "CORTEX_AGENT_RUN"
      identifier: "analytics_db.agents_schema.business_agent"
      description: "Answers questions about revenue, customers, and products
                    using governed Snowflake data. Use for any structured
                    business data query."
  $$;

-- Check it's there
DESCRIBE MCP SERVER analytics_db.agents_schema.business_mcp;

The description field is not documentation — it’s how the MCP client decides which tool to invoke when multiple tools are listed. Make it specific and domain-scoped. “Answers questions about data” is noise. “Answers questions about Q4 revenue by region using the finance semantic view” is signal.

Step 3 — Grant privileges

-- Role structure
CREATE ROLE mcp_access_role;
GRANT DATABASE ROLE SNOWFLAKE.CORTEX_AGENT_USER TO ROLE mcp_access_role;

-- Warehouse and schema access
GRANT USAGE ON WAREHOUSE analytics_wh       TO ROLE mcp_access_role;
GRANT USAGE ON DATABASE analytics_db        TO ROLE mcp_access_role;
GRANT USAGE ON SCHEMA analytics_db.agents_schema TO ROLE mcp_access_role;

-- MCP server itself
GRANT USAGE ON MCP SERVER analytics_db.agents_schema.business_mcp
  TO ROLE mcp_access_role;

-- The Agent the server exposes
GRANT USAGE ON AGENT analytics_db.agents_schema.business_agent
  TO ROLE mcp_access_role;

-- Resources the agent uses internally
GRANT SELECT ON SEMANTIC VIEW analytics_db.finance_schema.revenue_semantic
  TO ROLE mcp_access_role;
GRANT USAGE ON CORTEX SEARCH SERVICE analytics_db.docs_schema.product_docs
  TO ROLE mcp_access_role;

-- Assign to users and set defaults
GRANT ROLE mcp_access_role TO USER analyst_user;
ALTER USER analyst_user
  SET DEFAULT_ROLE = 'mcp_access_role'
      DEFAULT_WAREHOUSE = 'analytics_wh';

Step 4 — Connect the client

Every MCP client takes the same endpoint format:

https://<account_url>/api/v2/databases/analytics_db/schemas/agents_schema/mcp-servers/business_mcp

For Claude Desktop or Claude.ai, navigate to Settings → Connectors → Add custom connector, paste the URL, add the client ID and secret from the security integration, and complete the OAuth flow. For Cursor, add the block to your MCP config JSON and sign in via the MCP settings panel. For any HTTP-based client, include Accept: application/json, text/event-stream in the tools/call request header — the server has streamed SSE responses since August 20, 2026, and clients that send only application/json will get unexpected responses.

The Gotchas Nobody Warns You About

USAGE on the MCP server does not grant access to the tools inside it.The MCP server has its own access layer and each tool has its own separate privilege layer. A role with USAGE on the MCP server can connect and discover the tool list — but invoking a tool without the appropriate underlying grant returns an authorization error. This surprises every team the first time. Audit: SHOW GRANTS ON MCP SERVER <name> will not show you tool-level grants. You have to check each underlying object separately.

Underscores in your account hostname will silently break client connections.Snowflake’s own documentation flags this: use hyphens (-) instead of underscores (_) in account hostnames when configuring MCP clients. Older Snowflake account identifiers often use underscores. The error this produces is a generic connection failure, not an informative message about the hostname format. Check the account URL first if a client refuses to connect after OAuth completes.

Claude and ChatGPT always request session:role:all, regardless of your OAUTH_SCOPES_SUPPORTED setting.That scope resolves to the user’s DEFAULT_ROLE. If you haven’t explicitly set DEFAULT_ROLE to the mcp_access_role — or if the user has no DEFAULT_WAREHOUSE set — the session fails to initialize and the error is “session initialization failed,” which tells you nothing useful. Fix both before debugging anything else.

Agent tool responses can easily exceed 200 KB.When an agent uses Cortex Search, the response includes intermediate steps: reasoning traces, search results, citations. Large result sets push the payload well above 200 KB. The 250 KB truncation limit is enforced by the MCP server, so you may get partial responses without a clear error. Mitigate by setting max_results in the agent’s search tool configuration to something in the range of 3–5 for conversational agents.

Agent loops through MCP can hit the 10-invocation recursion limit.If an external client calls a Cortex Agent through MCP, and that agent invokes another MCP server that calls back into a Cortex Agent, you have a recursive loop. Snowflake enforces a hard limit of 10 invocations and then errors. This is more common than you’d think once teams start chaining agents — especially if an agent orchestration pattern grows organically from a single-agent prototype.

Network policies block MCP client IP ranges, not the end user’s IP.Remote MCP clients like Claude.ai and ChatGPT connect from their provider’s infrastructure, not from the end user’s browser. If your Snowflake account has network policies enabled and the MCP client’s outbound IP range isn’t in the allow list, the OAuth token request returns error: invalid_client — the same error as a bad client secret. Check the network policy before assuming authentication misconfiguration. Anthropic publishes Claude’s outbound IP addresses; other providers do the same.

What the MCP Server Doesn’t Do (Yet)

The Snowflake MCP server currently supports only tool capabilities from the MCP protocol. Resources, prompts, roots, notifications, version negotiation, lifecycle phases, and sampling are not supported. This matters if you’re comparing it against other MCP server implementations — some support resource subscriptions or prompt templates. Snowflake’s managed implementation is production-grade on the tools axis but doesn’t yet surface the broader protocol surface.

MCP server objects are also not replicated in failover groups. OAuth security integrations are replicated, but the MCP server definition itself lives only on the account where it was created. If you’re running a multi-account setup with failover configured, you’ll need to recreate MCP server objects on the secondary account as part of your DR runbook — this is an easy thing to forget until you need it.

For teams evaluating the Snowflake-managed approach against the self-hosted Snowflake Labs MCP server: the managed version handles infrastructure and OAuth for you, but you trade infrastructure control for that convenience. The self-hosted option is worth considering if you need full control over authentication flows, custom middleware, or deployment in environments where Snowflake’s hosted endpoint doesn’t satisfy data residency requirements.

The One Principle

“Configure the agent, not the connector. The MCP server is governance infrastructure — define it once, scope it tightly, and let every AI client inherit the same rules rather than building a new integration surface for each one.”

Related reading: MCP explained at three levels · Governing AI agents in Snowflake · Building RAG with Cortex Search · What actually works when building AI agents · Cortex Code and dbt optimization · AI coding agents and pipeline security · Snowflake MCP server docs (official)