Skip to main content
Glama
jgsteeler

ChurnFlow MCP Server

by jgsteeler

capture

Capture and route text input through an ADHD-friendly AI system for automatic context detection and intelligent task organization, reducing cognitive overhead.

Instructions

Capture and route text input using ChurnFlow ADHD-friendly AI system

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
contextNoOptional context hint for routing (business, personal, project, system)
priorityNoPriority level for the captured content
textYesText to capture and route (can contain multiple items)

Implementation Reference

  • The MCP 'capture' tool handler function. Initializes the CaptureEngine, processes input arguments into CaptureInput, executes capture, and returns formatted MCP CallToolResult with success summary or error.
    /**
     * Handle capture tool requests
     */
    async function handleCapture(args: any): Promise<CallToolResult> {
      try {
        await initializeCaptureEngine();
        
        if (!captureEngine) {
          throw new Error('Failed to initialize capture engine');
        }
    
        const input: CaptureInput = {
          text: args.text,
          inputType: 'text',
          forceContext: args.context,
        };
    
        const result: CaptureResult = await captureEngine.capture(input);
    
        if (!result.success) {
          return {
            content: [
              {
                type: 'text',
                text: `Capture failed: ${result.error}`,
              },
            ],
            isError: true,
          };
        }
    
        // Format successful capture result
        const summary = [
          `✅ Capture Successful!`,
          `📁 Primary Tracker: ${result.primaryTracker}`,
          `🎯 Confidence: ${Math.round(result.confidence * 100)}%`,
          `📊 Generated ${result.itemResults?.length || 0} items`,
          '',
        ];
    
        if (result.itemResults && result.itemResults.length > 0) {
          summary.push('📝 Items Generated:');
          result.itemResults.forEach(item => {
            summary.push(`  ✅ ${item.itemType} → ${item.tracker}`);
            summary.push(`     ${item.formattedEntry}`);
          });
        }
    
        if (result.completedTasks && result.completedTasks.length > 0) {
          summary.push('');
          summary.push('🎯 Task Completions:');
          result.completedTasks.forEach(completion => {
            summary.push(`  ✅ completion in ${completion.tracker}`);
            summary.push(`     ${completion.description}`);
          });
        }
    
        return {
          content: [
            {
              type: 'text',
              text: summary.join('\n'),
            },
          ],
          isError: false,
        };
      } catch (error) {
        return {
          content: [
            {
              type: 'text',
              text: `Error during capture: ${error instanceof Error ? error.message : String(error)}`,
            },
          ],
          isError: true,
        };
      }
    }
  • JSON schema definition for the 'capture' tool input, including required 'text' field and optional 'priority' and 'context'.
    {
      name: 'capture',
      description: 'Capture and route text input using ChurnFlow ADHD-friendly AI system',
      inputSchema: {
        type: 'object',
        properties: {
          text: {
            type: 'string',
            description: 'Text to capture and route (can contain multiple items)',
          },
          priority: {
            type: 'string',
            enum: ['high', 'medium', 'low'],
            description: 'Priority level for the captured content',
          },
          context: {
            type: 'string',
            description: 'Optional context hint for routing (business, personal, project, system)',
          },
        },
        required: ['text'],
      },
    },
  • src/index.ts:334-350 (registration)
    Registration of CallToolRequestHandler with switch statement that dispatches calls to 'capture' tool to the handleCapture function.
    server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;
    
      switch (name) {
        case 'capture':
          return await handleCapture(args);
        
        case 'status':
          return await handleStatus();
        
        case 'list_trackers':
          return await handleListTrackers(args);
        
        default:
          throw new Error(`Unknown tool: ${name}`);
      }
    });
  • src/index.ts:329-331 (registration)
    Registration of ListToolsRequestHandler that returns the list of available tools including 'capture'.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return { tools: TOOLS };
    });
  • Core implementation of capture logic in CaptureEngine class: AI inference, item/task processing, routing to trackers, database save, error handling with review/emergency fallbacks.
    async capture(input: string | CaptureInput): Promise<CaptureResult> {
      if (!this.initialized) {
        await this.initialize();
      }
    
      // Normalize input
      const captureInput: CaptureInput =
        typeof input === "string" ? { text: input, inputType: "text" } : input;
    
      console.log(`🎯 Capturing: "${captureInput.text}"`);
    
      try {
        // Use AI to infer routing and generate multiple items
        const inference = await this.inferenceEngine.inferCapture(captureInput);
    
        console.log(
          `🤖 AI inference: ${inference.primaryTracker} (${inference.confidence * 100}% confidence)`,
        );
        console.log(`📝 Analysis: ${inference.overallReasoning}`);
        console.log(
          `🔢 Generated ${inference.generatedItems.length} items, ${inference.taskCompletions.length} completions`,
        );
    
        // Handle low confidence - route to review
        if (inference.requiresReview) {
          return await this.routeToReview(captureInput, inference);
        }
    
        // Process task completions first
        const completedTasks = [];
        for (const completion of inference.taskCompletions) {
          console.log(`✅ Task completion detected: ${completion.description} in ${completion.tracker}`);
          
          // Actually mark the task as complete in the tracker file
          const success = await this.trackerManager.markTaskComplete(
            completion.tracker,
            completion.description
          );
          
          completedTasks.push({
            ...completion,
            success
          });
          
          if (success) {
            console.log(`✅ Successfully marked task as complete: ${completion.description}`);
          } else {
            console.error(`❌ Failed to mark task as complete: ${completion.description}`);
          }
        }
    
        // Process generated items
        const itemResults = [];
        for (const item of inference.generatedItems) {
          console.log(
            `📝 Processing ${item.itemType} for ${item.tracker}: ${item.reasoning}`,
          );
    
          let success: boolean;
          if (item.itemType === "activity") {
            success = await this.trackerManager.appendActivityToTracker(
              item.tracker,
              item.content,
            );
          } else {
            success = await this.trackerManager.appendToTracker(
              item.tracker,
              item.content,
            );
          }
    
          itemResults.push({
            success,
            tracker: item.tracker,
            itemType: item.itemType,
            formattedEntry: item.content,
            error: success ? undefined : `Failed to write to ${item.tracker}`,
          });
    
          if (success) {
            console.log(
              `✅ ${item.itemType} successfully added to ${item.tracker}`,
            );
          } else {
            console.error(`❌ Failed to add ${item.itemType} to ${item.tracker}`);
          }
        }
    
        // Determine overall success
        const overallSuccess = itemResults.some((result) => result.success);
        
        // Save to database if available (optional - doesn't affect capture success)
        if (overallSuccess && this.databaseAvailable) {
          try {
            await this.saveCaptureToDatabase(captureInput, inference, itemResults, overallSuccess);
          } catch (dbError) {
            console.warn("⚠️ Failed to save to database (file saved successfully):", dbError);
          }
        }
    
        return {
          success: overallSuccess,
          primaryTracker: inference.primaryTracker,
          confidence: inference.confidence,
          itemResults,
          completedTasks,
          requiresReview: false,
        };
      } catch (error) {
        console.error("❌ Capture failed:", error);
    
        // Emergency fallback - try to save somewhere
        return await this.emergencyCapture(captureInput, error as Error);
      }
    }
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It mentions 'capture and route' but doesn't explain what 'route' entails (e.g., where the text goes, how it's processed, or any side effects). There's no information on permissions, rate limits, or what happens after routing, leaving significant gaps for a tool that likely involves data handling.

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

