Skip to content

[Bug]: CLI backend (claude-cli) loopback MCP bridge NATIVE_TOOL_EXCLUDE contaminates session tool policy — affects subagent spawn, tool inheritance, and policy introspection #89242

@shadow-enthusiast

Description

@shadow-enthusiast

Describe the bug

When a session runs on a claude-cli backend, the loopback MCP bridge excludes native tools (read, write, edit, apply_patch, exec, process) via NATIVE_TOOL_EXCLUDE to avoid duplicating tools the harness provides natively. However, these exclusions are merged into the session's explicitDenylist in resolveGatewayScopedTools() alongside real policy denies, making them indistinguishable.

This has cascading effects beyond the ACP spawn issue (filed separately):

  1. Subagent capability resolution sees the caller as having tool denies that don't actually exist as policy
  2. inheritedToolDenylist propagates dedup exclusions to all child sessions (subagent and ACP)
  3. Tool policy introspection (e.g., resolveToolProfilePolicy) reports false denies for CLI-backend sessions
  4. Any future feature that reads explicitDenylist or inheritedToolDenylist will be affected

The design gap

There are two semantically different reasons to exclude a tool from a session's tool set:

Reason Source Should inherit? Should block ACP?
Policy deny Config, sender, agent, group policy Yes Yes
Dedup exclusion Loopback MCP bridge (NATIVE_TOOL_EXCLUDE) No No

Currently both flow through the same { deny: [...] } policy object and end up in the same explicitDenylist array. The tool-resolution.ts resolver has no way to tell them apart.

Affected code path

mcp-http.runtime.ts:  excludeToolNames: NATIVE_TOOL_EXCLUDE
         ↓
tool-resolution.ts:   params.excludeToolNames → { deny: excludedToolNames }
                      → merged into explicitDenylist
                      → copied to inheritedToolDenylist
         ↓
acp-spawn.ts:         findAcpUnsupportedInheritedToolDeny() → BLOCKED
subagent-capabilities.ts: inherits false denies

Suggested approach

Separate the two exclusion types at the resolveGatewayScopedTools level:

  • excludeToolNames should filter the current session's tool array only (as it does now)
  • excludeToolNames should not contribute to explicitDenylist or inheritedToolDenylist
  • Alternatively, introduce a scope or reason field on deny entries so downstream consumers can distinguish policy from dedup

Impact

  • Any user running OpenClaw with a claude-cli backend as their primary model cannot spawn ACP sessions from chat (the most natural workflow)
  • Workaround: temporarily switch to an API-backed model before spawning ACP, then switch back — functional but defeats the purpose of having a default model

Environment

  • OpenClaw version: 2026.5.28
  • Relevant source: tool-resolution.ts, mcp-http.runtime.ts, inherited-tool-deny.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions