ask_intensive_chat
Ask follow-up questions in an active intensive chat session to gather sequential information. Supports predefined options for quick responses and maintains chat history for streamlined interactions.
Instructions
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| predefinedOptions | No | Predefined options for the user to choose from (optional) | |
| question | Yes | Question to ask the user | |
| sessionId | Yes | ID of the intensive chat session |
Implementation Reference
- src/index.ts:239-301 (handler)Handler function registered with MCP server for executing the 'ask_intensive_chat' tool. Validates session ID, calls the core askQuestionInSession helper, handles timeouts and errors, and returns structured MCP response.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, }, ], }; } },
- Core helper function that implements the intensive chat question-asking logic: writes question to JSON file in session dir, polls for response file via filesystem, handles timeout and session checks.export 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 = (session.timeoutSeconds ?? 60) * 1000; // Use session timeout or default to 60s 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'; }
- JSON Schema (ToolCapabilityInfo) defining input parameters for 'ask_intensive_chat': sessionId (required), question (required), predefinedOptions (optional array).const askCapability: ToolCapabilityInfo = { description: 'Ask a question in an active intensive chat session.', parameters: { type: 'object', properties: { sessionId: { type: 'string', description: 'ID of the intensive chat session', }, question: { type: 'string', description: 'Question to ask the user', }, predefinedOptions: { type: 'array', items: { type: 'string' }, optional: true, description: 'Predefined options for the user to choose from (optional)', }, }, required: ['sessionId', 'question'], }, };
- Zod schema for input validation of 'ask_intensive_chat' tool parameters.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:230-303 (registration)Registration of 'ask_intensive_chat' tool with MCP server using server.tool(), including dynamic description, schema, and handler.if (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, }, ], }; } }, ); }