google-gemini / google-gemini/gemini-cli

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

Open
#28,361 2 comments 0 reactions 0 assignees View on GitHub
area/agent kind/bug priority/p1 status/bot-triaged
Dominant language
TypeScript
Stars
107k
Forks
14.6k
Avg merge
2d 3h
Merged PRs (30d)
45

Description

### 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..trust: true`, `mcp.allowed`, `mcp.autoAllowInHeadless`) can override it.

This silently breaks run-gemini-cli's own shipped [`examples/workflows/pr-review`](https://github.com/google-github-actions/run-gemini-cli/blob/main/examples/workflows/pr-review/gemini-review.yml) example, whose settings contain:

```json
"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 "" 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 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](https://github.com/google-gemini/gemini-cli/blob/v0.50.0/packages/core/src/policy/config.ts#L545-L562): any truthy `settings.tools.core` (an empty array is truthy) adds a wildcard DENY one notch below the core allowlist's ALLOW priority:

```ts
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](https://github.com/google-gemini/gemini-cli/blob/v0.50.0/packages/core/src/policy/config.ts#L75-L81)), 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..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()`](https://github.com/google-gemini/gemini-cli/blob/v0.50.0/packages/core/src/policy/policy-engine.ts#L872) 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`](https://github.com/google-gemini/gemini-cli/blob/v0.50.0/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`:

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

Run non-interactively:

```console
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 "" 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

- gemini-cli v0.50.0 (behaviour present since v0.41.0 / #25720; source references above are at tag v0.50.0)
- Linux (GitHub Actions `ubuntu-latest` runner), non-interactive mode via google-github-actions/run-gemini-cli
- github-mcp-server v0.27.0, gemini-cli-extensions/code-review extension

### 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:

- google-github-actions/run-gemini-cli#519 – the action keys failure on exit code and reads `.error` from stderr only, so the `INVALID_STREAM`/`FatalTurnLimitedError` embedded in stdout with exit 0 is reported as success.
- google-github-actions/run-gemini-cli#510 – the code-review extension's prompts reference stale hard-coded MCP tool names, which makes the blind-guessing described above even less likely to accidentally land on a valid name.

Contributor guide

Open the contributing guide

Research direction

Start with packages/core/src/policy/config.ts, especially the tools.core rule construction and priority constants, then inspect PolicyEngine.getExcludedTools() in packages/core/src/policy/policy-engine.ts. Reproduce the behavior with the minimal settings.json and non-interactive command from the issue. Done means tools.core: [] restricts built-in tools without silently removing trusted or otherwise allowed MCP tools, with relevant behavior covered by tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.