CherryHQ/cherry-studio · warning · Error

MCP tool is disabled: ${name}

Error message

MCP tool is disabled: ${name}

What it means

Thrown before invoking an MCP tool when the latest source policy marks the tool as disabled. The check `isMcpToolDisabledBySource(sourcePolicy, { name })` evaluates the server's current disabled-tools configuration. This is a policy enforcement guard, not a transport or connection error.

Source

Thrown at src/main/ai/mcp/McpRuntimeService.ts:1232

        getServerLogger(server, { tool: name, callId: toolCallId }).debug(`Calling tool`, {
          args: redactSensitive(args)
        })
        if (typeof args === 'string') {
          if (args.trim() === '') {
            args = {}
          } else {
            try {
              args = JSON.parse(args)
            } catch (e) {
              // Fail fast instead of forwarding malformed JSON as a raw string — the MCP
              // server expects an object/record, so a bare string yields opaque downstream errors.
              throw new Error(`Invalid JSON tool arguments for ${name}: ${(e as Error).message}`)
            }
          }
        }
        const sourcePolicy = this.getLatestSourcePolicy(server)
        if (isMcpToolDisabledBySource(sourcePolicy, { name })) {
          throw new Error(`MCP tool is disabled: ${name}`)
        }
        // Client init (ping probe, transport connect, OAuth) has no unified timeout at this
        // layer — release this call's wait on abort instead of blocking until it settles.
        // The shared `pendingClients` init keeps running (only this caller's wait is released),
        // and both racers are consumed, so the loser's late rejection is never unhandled.
        // The listener is removed once the race settles: `once` only cleans up after an
        // abort fires, and the composed signal is retained by the long-lived stream signal —
        // leaving it installed would accumulate a closure per tool call.
        let handleAbort: (() => void) | undefined
        const client = await Promise.race([
          this.getOrCreateClient(server),
          new Promise<never>((_, reject) => {
            handleAbort = (): void => reject(getAbortReason(effectiveSignal))
            if (effectiveSignal.aborted) return handleAbort()
            effectiveSignal.addEventListener('abort', handleAbort, { once: true })
          })
        ]).finally(() => {
          if (handleAbort) effectiveSignal.removeEventListener('abort', handleAbort)

View on GitHub (pinned to 726446b54c)

Solutions

  1. Re-enable the tool in MCP settings → server details → tools list
  2. Check the server's `disabledTools` array in the database to confirm which tools are disabled
  3. If using source policies, review the policy configuration that disabled the tool
  4. In the calling layer, check `isMcpToolDisabledBySource` before attempting the call to provide a cleaner error message
Defensive patterns

Strategy: validation

Validate before calling

import { isMcpToolDisabledBySource } from '...'

const sourcePolicy = runtime.getLatestSourcePolicy(server)
if (isMcpToolDisabledBySource(sourcePolicy, { name: toolName })) {
  throw new Error(`Tool '${toolName}' is disabled for server '${server.name}'`)
}
await runtime.callToolByServer({ server, name: toolName, args })

Type guard

function isToolEnabled(server: McpServer, toolName: string, policy: SourcePolicy): boolean {
  return !isMcpToolDisabledBySource(policy, { name: toolName })
}

Try / catch

try {
  await runtime.callToolByServer({ server, name, args })
} catch (e) {
  if (e instanceof Error && e.message.startsWith('MCP tool is disabled')) {
    // Skip this tool or inform the user it needs to be enabled
    logger.info(`Tool ${name} is disabled, skipping`)
    return null
  }
  throw e
}

Prevention

When it happens

Trigger: Calling `callToolByServer` or `callToolById` for a tool whose name appears in the server's `disabledTools` array or is disabled by the current source policy snapshot. The policy is fetched via `getLatestSourcePolicy(server)` at call time.

Common situations: User disabled specific tools in the MCP settings UI (per-tool toggle); an admin policy disabled certain tools; the tool was disabled by a security/compliance rule; the source policy was updated after the tool list was cached.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/8b5945d1fa3c7918. Report an issue: GitHub.