Skip to content

Commit e17ec47

Browse files
committed
Fix env variables for MCP Gateway
Signed-off-by: David Gageot <david.gageot@docker.com>
1 parent 20b398a commit e17ec47

4 files changed

Lines changed: 82 additions & 36 deletions

File tree

pkg/config/gather.go

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"os"
78
"sort"
89
"strings"
910

@@ -85,47 +86,41 @@ func GatherEnvVarsForTools(ctx context.Context, cfg *latest.Config) ([]string, e
8586
requiredEnv := map[string]bool{}
8687
var errs []error
8788

88-
for _, ref := range gatherMCPServerReferences(cfg) {
89-
mcpServerName := gateway.ParseServerRef(ref)
90-
91-
secrets, err := gateway.RequiredEnvVars(ctx, mcpServerName)
92-
if err != nil {
93-
errs = append(errs, fmt.Errorf("reading which secrets the MCP server needs for %s: %w", ref, err))
94-
continue
95-
}
96-
97-
for _, secret := range secrets {
98-
requiredEnv[secret.Env] = true
99-
}
100-
}
101-
102-
if len(errs) > 0 {
103-
return mcpToSortedList(requiredEnv), fmt.Errorf("tool env preflight: %w", errors.Join(errs...))
104-
}
105-
return mcpToSortedList(requiredEnv), nil
106-
}
107-
108-
func gatherMCPServerReferences(cfg *latest.Config) []string {
109-
servers := map[string]bool{}
110-
11189
for i := range cfg.Agents {
11290
agent := cfg.Agents[i]
91+
11392
for j := range agent.Toolsets {
11493
toolSet := agent.Toolsets[j]
94+
ref := toolSet.Ref
95+
if toolSet.Type != "mcp" || ref == "" {
96+
continue
97+
}
11598

116-
if toolSet.Type == "mcp" && toolSet.Ref != "" {
117-
servers[toolSet.Ref] = true
99+
mcpServerName := gateway.ParseServerRef(ref)
100+
secrets, err := gateway.RequiredEnvVars(ctx, mcpServerName)
101+
if err != nil {
102+
errs = append(errs, fmt.Errorf("reading which secrets the MCP server needs for %s: %w", ref, err))
103+
continue
104+
}
105+
106+
for _, secret := range secrets {
107+
value, ok := toolSet.Env[secret.Env]
108+
if !ok {
109+
requiredEnv[secret.Env] = true
110+
} else {
111+
os.Expand(value, func(name string) string {
112+
requiredEnv[name] = true
113+
return ""
114+
})
115+
}
118116
}
119117
}
120118
}
121119

122-
var list []string
123-
for e := range servers {
124-
list = append(list, e)
120+
if len(errs) > 0 {
121+
return mcpToSortedList(requiredEnv), fmt.Errorf("tool env preflight: %w", errors.Join(errs...))
125122
}
126-
sort.Strings(list)
127-
128-
return list
123+
return mcpToSortedList(requiredEnv), nil
129124
}
130125

131126
func mcpToSortedList(requiredEnv map[string]bool) []string {

pkg/environment/env.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package environment
33
import (
44
"context"
55
"os"
6+
"strings"
67
)
78

89
// OsEnvProvider provides access to the operating system's environment variables.
@@ -16,22 +17,44 @@ func (p *OsEnvProvider) Get(_ context.Context, name string) string {
1617
return os.Getenv(name)
1718
}
1819

19-
type EnvFilesProviders struct {
20+
// EnvListProvider provides access a list of environment variables.
21+
type EnvListProvider struct {
22+
env []string
23+
}
24+
25+
func NewEnvListProvider(env []string) *EnvListProvider {
26+
return &EnvListProvider{
27+
env: env,
28+
}
29+
}
30+
31+
func (p *EnvListProvider) Get(_ context.Context, name string) string {
32+
for _, e := range p.env {
33+
n, v, ok := strings.Cut(e, "=")
34+
if ok && n == name {
35+
return v
36+
}
37+
}
38+
return ""
39+
}
40+
41+
// EnvFilesProvider provides access env files.
42+
type EnvFilesProvider struct {
2043
values []KeyValuePair
2144
}
2245

23-
func NewEnvFilesProvider(absEnvFiles []string) (*EnvFilesProviders, error) {
46+
func NewEnvFilesProvider(absEnvFiles []string) (*EnvFilesProvider, error) {
2447
values, err := ReadEnvFiles(absEnvFiles)
2548
if err != nil {
2649
return nil, err
2750
}
2851

29-
return &EnvFilesProviders{
52+
return &EnvFilesProvider{
3053
values: values,
3154
}, nil
3255
}
3356

34-
func (p *EnvFilesProviders) Get(_ context.Context, name string) string {
57+
func (p *EnvFilesProvider) Get(_ context.Context, name string) string {
3558
for _, kv := range p.values {
3659
if kv.Key == name {
3760
return kv.Value

pkg/environment/env_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,21 @@ func TestOsEnvProvider(t *testing.T) {
2121
value = provider.Get(t.Context(), "NOT_FOUND")
2222
assert.Empty(t, value)
2323
}
24+
25+
func TestNewEnvListProvider(t *testing.T) {
26+
t.Parallel()
27+
28+
provider := NewEnvListProvider([]string{
29+
"TEST1=VALUE1",
30+
"TEST2=VALUE2",
31+
})
32+
33+
value := provider.Get(t.Context(), "TEST1")
34+
assert.Equal(t, "VALUE1", value)
35+
36+
value = provider.Get(t.Context(), "TEST2")
37+
assert.Equal(t, "VALUE2", value)
38+
39+
value = provider.Get(t.Context(), "NOT_FOUND")
40+
assert.Empty(t, value)
41+
}

pkg/teamloader/registry.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,17 @@ func createMCPTool(ctx context.Context, toolset latest.Toolset, _ string, runCon
198198
return mcp.NewRemoteToolset(toolset.Name, serverSpec.Remote.URL, serverSpec.Remote.TransportType, nil), nil
199199
}
200200

201-
return mcp.NewGatewayToolset(ctx, toolset.Name, mcpServerName, toolset.Config, runConfig.EnvProvider(), runConfig.WorkingDir)
201+
env, err := environment.ExpandAll(ctx, environment.ToValues(toolset.Env), runConfig.EnvProvider())
202+
if err != nil {
203+
return nil, fmt.Errorf("failed to expand the tool's environment variables: %w", err)
204+
}
205+
206+
envProvider := environment.NewMultiProvider(
207+
environment.NewEnvListProvider(env),
208+
runConfig.EnvProvider(),
209+
)
210+
211+
return mcp.NewGatewayToolset(ctx, toolset.Name, mcpServerName, toolset.Config, envProvider, runConfig.WorkingDir)
202212
}
203213

204214
if toolset.Command != "" {

0 commit comments

Comments
 (0)