ask_user
Send a question to a Slack channel and wait for the user's reply. Use when you need user input or a decision. Supports background execution to avoid blocking. Returns the reply text.
Instructions
Send a question to the user via Slack and wait for their reply.
Use this when you need user input or a decision. The user will be notified and can reply in the Slack thread. This will BLOCK until the user replies or the timeout is reached.
IMPORTANT - NON-BLOCKING USAGE: To avoid blocking, run this tool in a background agent/task. Example with Claude Code's Task tool:
Task(
prompt="Call ask_user with question='Your question here'",
run_in_background=True
)This lets you continue working while waiting for the Slack reply. You'll be notified when the background task completes with the user's response.
Args: question: The question to ask the user. channel: Channel name or ID. Uses SLACK_DEFAULT_CHANNEL if not specified. context: Optional context to include (e.g., what you're working on). timeout_minutes: How long to wait for a reply (default 5 minutes, max 30).
Returns: Dict with success status and user's reply text if received.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| question | Yes | ||
| channel | No | ||
| context | No | ||
| timeout_minutes | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- slack_mcp/server.py:43-166 (handler)Primary handler for the 'ask_user' tool. Registered with FastMCP as an async task-enabled tool. Sends a question to Slack, polls for a reply with progress updates, and returns the user's response or timeout.
@mcp.tool(task=True) async def ask_user( question: str, channel: str | None = None, context: str | None = None, timeout_minutes: int = 5, progress: Progress = Progress(), ) -> dict: """Send a question to the user via Slack and wait for their reply. Use this when you need user input or a decision. The user will be notified and can reply in the Slack thread. This will BLOCK until the user replies or the timeout is reached. IMPORTANT - NON-BLOCKING USAGE: To avoid blocking, run this tool in a background agent/task. Example with Claude Code's Task tool: Task( prompt="Call ask_user with question='Your question here'", run_in_background=True ) This lets you continue working while waiting for the Slack reply. You'll be notified when the background task completes with the user's response. Args: question: The question to ask the user. channel: Channel name or ID. Uses SLACK_DEFAULT_CHANNEL if not specified. context: Optional context to include (e.g., what you're working on). timeout_minutes: How long to wait for a reply (default 5 minutes, max 30). Returns: Dict with success status and user's reply text if received. """ client = _get_client() # Cap timeout at 30 minutes timeout_minutes = min(timeout_minutes, 30) timeout_seconds = timeout_minutes * 60 # Format the question message if context: formatted_message = ( f":question: *Claude Code needs your input*\n\n" f"*Context:* {context}\n\n" f"*Question:* {question}\n\n" f"_Reply in this thread within {timeout_minutes} minutes._" ) else: formatted_message = ( f":question: *Claude Code needs your input*\n\n" f"{question}\n\n" f"_Reply in this thread within {timeout_minutes} minutes._" ) # Report progress: sending question await progress.set_message("Sending question to Slack...") # Send the question send_result = client.send_message(text=formatted_message, channel=channel) if not send_result.ok: return { "success": False, "message": f"Failed to send question: {send_result.error}", "error": send_result.error, "reply": None, } # Report progress: waiting for reply await progress.set_message(f"Waiting for reply (up to {timeout_minutes} min)...") await progress.set_total(timeout_seconds) # Poll for reply with progress updates poll_interval = 5 # seconds elapsed = 0 while elapsed < timeout_seconds: # Check for replies replies = client.get_thread_replies( channel=send_result.channel, thread_ts=send_result.ts, since_ts=None, ) if replies: reply = replies[0] # Get the first reply # Send acknowledgment client.send_message( text=":white_check_mark: Got it, thanks!", channel=send_result.channel, thread_ts=send_result.ts, ) return { "success": True, "message": "Received user reply", "reply": reply.text, "replied_by": reply.user_name or reply.user, "user_id": reply.user, "ts": reply.ts, "channel": send_result.channel, "thread_ts": send_result.ts, } # Update progress await progress.set_current(elapsed) await asyncio.sleep(poll_interval) elapsed += poll_interval # Timeout reached client.send_message( text=f":hourglass: No reply received after {timeout_minutes} minutes. Continuing without input.", channel=send_result.channel, thread_ts=send_result.ts, ) return { "success": False, "message": f"No reply received within {timeout_minutes} minutes", "reply": None, "channel": send_result.channel, "thread_ts": send_result.ts, } - slack_mcp/server.py:43-50 (registration)Tool registered via the @mcp.tool(task=True) decorator on line 43 of slack_mcp/server.py. The decorator registers 'ask_user' with FastMCP as a task-capable tool.
@mcp.tool(task=True) async def ask_user( question: str, channel: str | None = None, context: str | None = None, timeout_minutes: int = 5, progress: Progress = Progress(), ) -> dict: - slack_mcp/server.py:44-76 (schema)Input parameters for ask_user: question (str, required), channel (str|None), context (str|None), timeout_minutes (int, default 5). Return type is dict via type hints.
async def ask_user( question: str, channel: str | None = None, context: str | None = None, timeout_minutes: int = 5, progress: Progress = Progress(), ) -> dict: """Send a question to the user via Slack and wait for their reply. Use this when you need user input or a decision. The user will be notified and can reply in the Slack thread. This will BLOCK until the user replies or the timeout is reached. IMPORTANT - NON-BLOCKING USAGE: To avoid blocking, run this tool in a background agent/task. Example with Claude Code's Task tool: Task( prompt="Call ask_user with question='Your question here'", run_in_background=True ) This lets you continue working while waiting for the Slack reply. You'll be notified when the background task completes with the user's response. Args: question: The question to ask the user. channel: Channel name or ID. Uses SLACK_DEFAULT_CHANNEL if not specified. context: Optional context to include (e.g., what you're working on). timeout_minutes: How long to wait for a reply (default 5 minutes, max 30). Returns: Dict with success status and user's reply text if received. """ - slack_mcp/slack_client.py:174-203 (helper)SlackClient.wait_for_reply - blocking helper used by the synchronous ask_user in slack_mcp/tools/messaging.py (a simpler duplicate of the main handler).
def wait_for_reply( self, channel: str, thread_ts: str, timeout_seconds: int = 300, poll_interval: int = 5, ) -> Message | None: """Wait for a reply in a thread. Args: channel: Channel ID containing the thread. thread_ts: Timestamp of the parent message. timeout_seconds: Maximum time to wait (default 5 minutes). poll_interval: Seconds between poll attempts (default 5). Returns: First new message in the thread, or None if timeout. """ start_time = time.time() last_ts = thread_ts while time.time() - start_time < timeout_seconds: replies = self.get_thread_replies(channel, thread_ts, since_ts=last_ts) if replies: return replies[0] time.sleep(poll_interval) return None - slack_mcp/tools/messaging.py:16-107 (handler)Synchronous duplicate implementation of ask_user (not registered as a tool). Used as a simpler blocking variant, but the primary MCP tool handler is in server.py.
def ask_user( question: str, channel: str | None = None, context: str | None = None, timeout_minutes: int = 5, ) -> dict: """Send a question to the user via Slack and wait for their reply. Use this when you need user input or a decision. The user will be notified and can reply in the Slack thread. Args: question: The question to ask the user. channel: Channel name or ID. Uses SLACK_DEFAULT_CHANNEL if not specified. context: Optional context to include (e.g., what you're working on). timeout_minutes: How long to wait for a reply (default 5 minutes, max 30). Returns: Dict with success status and user's reply text if received. """ client = _get_client() # Cap timeout at 30 minutes timeout_minutes = min(timeout_minutes, 30) timeout_seconds = timeout_minutes * 60 # Format the question message if context: formatted_message = ( f":question: *Claude Code needs your input*\n\n" f"*Context:* {context}\n\n" f"*Question:* {question}\n\n" f"_Reply in this thread within {timeout_minutes} minutes._" ) else: formatted_message = ( f":question: *Claude Code needs your input*\n\n" f"{question}\n\n" f"_Reply in this thread within {timeout_minutes} minutes._" ) # Send the question send_result = client.send_message(text=formatted_message, channel=channel) if not send_result.ok: return { "success": False, "message": f"Failed to send question: {send_result.error}", "error": send_result.error, "reply": None, } # Wait for reply reply = client.wait_for_reply( channel=send_result.channel, thread_ts=send_result.ts, timeout_seconds=timeout_seconds, ) if reply: # Send acknowledgment client.send_message( text=":white_check_mark: Got it, thanks!", channel=send_result.channel, thread_ts=send_result.ts, ) return { "success": True, "message": "Received user reply", "reply": reply.text, "replied_by": reply.user_name or reply.user, "user_id": reply.user, "ts": reply.ts, "channel": send_result.channel, "thread_ts": send_result.ts, } else: # Send timeout message client.send_message( text=f":hourglass: No reply received after {timeout_minutes} minutes. Continuing without input.", channel=send_result.channel, thread_ts=send_result.ts, ) return { "success": False, "message": f"No reply received within {timeout_minutes} minutes", "reply": None, "channel": send_result.channel, "thread_ts": send_result.ts, }