Skip to content

Add async task support for tool calls with progress tracking#45

Open
jancurn wants to merge 14 commits intomainfrom
claude/mcp-async-tasks-XUYpP
Open

Add async task support for tool calls with progress tracking#45
jancurn wants to merge 14 commits intomainfrom
claude/mcp-async-tasks-XUYpP

Conversation

@jancurn
Copy link
Member

@jancurn jancurn commented Mar 8, 2026

Summary

This PR adds comprehensive support for MCP's async task capability, enabling long-running tool calls to report progress and status updates to the client. When a server supports task-augmented tool execution, the CLI now automatically uses this capability with a visual progress spinner showing elapsed time and status messages.

Key Changes

Core Task Support

  • McpClient: Added callToolWithTask(), listTasks(), getTask(), and cancelTask() methods that wrap the SDK's experimental task APIs
  • Task conversion: Implemented taskToUpdate() helper to convert SDK Task objects to TaskUpdate format, handling optional properties correctly
  • Server capability detection: Added supportsTasksForToolCall() to check if server supports task-augmented tool calls

CLI Tool Execution

  • Automatic task detection: tools-call command now automatically uses task-augmented execution when the server supports it
  • Progress display: Added visual spinner in human mode showing elapsed time (formatted as M:SS or H:MM:SS) and server status messages
  • Sync override: Added --sync flag to force synchronous execution, bypassing async tasks
  • Task formatting: Enhanced formatToolDetail() to display execution.taskSupport field

New Task Management Commands

  • tasks-list: List all active tasks on the server with status indicators
  • tasks-get: Get detailed status of a specific task
  • tasks-cancel: Cancel a running task
  • Task formatting: Added formatTask() and formatTasks() with colored status icons (⟳ working, ? input_required, ✔ completed, ✖ failed, ⊘ cancelled)

Bridge & Session Client

  • Bridge task tracking: BridgeProcess maintains in-memory map of active tasks and emits task-update IPC messages keyed by request ID
  • SessionClient task support: Implemented task methods with event-based update handling for request correlation
  • IPC protocol: Added 'task-update' message type and TaskUpdate interface for streaming progress

E2E Test Server

  • slow-task tool: New test tool supporting both synchronous and task-augmented execution
  • Task handlers: Implemented GetTaskRequest, GetTaskPayloadRequest, ListTasksRequest, and CancelTaskRequest handlers
  • Background execution: Tasks run asynchronously with configurable duration and progress steps

Type System

  • TaskUpdate interface: New type for task progress updates with taskId, status, statusMessage, and timestamps
  • Type exports: Re-exported Task, GetTaskResult, ListTasksResult, CancelTaskResult from SDK
  • Notification type: Added 'tasks/status' to NotificationType union

Implementation Details

  • Task updates are streamed via IPC with request ID correlation, allowing multiple concurrent tool calls to track their own tasks independently
  • The progress spinner updates every second with elapsed time and the latest status message from the server
  • Completed/failed/cancelled tasks are cleaned up from the bridge's active task map to prevent memory leaks
  • The E2E test server's slow-task tool simulates realistic async work with configurable step count and duration
  • All task operations include proper error handling and logging at debug/error levels

https://claude.ai/code/session_01A1QvyZC9apAe1FPzdsTP2o

claude and others added 14 commits March 8, 2026 20:15
When the server supports MCP tasks (capabilities.tasks.requests.tools.call),
tools-call automatically uses task-augmented execution. In human mode, an ora
spinner shows elapsed time and server status messages. In JSON mode, it blocks
until completion and prints the result.

- Add callToolWithTask, listTasks, getTask, cancelTask to McpClient, bridge,
  SessionClient, and IMcpClient interface
- Extend IPC protocol with 'task-update' message type for streaming task
  progress from bridge to CLI
- Add --sync flag to tools-call to force synchronous execution
- Add tasks-list, tasks-get, tasks-cancel commands (CLI, shell, parser)
- Show task capability in server details and execution.taskSupport in tools-get
- Add slow-task tool with task support to E2E test server
- Declare task capabilities in bridge's MCP client initialization

https://claude.ai/code/session_01A1QvyZC9apAe1FPzdsTP2o
…lience

- Replace --sync with --async flag: async task execution is now opt-in
  (previously automatic when server supported it)
- Add --detach flag to start async task and return task ID immediately
  without waiting for completion (implies --async)
- Add bridge crash resilience: persist active task IDs to disk so that
  on bridge restart, existing tasks are polled via getTask() instead of
  re-invoking the tool (which would create duplicate tasks)
- Add callToolDetached() and pollTask() methods to McpClient, bridge,
  and SessionClient
- Update shell to support --async and --detach flags in tools-call

https://claude.ai/code/session_01A1QvyZC9apAe1FPzdsTP2o
The test server now has 6 tools (including slow-task added for async
task support) but the pagination test still expected 5.

https://claude.ai/code/session_01A1QvyZC9apAe1FPzdsTP2o
Tools that declare execution.taskSupport now display [async] in the
summary line of tools-list output, alongside existing annotations
like [read-only] or [destructive].

https://claude.ai/code/session_01A1QvyZC9apAe1FPzdsTP2o
…to claude/mcp-async-tasks-XUYpP

# Conflicts:
#	src/cli/output.ts
Active tasks for crash recovery were stored in a separate
active-tasks.json file. This moves them into sessions.json as an
activeTasks field on SessionData, reusing the existing file locking
and atomic write infrastructure.

https://claude.ai/code/session_01A1QvyZC9apAe1FPzdsTP2o
E2E tests covering:
- --async execution with progress
- --detach execution returning task ID immediately
- tasks-list, tasks-get, tasks-cancel management commands
- Task cancellation of running tasks
- Detached task completion verification
- Synchronous fallback without --async flag

Bug fixes discovered during testing:
- callToolStream was not sending task creation params (task: {}) to
  the SDK, causing the stream to skip task-based execution entirely.
  Both callToolWithTask and callToolDetached now explicitly pass
  task: {} in request options.
- Test server's Task objects were missing required ttl field.

https://claude.ai/code/session_01A1QvyZC9apAe1FPzdsTP2o
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants