Skip to main content
Glama
anortham

COA Goldfish MCP

by anortham

search_history

Search and retrieve work history with fuzzy matching across checkpoints and workspaces to answer context-specific queries like "Did we fix the auth bug last week?" Supports time range, scope, and result limits.

Instructions

Search work history with fuzzy matching. Perfect for "Did we fix the auth bug last week?" type questions. Searches across checkpoints and finds relevant work.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum results to return (default: 20)
queryYesSearch query (e.g., "auth bug fix", "database migration")
scopeNoSearch scope: current workspace or all workspaces
sinceNoTime range (e.g., "3d", "1w", "yesterday", "2025-01-15")
workspaceNoSpecific workspace to search (optional)

Implementation Reference

  • Main handler function for the search_history tool. Performs fuzzy search on work history checkpoints using Fuse.js-powered SearchEngine, handles no-results case, formats output with age, scores, highlights, and match snippets. Returns structured SearchHistoryResponse.
    async searchHistory(args: {
      query: string;
      since?: string;
      workspace?: string;
      scope?: 'current' | 'all';
      limit?: number;
      format?: OutputMode;
    }) {
      const {
        query,
        since,
        workspace,
        scope = 'current',
        limit = 20,
        format
      } = args;
    
      try {
        const results = await this.searchEngine.searchWithHighlights(query, {
          since,
          workspace,
          scope,
          limit,
          type: 'checkpoint' // Focus on checkpoints for history
        });
    
        if (results.length === 0) {
          const formatted = `šŸ” No results found for "${query}"\n\nTry:\n• Different keywords\n• Broader time range (e.g., since: "7d")\n• Cross-workspace search (scope: "all")`;
          const data = { query, since, workspace, scope, resultsFound: 0 } as const;
          return buildToolContent('search-history', formatted, data as any, format);
        }
    
        const output = [`šŸ” Found ${results.length} results for "${query}"\n`];
    
        for (const result of results.slice(0, 10)) {
          const { memory, score, matches } = result;
          const age = this.formatAge(memory.timestamp);
          const workspace = memory.workspace === this.storage.getCurrentWorkspace() 
            ? '' 
            : ` [${memory.workspace}]`;
    
          output.push(`šŸ’¾ ${age}${workspace} - Score: ${(1 - score).toFixed(2)}`);
          
          if (typeof memory.content === 'object' && memory.content && 'description' in memory.content) {
            const contentObj = memory.content as { description?: string; highlights?: string[] };
            output.push(`   ${contentObj.description}`);
            
            if (contentObj.highlights && Array.isArray(contentObj.highlights) && contentObj.highlights.length > 0) {
              output.push(`   ✨ ${contentObj.highlights.slice(0, 2).join(', ')}`);
            }
          } else {
            output.push(`   ${memory.content}`);
          }
    
          // Show match context (skip if it looks like raw JSON)
          if (matches.length > 0) {
            const bestMatch = matches[0];
            if (bestMatch && bestMatch.value && !bestMatch.value.startsWith('{')) {
              const snippet = this.getMatchSnippet(bestMatch.value, bestMatch.indices);
              output.push(`   šŸŽÆ "${snippet}"`);
            }
          }
    
          output.push('');
        }
    
        if (results.length > 10) {
          output.push(`... and ${results.length - 10} more results`);
        }
    
        const formatted = output.join('\n');
        const data = {
          query,
          resultsFound: results.length,
          matches: results.slice(0, 10).map(result => ({
            memory: result.memory as Record<string, unknown>,
            score: 1 - result.score,
            snippet: result.matches.length > 0 && result.matches[0]
              ? this.getMatchSnippet(result.matches[0].value, result.matches[0].indices)
              : undefined
          }))
        } as const;
        return buildToolContent('search-history', formatted, data as any, format);
      } catch (error) {
        return {
          content: [
            {
              type: 'text',
              text: `āŒ Search failed: ${error instanceof Error ? error.message : String(error)}`
            }
          ]
        };
      }
    }
  • Input schema definition for search_history tool, defining parameters like query (required), since, workspace, scope, limit, format with descriptions and defaults.
    {
      name: 'search_history',
      description: 'Find past work and solutions. Use when user asks about previous implementations or mentions earlier tasks. Searches all work history.',
      inputSchema: {
        type: 'object',
        properties: {
          query: {
            type: 'string',
            description: 'Search query (e.g., "auth bug fix", "database migration")'
          },
          since: {
            type: 'string',
            description: 'Time range (e.g., "3d", "1w", "yesterday", "2025-01-15")'
          },
          workspace: {
            type: 'string',
            description: 'Workspace name or path (e.g., "coa-goldfish-mcp" or "C:\\source\\COA Goldfish MCP"). Will be normalized automatically.'
          },
          scope: {
            type: 'string',
            enum: ['current', 'all'],
            description: 'Search scope: current workspace or all workspaces',
            default: 'current'
          },
          limit: {
            type: 'number',
            description: 'Maximum results to return (default: 20)',
            default: 20
          },
          format: {
            type: 'string',
            enum: ['plain', 'emoji', 'json', 'dual'],
            description: 'Output format override (defaults to env GOLDFISH_OUTPUT_MODE or dual)'
          }
        },
        required: ['query']
      }
  • Tool dispatch registration in main MCP server switch statement: validates query param and delegates to SearchTools.searchHistory method.
    case 'search_history':
      if (!args || typeof args !== 'object' || !args.query) {
        throw new Error('search_history requires query parameter');
      }
      return await this.searchTools.searchHistory(args as { query: string; since?: string; workspace?: string; scope?: 'current' | 'all'; limit?: number });
  • Registers search_history schema by including SearchTools.getToolSchemas() in the listTools response tools array.
    ...SearchTools.getToolSchemas(),
  • TypeScript interface defining the structured response format for search_history results.
    export interface SearchHistoryResponse extends FormattedResponse {
      operation: 'search-history';
      query: string;
      resultsFound: number;
      matches?: Array<{
        memory: Record<string, unknown>;
        score: number;
        snippet?: string;
      }>;
    }
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 'fuzzy matching' and searching across checkpoints, but fails to address critical aspects like whether this is a read-only operation, potential rate limits, authentication needs, or what the output format looks like (e.g., list of results with details). For a search tool with 5 parameters, this leaves significant gaps.

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

Conciseness4/5

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

The description is appropriately sized with three sentences: the first states the core functionality, the second gives a concrete example, and the third clarifies scope. Each sentence adds value without redundancy, though it could be slightly more front-loaded by merging the second and third points.

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

Completeness3/5

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

Given the tool's moderate complexity (5 parameters, no output schema, no annotations), the description is incomplete. It covers the purpose and basic usage but lacks details on behavioral traits, output format, and error handling. Without annotations or output schema, more context is needed for effective agent use, though it's minimally viable.

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 5 parameters thoroughly. The description adds minimal value beyond the schema by implying the query is for work-related topics (e.g., 'auth bug') but doesn't provide additional syntax, format details, or constraints. Baseline 3 is appropriate as the schema does the heavy lifting.

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 clearly states the tool's purpose with specific verbs ('search work history with fuzzy matching') and resource ('work history'), distinguishing it from siblings like 'timeline' or 'summarize_session' by emphasizing fuzzy search across checkpoints. The example question further clarifies its use case for finding past work.

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

Usage Guidelines3/5

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

The description implies usage for finding relevant past work with fuzzy matching, as shown in the example question, but lacks explicit guidance on when to use this tool versus alternatives like 'recall' or 'timeline'. It provides context but no clear exclusions or comparisons to sibling tools.

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

Related 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/anortham/coa-goldfish-mcp'

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