Summary
When Claude Code sends notifications/cancelled (user hit ctrl-c), clemini ignores it and the Gemini request keeps running in the background. This wastes API tokens and can cause confusion if the abandoned task modifies files.
Current Behavior
// mcp.rs line 262-264
if request.method.starts_with("notifications/") {
continue; // Just ignores cancellation!
}
And tools/call spawns a task that runs independently:
tokio::spawn(async move {
// This keeps running even after cancellation
});
Expected Behavior
When notifications/cancelled arrives:
- Abort any running
tools/call task
- Clean up gracefully
- The spawned task should stop (not continue burning tokens)
Implementation
In mcp.rs:
- Store the
JoinHandle from the spawned task:
let mut current_task: Option<tokio::task::JoinHandle<()>> = None;
// When spawning:
current_task = Some(tokio::spawn(async move { ... }));
- Handle the cancellation notification:
if request.method == "notifications/cancelled" {
if let Some(handle) = current_task.take() {
handle.abort();
}
continue;
}
- The task should handle
JoinError::is_cancelled() gracefully if needed.
Testing
- Start clemini MCP server
- Send a long-running request (e.g., complex code generation)
- Send
notifications/cancelled
- Verify in
/tmp/clemini.log that tool calls stop after cancellation
Related
Summary
When Claude Code sends
notifications/cancelled(user hit ctrl-c), clemini ignores it and the Gemini request keeps running in the background. This wastes API tokens and can cause confusion if the abandoned task modifies files.Current Behavior
And
tools/callspawns a task that runs independently:Expected Behavior
When
notifications/cancelledarrives:tools/calltaskImplementation
In
mcp.rs:JoinHandlefrom the spawned task:JoinError::is_cancelled()gracefully if needed.Testing
notifications/cancelled/tmp/clemini.logthat tool calls stop after cancellationRelated