@@ -38,34 +38,45 @@ type ToolsFile struct {
3838 Prompts server.PromptConfigs `yaml:"prompts"`
3939}
4040
41+ type ToolsFileParser struct {
42+ EnvVars map [string ]string
43+ }
44+
4145// parseEnv replaces environment variables ${ENV_NAME} with their values.
4246// also support ${ENV_NAME:default_value}.
43- func parseEnv (input string ) (string , error ) {
47+ func ( p * ToolsFileParser ) parseEnv (input string ) (string , error ) {
4448 re := regexp .MustCompile (`\$\{(\w+)(:([^}]*))?\}` )
4549
50+ if p .EnvVars == nil {
51+ p .EnvVars = make (map [string ]string )
52+ }
53+
4654 var err error
4755 output := re .ReplaceAllStringFunc (input , func (match string ) string {
4856 parts := re .FindStringSubmatch (match )
4957
5058 // extract the variable name
5159 variableName := parts [1 ]
5260 if value , found := os .LookupEnv (variableName ); found {
61+ p .EnvVars [variableName ] = value
5362 return value
5463 }
5564 if len (parts ) >= 4 && parts [2 ] != "" {
56- return parts [3 ]
65+ value := parts [3 ]
66+ p .EnvVars [variableName ] = value
67+ return value
5768 }
5869 err = fmt .Errorf ("environment variable not found: %q" , variableName )
5970 return ""
6071 })
6172 return output , err
6273}
6374
64- // parseToolsFile parses the provided yaml into appropriate configs.
65- func parseToolsFile (ctx context.Context , raw []byte ) (ToolsFile , error ) {
75+ // ParseToolsFile parses the provided yaml into appropriate configs.
76+ func ( p * ToolsFileParser ) ParseToolsFile (ctx context.Context , raw []byte ) (ToolsFile , error ) {
6677 var toolsFile ToolsFile
6778 // Replace environment variables if found
68- output , err := parseEnv (string (raw ))
79+ output , err := p . parseEnv (string (raw ))
6980 if err != nil {
7081 return toolsFile , fmt .Errorf ("error parsing environment variables: %s" , err )
7182 }
@@ -157,7 +168,7 @@ func transformDocs(kind string, input yaml.MapSlice) ([]yaml.MapSlice, error) {
157168 if ! ok {
158169 return nil , fmt .Errorf ("unexpected non-string key for entry in '%s': %v" , kind , entry .Key )
159170 }
160- entryBody := ProcessValue (entry .Value , kind == "toolsets" )
171+ entryBody := processValue (entry .Value , kind == "toolsets" )
161172
162173 currentTransformed := yaml.MapSlice {
163174 {Key : "kind" , Value : kind },
@@ -175,8 +186,8 @@ func transformDocs(kind string, input yaml.MapSlice) ([]yaml.MapSlice, error) {
175186 return transformed , nil
176187}
177188
178- // ProcessValue recursively looks for MapSlices to rename 'kind' -> 'type'
179- func ProcessValue (v any , isToolset bool ) any {
189+ // processValue recursively looks for MapSlices to rename 'kind' -> 'type'
190+ func processValue (v any , isToolset bool ) any {
180191 switch val := v .(type ) {
181192 case yaml.MapSlice :
182193 // creating a new MapSlice is safer for recursive transformation
@@ -187,7 +198,7 @@ func ProcessValue(v any, isToolset bool) any {
187198 item .Key = "type"
188199 }
189200 // Recursive call for nested values (e.g., nested objects or lists)
190- item .Value = ProcessValue (item .Value , false )
201+ item .Value = processValue (item .Value , false )
191202 newVal [i ] = item
192203 }
193204 return newVal
@@ -199,7 +210,7 @@ func ProcessValue(v any, isToolset bool) any {
199210 // Otherwise, recurse into list items (to catch nested objects)
200211 newVal := make ([]any , len (val ))
201212 for i := range val {
202- newVal [i ] = ProcessValue (val [i ], false )
213+ newVal [i ] = processValue (val [i ], false )
203214 }
204215 return newVal
205216 default :
@@ -287,7 +298,7 @@ func mergeToolsFiles(files ...ToolsFile) (ToolsFile, error) {
287298}
288299
289300// LoadAndMergeToolsFiles loads multiple YAML files and merges them
290- func LoadAndMergeToolsFiles (ctx context.Context , filePaths []string ) (ToolsFile , error ) {
301+ func ( p * ToolsFileParser ) LoadAndMergeToolsFiles (ctx context.Context , filePaths []string ) (ToolsFile , error ) {
291302 var toolsFiles []ToolsFile
292303
293304 for _ , filePath := range filePaths {
@@ -296,7 +307,7 @@ func LoadAndMergeToolsFiles(ctx context.Context, filePaths []string) (ToolsFile,
296307 return ToolsFile {}, fmt .Errorf ("unable to read tool file at %q: %w" , filePath , err )
297308 }
298309
299- toolsFile , err := parseToolsFile (ctx , buf )
310+ toolsFile , err := p . ParseToolsFile (ctx , buf )
300311 if err != nil {
301312 return ToolsFile {}, fmt .Errorf ("unable to parse tool file at %q: %w" , filePath , err )
302313 }
@@ -313,7 +324,7 @@ func LoadAndMergeToolsFiles(ctx context.Context, filePaths []string) (ToolsFile,
313324}
314325
315326// LoadAndMergeToolsFolder loads all YAML files from a directory and merges them
316- func LoadAndMergeToolsFolder (ctx context.Context , folderPath string ) (ToolsFile , error ) {
327+ func ( p * ToolsFileParser ) LoadAndMergeToolsFolder (ctx context.Context , folderPath string ) (ToolsFile , error ) {
317328 // Check if directory exists
318329 info , err := os .Stat (folderPath )
319330 if err != nil {
@@ -345,5 +356,5 @@ func LoadAndMergeToolsFolder(ctx context.Context, folderPath string) (ToolsFile,
345356 }
346357
347358 // Use existing LoadAndMergeToolsFiles function
348- return LoadAndMergeToolsFiles (ctx , allFiles )
359+ return p . LoadAndMergeToolsFiles (ctx , allFiles )
349360}
0 commit comments