Skip to main content
Glama
mikeysrecipes

interactive-mcp

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
NameRequiredDescriptionDefault
sessionIdYesID of the intensive chat session
questionYesQuestion to ask the user
predefinedOptionsNoPredefined options for the user to choose from (optional)

Implementation Reference

  • MCP tool handler for 'ask_intensive_chat': destructures args, checks active session, calls askQuestionInSession helper, handles timeout/empty/error responses and formats MCP content 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,
            },
          ],
        };
      }
    },
  • 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 function
    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,
                },
              ],
            };
          }
        },
      );
    }
  • 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 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 = 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 capabilities
    const 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;
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden and does well: it discloses that the tool requires a session ID from another tool, supports predefined options, returns user answers or non-response indicators, should be used repeatedly within sessions, maintains chat history, and has specific best practices. It doesn't mention rate limits, authentication needs, or error conditions, but covers most behavioral aspects well for a chat tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear sections, but is overly verbose with redundant information. The core purpose is stated upfront, but sections like <features> largely repeat what's in other parts. While organized, it could be more concise by eliminating duplication between sections like <importantNotes>, <features>, and <parameters>.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no annotations and no output schema, the description provides substantial context: it explains the tool's role in a workflow, prerequisites, usage patterns, behavioral characteristics, and best practices. The main gap is the lack of output description (what format the response takes), but given the tool's relatively simple purpose and good behavioral coverage, it's mostly complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all three parameters thoroughly. The description's <parameters> section repeats what's in the schema without adding significant semantic context beyond what's already covered. The <examples> section provides some usage context but doesn't fundamentally enhance parameter understanding beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states 'Ask a new question in an active intensive chat session previously started with 'start_intensive_chat'' - this provides a specific verb ('Ask'), resource ('question'), and context ('intensive chat session'), clearly distinguishing it from sibling tools like 'start_intensive_chat' and 'stop_intensive_chat'. The purpose is immediately clear in the first sentence.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides extensive guidance through dedicated sections: <whenToUseThisTool> lists four specific scenarios, <importantNotes> explicitly states when to use ('Use this repeatedly within the same response message after 'start_intensive_chat' until all questions are asked'), and the description itself mentions the prerequisite ('Requires a valid session ID from 'start_intensive_chat''). This gives clear when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mikeysrecipes/interactive-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server