openclaw - 💡(How to fix) Fix MCP tools bypass per-agent tools.allow / tools.deny filter [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#63399Fetched 2026-04-09 07:54:13
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Author
Participants

OpenClaw 2026.4.5 makes all globally configured MCP tools available to ALL agents, regardless of the agent's tools.allow, tools.alsoAllow, tools.deny, or tools.profile configuration. The per-agent tool restriction system applies to built-in tools (read, edit, write, exec, web_search, sessions_spawn, etc.) but NOT to MCP tools, which are auto-injected from mcp.servers globally.

This makes per-agent MCP scoping impossible via config alone — there's no way to say "the router agent can only call sessions_spawn, but the pleres agent can call ms365__* tools". Either all agents get access to all MCP tools, or none do.

Root Cause

In our deployment, the router agent is supposed to be a fast triage layer that ONLY classifies and delegates via sessions_spawn. But because MS365 tools leak into its tool list, the router is encouraged by the LLM (Haiku in our case) to call MS365 tools directly when the user asks for calendar/email — completely bypassing the specialist agents that should own that capability.

Fix Action

Workaround

None reliable. Things we tried that didn't work:

  • tools.profile=minimal + tools.alsoAllow=["sessions_spawn"] + 23-name explicit deny — MCP tools still present
  • tools.allow=["sessions_spawn"] (replacing alsoAllow with explicit allow) — MCP tools still present
  • tools.deny listing every MCP tool name — would work but brittle (need to update for every package update of every MCP server)

The only effective workarounds are:

  • Only configure MCP servers globally if EVERY agent needs access to those tools, OR
  • Restructure to launch a separate gateway instance per "scope" (massive infrastructure cost)

Code Example

{
     "mcp": {
       "servers": {
         "ms365": {
           "command": "npx",
           "args": ["-y", "@softeria/ms-365-mcp-server", "--org-mode"]
         }
       }
     }
   }

---

{
     "agents": {
       "list": [
         {
           "id": "router",
           "model": "litellm/claude-haiku-4-5",
           "tools": {
             "profile": "minimal",
             "allow": ["sessions_spawn"],
             "deny": ["read", "edit", "write", "exec", "process",
                      "canvas", "nodes", "cron", "message", "tts", "gateway",
                      "agents_list", "sessions_list", "sessions_history",
                      "sessions_send", "sessions_yield", "subagents", "session_status",
                      "web_search", "web_fetch", "image", "pdf", "browser"]
           },
           "skills": []
         }
       ]
     }
   }

---

"tools": {
    "mcp": {
      "allow": ["ms365"],   // server names, not tool names
      "deny": []
    }
  }

---

tools?: {
     // existing fields...
     mcp?: {
       allow?: string[];   // mcp.servers names whose tools are visible to this agent
       deny?: string[];
       allowTools?: string[];  // optional: per-tool-name granularity
       denyTools?: string[];
     }
   }
RAW_BUFFERClick to expand / collapse

Bug: MCP tools bypass per-agent tools.allow / tools.deny filter

Summary

OpenClaw 2026.4.5 makes all globally configured MCP tools available to ALL agents, regardless of the agent's tools.allow, tools.alsoAllow, tools.deny, or tools.profile configuration. The per-agent tool restriction system applies to built-in tools (read, edit, write, exec, web_search, sessions_spawn, etc.) but NOT to MCP tools, which are auto-injected from mcp.servers globally.

This makes per-agent MCP scoping impossible via config alone — there's no way to say "the router agent can only call sessions_spawn, but the pleres agent can call ms365__* tools". Either all agents get access to all MCP tools, or none do.

Environment

  • OpenClaw 2026.4.5 (3e72c03)
  • Ubuntu 24.04.4 LTS, Node v24.14.1 via nvm
  • MCP server: @softeria/ms-365-mcp-server (110+ tools), but the issue is general — happens with any MCP server

Steps to reproduce

  1. Configure an MCP server in mcp.servers:

    {
      "mcp": {
        "servers": {
          "ms365": {
            "command": "npx",
            "args": ["-y", "@softeria/ms-365-mcp-server", "--org-mode"]
          }
        }
      }
    }
  2. Configure a "router" agent with the strictest possible tool restriction — explicit allow of only sessions_spawn, plus an explicit deny list, plus profile=minimal:

    {
      "agents": {
        "list": [
          {
            "id": "router",
            "model": "litellm/claude-haiku-4-5",
            "tools": {
              "profile": "minimal",
              "allow": ["sessions_spawn"],
              "deny": ["read", "edit", "write", "exec", "process",
                       "canvas", "nodes", "cron", "message", "tts", "gateway",
                       "agents_list", "sessions_list", "sessions_history",
                       "sessions_send", "sessions_yield", "subagents", "session_status",
                       "web_search", "web_fetch", "image", "pdf", "browser"]
            },
            "skills": []
          }
        ]
      }
    }
  3. Send a message to the router agent that would naturally invoke an MS365 tool (e.g., "list my recent calendar events").

  4. Observed: the router agent calls ms365__list-calendar-events directly. The lane in the gateway logs is agent:router:msteams:default:direct:..., confirming this is the router itself, NOT a spawned subagent. Despite tools.allow=["sessions_spawn"] being explicit, the MS365 tools are present in the router's tool list.

  5. Confirm via tcpdump on the LiteLLM port (or by capturing the LLM request body via a wrapper script): the structured tools array sent to the model includes all 110+ MS365 tool definitions, alongside sessions_spawn.

Expected behavior

tools.allow should be the COMPLETE allowlist for an agent's tool surface. If tools.allow=["sessions_spawn"], then ONLY sessions_spawn should appear in the agent's tool list — no built-ins, no MCP tools, no skills. The current behavior is closer to "alsoAllow" semantics: tools.allow adds to whatever was going to be allowed anyway.

Either:

  • tools.allow is treated as an explicit allowlist (most correct), OR
  • A new tools.mcp field exists for per-agent MCP server scoping:
    "tools": {
      "mcp": {
        "allow": ["ms365"],   // server names, not tool names
        "deny": []
      }
    }

Actual behavior

tools.allow only filters built-in tools. MCP tools and skill tools are auto-injected separately and bypass the filter.

Severity

High for any deployment with both:

  • A multi-agent architecture (router + specialists)
  • Globally configured MCP servers

In our deployment, the router agent is supposed to be a fast triage layer that ONLY classifies and delegates via sessions_spawn. But because MS365 tools leak into its tool list, the router is encouraged by the LLM (Haiku in our case) to call MS365 tools directly when the user asks for calendar/email — completely bypassing the specialist agents that should own that capability.

This also has security implications: an MCP server scoped to one tenant's credentials should not be reachable from agents that have access to a different tenant's data.

Workaround

None reliable. Things we tried that didn't work:

  • tools.profile=minimal + tools.alsoAllow=["sessions_spawn"] + 23-name explicit deny — MCP tools still present
  • tools.allow=["sessions_spawn"] (replacing alsoAllow with explicit allow) — MCP tools still present
  • tools.deny listing every MCP tool name — would work but brittle (need to update for every package update of every MCP server)

The only effective workarounds are:

  • Only configure MCP servers globally if EVERY agent needs access to those tools, OR
  • Restructure to launch a separate gateway instance per "scope" (massive infrastructure cost)

Suggested fix paths

  1. Make tools.allow an explicit allowlist that filters ALL tool sources (built-in, MCP, skills). Backward incompatibility risk: existing configs that use tools.allow to add to defaults would break. Mitigate via a config schema version bump or a deprecation period with both behaviors supported.

  2. Add tools.mcp for per-agent MCP server scoping:

    tools?: {
      // existing fields...
      mcp?: {
        allow?: string[];   // mcp.servers names whose tools are visible to this agent
        deny?: string[];
        allowTools?: string[];  // optional: per-tool-name granularity
        denyTools?: string[];
      }
    }

    This is additive (no backward incompat) and gives operators clean control.

  3. At minimum, document the current behavior in the OpenClaw docs page for tools config so operators know that allow/deny doesn't gate MCP tools, and the only way to scope MCP tools currently is to launch separate gateway instances.

Where this bit us

Synap deployment, 2026-04-08. Wiring @softeria/ms-365-mcp-server for pleres + family agents. The router was supposed to triage and sessions_spawn to pleres for M365 questions; pleres would then own the MS365 tool calls. Instead, MS365 tools leaked into the router's tool list, so the router called them directly using its Haiku model. Combined with the Vertex thought_signature bug (#34-to-file) and the OpenAI schema validation bug (#35-to-file), every direct call from the router failed in a different way.

Related upstream issues

  • #62763, #62764, #62765, #62766, #63357, #63394 (other OpenClaw issues from the same Synap deployment)
  • The to-be-filed Vertex thought_signature bug
  • The to-be-filed OpenAI MS365 tool schema validation bug

extent analysis

TL;DR

To fix the issue where MCP tools bypass per-agent tools.allow/tools.deny filter, consider implementing one of the suggested fix paths, such as making tools.allow an explicit allowlist or adding tools.mcp for per-agent MCP server scoping.

Guidance

  1. Review the suggested fix paths: Consider the trade-offs between making tools.allow an explicit allowlist, adding tools.mcp for per-agent MCP server scoping, or documenting the current behavior.
  2. Assess the impact of changing tools.allow behavior: If you choose to make tools.allow an explicit allowlist, be aware that existing configs using tools.allow to add to defaults may break, and plan for a config schema version bump or deprecation period.
  3. Evaluate the need for per-agent MCP server scoping: If you have a multi-agent architecture with different MCP server requirements, consider adding tools.mcp to provide clean control over which MCP tools are visible to each agent.
  4. Document the current behavior: Regardless of the chosen fix, ensure that the OpenClaw documentation is updated to reflect the current behavior of tools.allow and tools.deny in relation to MCP tools.

Example

No specific code example is provided, as the issue requires a design decision and implementation change rather than a simple code fix.

Notes

The chosen solution will depend on the specific requirements and constraints of your deployment. Be sure to consider the potential impact on existing configurations and the trade-offs between different fix paths.

Recommendation

Apply the add tools.mcp for per-agent MCP server scoping fix, as it provides a clean and backward-compatible way to control which MCP tools are visible to each agent, without introducing potential backward incompatibility risks.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

tools.allow should be the COMPLETE allowlist for an agent's tool surface. If tools.allow=["sessions_spawn"], then ONLY sessions_spawn should appear in the agent's tool list — no built-ins, no MCP tools, no skills. The current behavior is closer to "alsoAllow" semantics: tools.allow adds to whatever was going to be allowed anyway.

Either:

  • tools.allow is treated as an explicit allowlist (most correct), OR
  • A new tools.mcp field exists for per-agent MCP server scoping:
    "tools": {
      "mcp": {
        "allow": ["ms365"],   // server names, not tool names
        "deny": []
      }
    }

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING