Skip to main content
Glama
match.go4.67 kB
package tools import ( "strings" "unicode" ) // MatchScore represents the result of a fuzzy match type MatchScore struct { ToolName string // Name of the matching tool Score float64 // Score from 0.0 to 1.0 (higher is better) Reason string // Why this match was selected } // MatchToolName finds the best tool match for a natural language query // Returns empty string if no good match is found func MatchToolName(query string) *MatchScore { if query == "" { return nil } // Normalize query query = strings.TrimSpace(strings.ToLower(query)) // Track best match bestMatch := &MatchScore{ ToolName: "", Score: 0.0, Reason: "", } // Check each tool and its metadata for toolName, metadata := range ToolNLMetadata { // 1. Check exact match with tool name if strings.ToLower(toolName) == query { return &MatchScore{ ToolName: toolName, Score: 1.0, Reason: "Exact tool name match", } } // 2. Check aliases (exact matches) for _, alias := range metadata.Aliases { if strings.ToLower(alias) == query { return &MatchScore{ ToolName: toolName, Score: 0.95, Reason: "Exact alias match: " + alias, } } } // 3. Try substring matching against tool name if strings.Contains(strings.ToLower(toolName), query) { score := 0.85 if score > bestMatch.Score { bestMatch.ToolName = toolName bestMatch.Score = score bestMatch.Reason = "Tool name contains query" } } // 4. Check aliases with substring matching for _, alias := range metadata.Aliases { if strings.Contains(strings.ToLower(alias), query) { score := 0.8 if score > bestMatch.Score { bestMatch.ToolName = toolName bestMatch.Score = score bestMatch.Reason = "Alias contains query: " + alias } } } // 5. Check if query contains tool name if strings.Contains(query, strings.ToLower(toolName)) { score := 0.75 if score > bestMatch.Score { bestMatch.ToolName = toolName bestMatch.Score = score bestMatch.Reason = "Query contains tool name" } } // 6. Check if query contains any aliases for _, alias := range metadata.Aliases { if strings.Contains(query, strings.ToLower(alias)) { score := 0.7 if score > bestMatch.Score { bestMatch.ToolName = toolName bestMatch.Score = score bestMatch.Reason = "Query contains alias: " + alias } } } // 7. Check examples with similarity scoring for _, example := range metadata.Examples { similarity := calculateSimilarity(query, strings.ToLower(example)) if similarity > bestMatch.Score { bestMatch.ToolName = toolName bestMatch.Score = similarity bestMatch.Reason = "Similar to example: " + example } } // 8. Last resort: token overlap with tool name and description tokens1 := tokenize(query) tokens2 := tokenize(strings.ToLower(toolName)) overlap := calculateTokenOverlap(tokens1, tokens2) if overlap > 0.3 && overlap > bestMatch.Score { bestMatch.ToolName = toolName bestMatch.Score = overlap * 0.6 // Scale down token matches bestMatch.Reason = "Token overlap with tool name" } } // Only return a match if we're reasonably confident if bestMatch.Score > 0.4 { return bestMatch } return nil } // calculateSimilarity scores how similar two strings are (0.0 to 1.0) func calculateSimilarity(s1, s2 string) float64 { // Special case for exact match if s1 == s2 { return 0.9 } // Special case for substring if strings.Contains(s1, s2) || strings.Contains(s2, s1) { return 0.8 } // Check token overlap tokens1 := tokenize(s1) tokens2 := tokenize(s2) return calculateTokenOverlap(tokens1, tokens2) * 0.7 } // tokenize splits a string into tokens (words) func tokenize(s string) []string { // Split on whitespace and remove empty strings tokens := strings.FieldsFunc(s, func(r rune) bool { return unicode.IsSpace(r) || unicode.IsPunct(r) }) // Convert to lowercase for i, token := range tokens { tokens[i] = strings.ToLower(token) } return tokens } // calculateTokenOverlap determines how many tokens overlap between two sets func calculateTokenOverlap(tokens1, tokens2 []string) float64 { if len(tokens1) == 0 || len(tokens2) == 0 { return 0.0 } // Create a map for tokens1 tokenMap := make(map[string]bool) for _, t1 := range tokens1 { if len(t1) > 2 { // Only consider meaningful words (>2 chars) tokenMap[t1] = true } } // Count matches in tokens2 matches := 0 for _, t2 := range tokens2 { if len(t2) > 2 && tokenMap[t2] { matches++ } } // Average overlap ratio return float64(matches) / float64((len(tokens1)+len(tokens2))/2) }

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/MrFixit96/go-dev-mcp'

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