Skip to content

Any settings.tools.core value (even []) emits a wildcard DENY that silently excludes all MCP tools – breaks run-gemini-cli's shipped pr-review example #28361

Description

@philwatt

What happened?

Setting any value for tools.core in settings – including the empty array [] – causes the policy engine to emit a wildcard * DENY rule that statically excludes every MCP tool (plus non-allowlisted built-ins such as activate_skill) from the tool registry. The exclusion is active in YOLO mode, and no MCP allow mechanism (mcpServers.<name>.trust: true, mcp.allowed, mcp.autoAllowInHeadless) can override it.

This silently breaks run-gemini-cli's own shipped examples/workflows/pr-review example, whose settings contain:

"tools": {
  "core": []
}

Symptom chain observed with that example as shipped (gemini-cli-extensions/code-review extension + github-mcp-server v0.27.0, GitHub Actions non-interactive mode):

  1. Startup logs Refresh for 'github' discovered 3 tools – the MCP server connects and discovery works.
  2. But the excluded tools are filtered out of ToolRegistry.getFunctionDeclarations(), so the model receives no MCP tool declarations and blind-guesses tool names.
  3. getTool() excludes them too, so every guess fails with Tool "<name>" not found. Did you mean "activate_skill"?.
  4. The model burns through maxSessionTurns trying 22+ name variants (get_pull_request, github.get_pull_request, pull_request_read, prefixed/unprefixed FQNs, ...) and the run dies with FatalTurnLimitedError.
  5. With --output-format json, the CLI embeds INVALID_STREAM / FatalTurnLimitedError in stdout while exiting 0, so the surrounding action reports success and simply posts no review (the action-side half of that is Silent success when multiple auth methods are provided (zero review output, no error) google-github-actions/run-gemini-cli#519).

The net effect: anyone deploying the pr-review example as documented gets a green workflow that never reviews anything, with no error surfaced anywhere.

Root cause

At tag v0.50.0, packages/core/src/policy/config.ts lines 545–562: any truthy settings.tools.core (an empty array is truthy) adds a wildcard DENY one notch below the core allowlist's ALLOW priority:

if (settings.tools?.core) {
  mapToolsToRules(
    settings.tools.core,
    CORE_TOOLS_FLAG_PRIORITY,
    'Settings (Core Tools)',
    nonPlanModes,
  );

  // If core tools are restricted, we should add a default DENY rule for everything else
  // at a slightly lower priority than the explicit allows.
  rules.push({
    toolName: '*',
    decision: PolicyDecision.DENY,
    priority: CORE_TOOLS_FLAG_PRIORITY - 0.01,
    source: 'Settings (Core Tools Allowlist Enforcement)',
    modes: nonPlanModes,
  });
}

With the priority constants from the same file (lines 75–81), the resulting ranking is:

Rule Priority Decision
tools.allowed 4.3 ALLOW
tools.core entries 4.25 ALLOW
core-allowlist wildcard * 4.24 DENY
mcpServers.<name>.trust: true 4.2 ALLOW
mcp.allowed / mcp.autoAllowInHeadless (#27215) 4.1 ALLOW
YOLO allow-all 1.998 ALLOW

Every MCP allow mechanism ranks below the wildcard DENY; only tools.allowed and explicit tools.core entries outrank it. And because PolicyEngine.getExcludedTools() converts static DENYs into registry exclusions consumed by ToolRegistry.getActiveTools(), the tools are not merely denied at execution time – their declarations are never sent to the model, which is what produces the blind-guessing loop instead of a clean policy error.

Behaviour introduced in v0.41.0 by #25720.

This also contradicts the documentation: docs/reference/configuration.md describes tools.core as "Restrict the set of built-in tools with an allowlist" – nothing indicates it also disables all MCP tools regardless of MCP trust/allow settings.

What did you expect to happen?

tools.core: [] should restrict built-in tools (as documented) while leaving MCP tools governed by the MCP policy mechanisms – or at minimum fail loudly rather than silently stripping tool declarations.

Suggested fixes, in descending order of preference:

  1. Scope the core-allowlist wildcard DENY to built-in tools (exclude mcp_* / declared MCP server tools from the * match), so tools.core matches its documented semantics and trust/mcp.allowed/autoAllowInHeadless keep working.
  2. Failing that, fix the shipped run-gemini-cli pr-review example settings so they don't ship a config that disables the very MCP server the workflow depends on (I'm filing a linked issue on google-github-actions/run-gemini-cli).
  3. At minimum, document the interaction in docs/reference/configuration.md and consider warning at startup when tools.core is set and MCP servers are configured but end up fully excluded.

Steps to reproduce

Minimal, generic repro (no GitHub Actions needed):

settings.json:

{
  "mcpServers": {
    "github": {
      "command": "github-mcp-server",
      "args": ["stdio"],
      "trust": true
    }
  },
  "tools": {
    "core": []
  }
}

Run non-interactively:

gemini --approval-mode yolo -p "Call any tool from the github MCP server"

Expected: MCP tools callable (server is trusted, YOLO mode).
Actual: discovery logs the server's tools, but the model gets no declarations for them and any attempted call returns Tool "<name>" not found.

As-shipped repro: deploy examples/workflows/pr-review/gemini-review.yml from run-gemini-cli unmodified and open a PR – the review run exhausts maxSessionTurns and posts nothing while the workflow stays green.

Verified workarounds (end-to-end):

  • add "mcp_github_*" (and/or exact FQNs) to tools.core, or use "tools": { "allowed": ["mcp_github_*"] } (4.3 outranks the 4.24 DENY);
  • also allowlist "activate_skill" – the code-review extension's mandatory skill activation is a built-in tool call that "core": [] denies.

Client information

Login information

API key (GEMINI_API_KEY) in CI.

Anything else we need to know?

Related issues that compound this one in the pr-review workflow:

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/agentIssues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Qualitykind/bugpriority/p1Important and should be addressed in the near term.status/bot-triaged

    Type

    Fields

    No fields configured for Bug.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions