helm-chart-values-fuzzy-search
Search Helm chart values.yaml files with fuzzy matching to find properties, values, and comments across repositories and versions.
Instructions
Fuzzy search through all properties/values/comments in a Helm chart's values.yaml file
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| chartRepo | Yes | The Helm chart repository name | |
| chartName | Yes | The Helm chart name | |
| searchQuery | Yes | The search query for fuzzy matching | |
| version | No | The chart version (optional, defaults to latest) |
Implementation Reference
- src/tools/fuzzySearchValues.ts:101-187 (handler)Main handler logic: fetches chart info and values.yaml from ArtifactHub, parses YAML with comments, collects all properties recursively, uses Fuse.js for fuzzy search on name/path/comment/value, formats and returns markdown results or error.async ({ chartRepo, chartName, searchQuery, version, }: FuzzySearchParams) => { try { let packageId: string; let chartVersion: string; // First get the chart info const chartInfo = await getChartInfo(chartRepo, chartName); packageId = chartInfo.package_id; // If version is not provided, use the latest version chartVersion = version || chartInfo.version; // Get the values.yaml const valuesYaml = await getChartValues(packageId, chartVersion); // Parse YAML to get the value const parsedYaml = parse(valuesYaml); const doc = parseDocument(valuesYaml); // Collect all properties recursively const allProperties = collectPropertiesRecursive(parsedYaml, "", doc); // Set up Fuse.js for fuzzy searching const fuse = new Fuse(allProperties, { keys: ["propertyName", "propertyPath", "comment", "value"], includeScore: true, threshold: 0.4, }); // Perform the fuzzy search const searchResults = fuse.search(searchQuery); // Format the results let responseText = ""; if (searchResults.length > 0) { responseText = `# Found ${searchResults.length} matching properties:\n\n`; searchResults.forEach((result, index) => { const property = result.item; responseText += `## ${index + 1}. ${property.propertyPath}\n`; if (property.comment) { responseText += `Comment: ${property.comment.trim()}\n`; } if (property.value !== undefined) { responseText += `Value: ${ typeof property.value === "object" ? JSON.stringify(property.value, null, 2) : String(property.value) }\n`; } else { responseText += "Value: [object]\n"; } responseText += "\n"; }); } else { responseText = `No properties matching "${searchQuery}" found.`; } return { content: [ { type: "text", text: responseText, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error performing fuzzy search: ${ (error as Error).message }`, }, ], }; } }
- Zod schema for tool input parameters: chartRepo, chartName, searchQuery, optional version.{ chartRepo: z.string().describe("The Helm chart repository name"), chartName: z.string().describe("The Helm chart name"), searchQuery: z.string().describe("The search query for fuzzy matching"), version: z .string() .optional() .describe("The chart version (optional, defaults to latest)"), },
- src/index.ts:19-19 (registration)Top-level registration call that invokes the tool registration function on the MCP server instance.registerFuzzySearchValuesTool(server);
- src/tools/fuzzySearchValues.ts:17-80 (helper)Recursive helper to traverse YAML object, extract property paths, values (leaf only), and associated comments using yaml parseDocument nodes.function collectPropertiesRecursive( obj: any, currentPath = "", doc: any, result: ValueProperty[] = [] ): ValueProperty[] { if (obj === null || typeof obj !== "object") { return result; } for (const key in obj) { const value = obj[key]; const newPath = currentPath ? `${currentPath}.${key}` : key; // Try to extract comment for this property let comment: string | undefined = undefined; try { // Navigate through the document to find comments let currentNode = doc.contents; for (const part of newPath.split(".")) { if ( currentNode && typeof currentNode === "object" && "get" in currentNode ) { const node = currentNode.get(part); if (node) { if (node.commentBefore) { comment = node.commentBefore; } currentNode = node; } else { break; } } else { break; } } } catch (e) { // If we can't get comments, just ignore and continue } // Add property to result const property: ValueProperty = { propertyName: key, propertyPath: newPath, comment, }; // Only add value if it's not an object if (value === null || typeof value !== "object") { property.value = value; } result.push(property); // Recursively process nested objects if (value !== null && typeof value === "object") { collectPropertiesRecursive(value, newPath, doc, result); } } return result; }
- src/tools/fuzzySearchValues.ts:88-189 (registration)Tool registration function defining the tool name, description, schema, and handler using MCP server.tool method.export function registerFuzzySearchValuesTool(server: McpServer) { return server.tool( "helm-chart-values-fuzzy-search", "Fuzzy search through all properties/values/comments in a Helm chart's values.yaml file", { chartRepo: z.string().describe("The Helm chart repository name"), chartName: z.string().describe("The Helm chart name"), searchQuery: z.string().describe("The search query for fuzzy matching"), version: z .string() .optional() .describe("The chart version (optional, defaults to latest)"), }, async ({ chartRepo, chartName, searchQuery, version, }: FuzzySearchParams) => { try { let packageId: string; let chartVersion: string; // First get the chart info const chartInfo = await getChartInfo(chartRepo, chartName); packageId = chartInfo.package_id; // If version is not provided, use the latest version chartVersion = version || chartInfo.version; // Get the values.yaml const valuesYaml = await getChartValues(packageId, chartVersion); // Parse YAML to get the value const parsedYaml = parse(valuesYaml); const doc = parseDocument(valuesYaml); // Collect all properties recursively const allProperties = collectPropertiesRecursive(parsedYaml, "", doc); // Set up Fuse.js for fuzzy searching const fuse = new Fuse(allProperties, { keys: ["propertyName", "propertyPath", "comment", "value"], includeScore: true, threshold: 0.4, }); // Perform the fuzzy search const searchResults = fuse.search(searchQuery); // Format the results let responseText = ""; if (searchResults.length > 0) { responseText = `# Found ${searchResults.length} matching properties:\n\n`; searchResults.forEach((result, index) => { const property = result.item; responseText += `## ${index + 1}. ${property.propertyPath}\n`; if (property.comment) { responseText += `Comment: ${property.comment.trim()}\n`; } if (property.value !== undefined) { responseText += `Value: ${ typeof property.value === "object" ? JSON.stringify(property.value, null, 2) : String(property.value) }\n`; } else { responseText += "Value: [object]\n"; } responseText += "\n"; }); } else { responseText = `No properties matching "${searchQuery}" found.`; } return { content: [ { type: "text", text: responseText, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error performing fuzzy search: ${ (error as Error).message }`, }, ], }; } } ); }