search_skills
Find relevant skills by topic or keyword in the Hivemind MCP knowledge base, returning summaries to identify useful solutions.
Instructions
Search for skills by topic/keyword. Returns lightweight summaries - use get_skill() for full details.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Topic or keyword to search for (e.g., 'deployment', 'testing', 'CI/CD') |
Implementation Reference
- src/api.ts:210-224 (handler)Primary handler function for search_skills tool. Performs HTTP POST to backend /search-skills endpoint with query, returns SkillSearchResult.export async function searchSkills(query: string, maxResults: number = 20): Promise<SkillSearchResult> { const response = await fetch(`${API_BASE}/search-skills`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ query, max_results: maxResults }), }); if (!response.ok) { throw new Error(`Search skills failed: ${response.statusText}`); } return response.json(); }
- src/index.ts:85-99 (schema)MCP tool schema definition: name, description, and inputSchema requiring 'query' string parameter.{ name: "search_skills", description: "Search for skills by topic/keyword. Returns lightweight summaries - use get_skill() for full details.", inputSchema: { type: "object", properties: { query: { type: "string", description: "Topic or keyword to search for (e.g., 'deployment', 'testing', 'CI/CD')", }, }, required: ["query"], }, },
- src/index.ts:387-392 (handler)MCP server CallToolRequest handler dispatches search_skills calls to searchSkills function and returns JSON response.case "search_skills": { const result = await searchSkills(args?.query as string); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; }
- Backend Supabase edge function handler for /search-skills. Executes PostgreSQL RPC search_knowledge filtered to type='skill', maps to lightweight skill objects (id, title, category, preview, relevance), handles errors and rate limits.async function handleSearchSkills(supabase: any, body: any, corsHeaders: any) { const { query, max_results = 20 } = body; if (!query) { return new Response(JSON.stringify({ error: 'query parameter required' }), { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }); } const startTime = performance.now(); // Cap at 50 to prevent huge responses const cappedLimit = Math.min(max_results, 50); // Use FTS search filtered to skills only const { data: results, error } = await supabase.rpc('search_knowledge', { search_query: query, result_limit: cappedLimit, type_filter: 'skill' }); if (error) { console.error('Skills search error:', error); return new Response(JSON.stringify({ error: 'Search failed' }), { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }); } const searchTime = performance.now() - startTime; // Return lightweight summaries only (no full solutions array) const skills = (results || []).map((r: any) => ({ id: r.id, title: r.query, category: r.category, // Just first solution as preview, not the full array preview: r.solutions?.[0]?.solution?.substring(0, 150) + '...' || '', relevance: r.search_rank ? Math.abs(r.search_rank) : 0.5 })); return new Response(JSON.stringify({ query, skills, total: skills.length, tip: skills.length > 0 ? `Use get_skill(${skills[0].id}) to see full details` : 'No matching skills found', query_metadata: { search_method: 'postgres_fts', search_time_ms: Math.round(searchTime * 100) / 100 }, _ctx: "SEARCH FIRST: Check available skills before building custom solutions." }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }); }
- src/api.ts:178-189 (schema)TypeScript interface defining the expected output structure of searchSkills (SkillSearchResult).interface SkillSearchResult { query: string; skills: Array<{ id: number; title: string; category: string; preview: string; relevance: number; }>; total: number; tip: string; }