ask_intensive_chat
Ask follow-up questions within an active chat session to gather sequential information or offer multiple-choice options for user responses.
Instructions
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| sessionId | Yes | ID of the intensive chat session | |
| question | Yes | Question to ask the user | |
| predefinedOptions | No | Predefined options for the user to choose from (optional) |
Implementation Reference
- src/index.ts:232-294 (handler)MCP tool handler for 'ask_intensive_chat': destructures args, checks active session, calls askQuestionInSession helper, handles timeout/empty/error responses and formats MCP content responseasync (args) => { // Use inferred args type const { sessionId, question, predefinedOptions } = args; // Check if session exists if (!activeChatSessions.has(sessionId)) { return { content: [ { type: 'text', text: 'Error: Invalid or expired session ID.' }, ], }; } try { // Ask the question in the session const answer = await askQuestionInSession( sessionId, question, predefinedOptions, ); // Check for the specific timeout indicator if (answer === '__TIMEOUT__') { return { content: [ { type: 'text', text: 'User did not reply to question in intensive chat: Timeout occurred.', }, ], }; } // Empty string means user submitted empty input, non-empty is actual reply else if (answer === '') { return { content: [ { type: 'text', text: 'User replied with empty input in intensive chat.', }, ], }; } else { return { content: [{ type: 'text', text: `User replied: ${answer}` }], }; } } catch (error: unknown) { let errorMessage = 'Failed to ask question in session.'; if (error instanceof Error) { errorMessage = `Failed to ask question in session: ${error.message}`; } else if (typeof error === 'string') { errorMessage = `Failed to ask question in session: ${error}`; } return { content: [ { type: 'text', text: errorMessage, }, ], }; } },
- Zod schema defining input parameters for ask_intensive_chat tool: sessionId (required), question (required), predefinedOptions (optional array)const askSchema: ZodRawShape = { sessionId: z.string().describe('ID of the intensive chat session'), question: z.string().describe('Question to ask the user'), predefinedOptions: z .array(z.string()) .optional() .describe('Predefined options for the user to choose from (optional)'), };
- src/index.ts:223-296 (registration)Registration of 'ask_intensive_chat' tool with MCP server using server.tool(), including dynamic description, schema from intensiveChatTools, and handler functionif (isToolEnabled('ask_intensive_chat')) { // Use properties from the imported intensiveChatTools object server.tool( 'ask_intensive_chat', // Description is a string here typeof intensiveChatTools.ask.description === 'function' ? intensiveChatTools.ask.description(globalTimeoutSeconds) // Should not happen, but safe : intensiveChatTools.ask.description, intensiveChatTools.ask.schema, // Use schema property async (args) => { // Use inferred args type const { sessionId, question, predefinedOptions } = args; // Check if session exists if (!activeChatSessions.has(sessionId)) { return { content: [ { type: 'text', text: 'Error: Invalid or expired session ID.' }, ], }; } try { // Ask the question in the session const answer = await askQuestionInSession( sessionId, question, predefinedOptions, ); // Check for the specific timeout indicator if (answer === '__TIMEOUT__') { return { content: [ { type: 'text', text: 'User did not reply to question in intensive chat: Timeout occurred.', }, ], }; } // Empty string means user submitted empty input, non-empty is actual reply else if (answer === '') { return { content: [ { type: 'text', text: 'User replied with empty input in intensive chat.', }, ], }; } else { return { content: [{ type: 'text', text: `User replied: ${answer}` }], }; } } catch (error: unknown) { let errorMessage = 'Failed to ask question in session.'; if (error instanceof Error) { errorMessage = `Failed to ask question in session: ${error.message}`; } else if (typeof error === 'string') { errorMessage = `Failed to ask question in session: ${error}`; } return { content: [ { type: 'text', text: errorMessage, }, ], }; } }, ); }
- Helper function implementing the core logic: writes question to session JSON file, generates unique question ID, polls for corresponding response file, handles timeout and session checksexport async function askQuestionInSession( sessionId: string, question: string, predefinedOptions?: string[], ): Promise<string | null> { const session = activeSessions[sessionId]; if (!session || !session.isActive) { return null; // Session doesn't exist or is not active } // Generate a unique ID for this question-answer pair const questionId = crypto.randomUUID(); // Create the input data object const inputData: { id: string; text: string; options?: string[] } = { id: questionId, text: question, }; if (predefinedOptions && predefinedOptions.length > 0) { inputData.options = predefinedOptions; } // Write the combined input data to a session-specific JSON file const inputFilePath = path.join(session.outputDir, `${sessionId}.json`); await fs.writeFile(inputFilePath, JSON.stringify(inputData), 'utf8'); // Wait for the response file corresponding to the generated ID const responseFilePath = path.join( session.outputDir, `response-${questionId}.txt`, ); // Wait for response with timeout const maxWaitTime = 60000; // 60 seconds max wait time const pollInterval = 100; // 100ms polling interval const startTime = Date.now(); while (Date.now() - startTime < maxWaitTime) { try { // Check if the response file exists await fs.access(responseFilePath); // Read the response const response = await fs.readFile(responseFilePath, 'utf8'); // Clean up the response file await fs.unlink(responseFilePath).catch(() => {}); return response; } catch { // Response file doesn't exist yet, check session status if (!(await isSessionActive(sessionId))) { return null; // Session has ended } // Wait before polling again await new Promise((resolve) => setTimeout(resolve, pollInterval)); } } // Timeout reached return 'User closed intensive chat session'; }
- src/index.ts:28-34 (registration)Initial registration of tool capabilities including 'ask_intensive_chat' from intensiveChatTools.ask.capability for MCP server capabilitiesconst allToolCapabilities = { request_user_input: requestUserInputTool.capability, message_complete_notification: messageCompleteNotificationTool.capability, start_intensive_chat: intensiveChatTools.start.capability, ask_intensive_chat: intensiveChatTools.ask.capability, stop_intensive_chat: intensiveChatTools.stop.capability, } satisfies ToolCapabilitiesStructure;