Skip to content

runMcpTool() executes tool calls for disabled MCP servers/tools (enabled filter missing at execution time) #1018

Description

@davidwa

Summary

getToolsPrompt() correctly filters MCP tool schemas shown to the model by both
mcpServer.enabled and per-tool enabled status. However, runMcpTool() — the
function that actually executes a tool call — does not re-apply this filter. It
resolves the target server purely by matching the requested tool name:

val serverState = mcpManagerViewModel.uiState.value.mcpServers.find { serverState ->
    serverState.mcpServer.toolsList.any { it.name == toolName }
}
// missing: .filter { it.mcpServer.enabled } / .filter { it.enabled }

Impact

If the model calls a tool name belonging to a server/tool the user has explicitly
disabled in the UI — e.g. via stale conversation context, or hallucination — the
call is still executed. This breaks the implicit UI contract that "Disabled" means
the server receives no further calls, and can lead to unintended data transmission
or actions on a server the user actively revoked permission for (e.g. a user with
both a personal and a work MCP server who disables the work server for a private
session).

Not a remote attack vector — requires the user to have configured the affected
server themselves — but a privacy-relevant access-control gap.

Steps to reproduce

  1. Configure two MCP servers, both with overlapping/similarly-named tools.
  2. Disable one server (or one tool) via the UI toggle.
  3. In a session where the model has prior context referencing the disabled
    tool's name (or via a crafted/hallucinated call), have the model call that
    tool name.
  4. Observe: the call executes against the disabled server instead of being
    rejected.

Suggested fix

Apply the same enabled filter used in getToolsPrompt() (.filter { it.mcpServer.enabled },
.filter { it.enabled }) inside runMcpTool() before resolving/executing the call,
and return a clear error if the resolved tool is disabled.

Related issues checked (none cover this)

Environment

Reproduced on current main.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions