Inaccessible tool handling

By default, orchestration.tool_not_accessible is accept: a Cortex Agent run continues when the caller’s role can’t access any of the tools in the agent specification. If you omit the field, Snowflake uses accept. This applies to agent runs from the REST API, SQL, and conversations in Snowflake CoWork. The agent uses the tools that role can access and reports the rest as warnings. You don’t need a separate agent object for each privilege class.

Configure this behavior on the agent specification with orchestration.tool_not_accessible. The setting applies when you create or update an agent object, and when you pass the full specification to POST /api/v2/cortex/agent:run. You can’t change it on an agents/{name}:run request; update the agent object instead.

Access modes

Set tool_not_accessible on the orchestration object. Values are case-insensitive.

ValueBehavior
acceptContinue the run. Snowflake emits a response.warning event for each inaccessible tool that the caller named, and the agent uses the remaining accessible tools. This is the default when the field is omitted.
rejectCollect every inaccessible tool in the checked set, then reject the run with a single HTTP 4XX error that lists all of them.
legacyReject the run at the first inaccessible Cortex Search, Cortex Analyst, MCP, or skill tool. Use this when a caller depends on that first-failure HTTP 4XX wire format.

YAML example:

orchestration:
  tool_not_accessible: accept
  budget:
    seconds: 30
    tokens: 16000

JSON example:

{
  "orchestration": {
    "tool_not_accessible": "accept",
    "budget": {
      "seconds": 30,
      "tokens": 16000
    }
  }
}

Which tools Snowflake checks

In every mode, Snowflake checks access at the start of the run for Cortex Search (cortex_search), Cortex Analyst (cortex_analyst_text_to_sql), MCP (mcp), and skill (skill) tools.

The following tools aren’t included in this pre-check. If the caller lacks privileges on them, the run still starts. A call to one of these tools fails at execution time, the agent receives that failure as a tool result, and it continues reasoning and tries to answer with what it has:

  • Custom tools (generic and function types, including user-defined functions and stored procedures)
  • SQL execution (sql_exec)
  • Code execution (code_execution)
  • Any other tool type

agent_toolset references are unchanged: if the caller lacks USAGE on the referenced agent, Snowflake skips that reference and continues. For details, see Agent toolsets.

Named tools versus discovered tools

How Snowflake reports an inaccessible resource depends on whether the caller named it:

  • Named in the specification: If tool_resources points at a specific object (a Cortex Search service, semantic view or model, skill, or MCP server_name), Snowflake treats that resource as explicit. In accept mode you get a warning. In reject or legacy mode the run can fail.
  • Discovered for you: If Snowflake enumerates the resource set (for example, MCP selection: all), inaccessible items are omitted with no warning. The caller never named those objects, so Snowflake doesn’t list them.

Behavior by tool

Each search tool is checked independently. If the caller’s role lacks USAGE on that Cortex Search service, that tool is inaccessible. Other search tools in the same spec are unaffected.

Cortex Analyst

Snowflake checks whether the caller can access the semantic model or semantic view behind the tool. If it can’t, the entire Analyst tool is inaccessible.

This check doesn’t cover the objects inside the model, such as SELECT on the tables it references or USAGE on an embedded Cortex Search service. A missing privilege on one of those objects surfaces later, when Analyst runs.

Skills

Each skill is its own tool entry. An inaccessible skill doesn’t block other skills in the same spec.

MCP servers

When tool_resources includes an explicit server_name, a missing server or missing USAGE on that MCP server makes that MCP tool inaccessible.

When the agent uses MCP selection: all, Snowflake includes only the servers the caller can use. Servers the caller can’t use are omitted with no warning.

Configuration and availability issues after the server is authorized (for example, an unresolved URL or an incomplete OAuth flow) still surface as the existing response.warning events. Those aren’t access-mode failures.

Warnings and errors

In accept mode, Snowflake sends one event: response.warning per inaccessible named tool before the first model call. The stream then continues. Warning text doesn’t distinguish “the object doesn’t exist” from “the object exists but this role isn’t authorized.” Both cases use the same message.

Example:

event: response.warning
data: {"code": "399569", "message": "TOOL_NOT_ACCESSIBLE: Search1 (cortex_search) - The Cortex Search Service does not exist or access is not authorized for the current role: db.schema.css1"}

Clients that already handle response.warning (for example, MCP availability warnings) don’t need a new event type.

In reject mode, the HTTP 4XX body lists every inaccessible tool in the checked set. In legacy mode, the HTTP 4XX body describes the first Cortex Search, Analyst, MCP, or skill failure.

These warnings also appear in agent traces and the event table. For where to view traces, see Monitor Cortex Agent requests.

Choose a mode

  • Use accept (the default) when one agent should serve users with different tool grants, and the agent can still answer with the remaining tools.
  • Use reject when you want a strict gate: the run must not start unless every named, checked tool is accessible. The error lists all of those failures at once, which is useful when you’re debugging grants.
  • Use legacy only if an existing client depends on a first-failure HTTP 4XX error for Search, Analyst, MCP, or skills.

Granting the caller’s default role the privileges in Additional privileges for tools is still required for any tool you expect the agent to use. Inaccessible-tool handling doesn’t bypass Snowflake privileges; it only controls whether a missing privilege aborts the whole run.

Change the mode on a versioned agent

tool_not_accessible lives in the agent specification, so changing it means changing the spec of the version that serves your traffic.

Named versions are immutable. If your agent’s default version is a committed named version, editing the live version isn’t enough: commit a new named version with the mode you want, then point the default version or the alias your callers use at it.

ALTER AGENT my_agent ADD LIVE VERSION FROM LAST;

-- SET SPECIFICATION replaces the whole specification, so include your existing settings.
ALTER AGENT my_agent MODIFY LIVE VERSION SET SPECIFICATION =
$$
<existing agent specification>
orchestration:
  tool_not_accessible: legacy
$$;

ALTER AGENT my_agent COMMIT COMMENT = 'Keep first-failure rejection';

ALTER AGENT my_agent SET DEFAULT_VERSION = LAST;

If your default version is already LIVE, updating the live version’s specification is enough. For the version lifecycle, see Cortex Agent versioning.