Conciseness5/5

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

The description is a single, efficient sentence that front-loads the core action ('Capture and route text input') and specifies the system. There's no wasted verbiage, and every word contributes to understanding the tool's purpose, making it appropriately concise and well-structured.

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

Completeness2/5

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

Given the complexity of a tool that captures and routes text, with no annotations and no output schema, the description is incomplete. It lacks details on behavioral traits, output format, or how routing works, which are crucial for an agent to use it correctly. The description alone is insufficient for a tool with potential side effects and undefined results.

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 adds no additional meaning beyond what's in the schema (e.g., it doesn't clarify 'routing' behavior related to parameters). With high schema coverage, the baseline score of 3 is appropriate as the description doesn't compensate but also doesn't detract.

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

Purpose4/5

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

The description clearly states the tool's purpose: 'Capture and route text input' with the specific system 'ChurnFlow ADHD-friendly AI system'. It distinguishes from siblings like 'list_trackers' and 'status' by focusing on input capture rather than listing or checking status. However, it doesn't explicitly differentiate from potential similar tools beyond the named siblings.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. There's no mention of when to choose 'capture' over 'list_trackers' or 'status', nor any context about prerequisites or typical scenarios for routing text input. Usage is implied but not explicitly stated.

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/jgsteeler/churnflow-mcp'

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