Hmbown/CodeWhale · error · anyhow::Error

MCP operation on plugin server '{}' was cancelled after auth

Error message

MCP operation on plugin server '{}' was cancelled after authority changed: {reason}

What it means

finish_guarded_error wraps every error coming out of a connection operation and checks the shared authority_revocation_reason lock. If a reviewed plugin bundle's authority (catalog hash/source) was revoked or changed while an operation was in flight, the transport is shut down, the state set to Disconnected, and this error replaces the original one. It is a security guard: stale plugin connections must not keep operating under an authority that no longer approves them.

Source

Thrown at crates/tui/src/mcp.rs:2265

    }

    fn catalog_authorized(&self) -> bool {
        self.config
            .reviewed_plugin
            .as_ref()
            .is_none_or(ReviewedPluginMcpSource::catalog_is_current)
    }

    async fn finish_guarded_error<T>(&mut self, error: anyhow::Error) -> Result<T> {
        let reason = self
            .authority_revocation_reason
            .lock()
            .ok()
            .and_then(|reason| reason.clone());
        if let Some(reason) = reason {
            self.transport.shutdown().await;
            self.state = ConnectionState::Disconnected;
            anyhow::bail!(
                "MCP operation on plugin server '{}' was cancelled after authority changed: {reason}",
                self.name
            );
        }
        Err(error)
    }
}

/// Apply the ambient proxy policy for MCP HTTP transports.
///
/// User-authored MCP configuration keeps the long-standing corporate-proxy
/// behavior. Reviewed plugin bundles deliberately do not: proxy URLs can carry
/// credentials and proxy processes can observe request metadata, neither of
/// which is part of the v1 reviewed remote authority. Return before consulting
/// the environment so even reading ambient proxy credentials is impossible on
/// that path, and call `no_proxy` explicitly to keep this invariant stable if
/// reqwest's defaults change.
fn configure_mcp_proxy<F>(

View on GitHub (pinned to 8880682c63)

Solutions

  1. Update or re-approve the reviewed plugin bundle so its catalog is current, then reconnect — get_or_connect revalidates via validate_before_use.
  2. Do not retry blindly: the error means the running code is no longer authorized; surface it to the user or operator.
  3. If the revocation was accidental, restore the exact reviewed plugin files/catalog so the hash matches again.
  4. Check for concurrent processes mutating the plugin registry workspace.

Example fix

// before
match conn.call_tool(name, args, t).await { Err(e) => retry(e) } // loops forever on authority revocation

// after
match conn.call_tool(name, args, t).await {
    Err(e) if e.to_string().contains("authority changed") => {
        return Err(e); // terminal: surface to user, re-approve plugin first
    }
    other => other,
}
Defensive patterns

Strategy: try-catch

Try / catch

// Rust: terminal security error — never auto-retry
match result {
    Err(e) if e.to_string().contains("authority changed") => {
        tracing::error!("plugin authority revoked mid-operation: {e:#}");
        return Err(e); // user must re-approve the plugin bundle
    }
    other => other,
}

Prevention

When it happens

Trigger: A tool call is in flight on a reviewed-plugin MCP server when the plugin catalog is updated or the plugin's review state is revoked — validate_before_use in get_or_connect will then refuse future use, and finish_guarded_error converts already-started operations into this cancellation error.

Common situations: Plugin bundle upgraded while the session held open connections; a security review revoked the plugin between turns; CI environments that mutate the plugin registry concurrently with tool execution.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/5aed354c530425e8. Report an issue: GitHub.