Skip to main content
Glama

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; }>; }

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