@@ -12,6 +12,7 @@ import (
1212
1313 "github.com/azure/azure-dev/cli/azd/pkg/azdext"
1414 "github.com/jongio/azd-core/azdextutil"
15+ "github.com/jongio/azd-core/keyvault"
1516 "github.com/jongio/azd-core/security"
1617 "github.com/jongio/azd-core/shellutil"
1718 "github.com/jongio/azd-exec/cli/src/internal/version"
@@ -176,7 +177,10 @@ func handleExecScript(ctx context.Context, args azdext.ToolArgs) (*mcp.CallToolR
176177
177178 cmdArgs := buildShellArgs (shell , validPath , false , scriptArgs )
178179 cmd := exec .CommandContext (execCtx , cmdArgs [0 ], cmdArgs [1 :]... )
179- cmd .Env = os .Environ ()
180+
181+ // Resolve Key Vault references in environment variables, matching the
182+ // CLI execution path behavior. Continue on error (best-effort).
183+ cmd .Env = prepareEnvironmentForMCP (ctx )
180184
181185 var stdout , stderr bytes.Buffer
182186 cmd .Stdout = & stdout
@@ -214,7 +218,10 @@ func handleExecInline(ctx context.Context, args azdext.ToolArgs) (*mcp.CallToolR
214218
215219 cmdArgs := buildShellArgs (shell , command , true , nil )
216220 cmd := exec .CommandContext (execCtx , cmdArgs [0 ], cmdArgs [1 :]... )
217- cmd .Env = os .Environ ()
221+
222+ // Resolve Key Vault references in environment variables, matching the
223+ // CLI execution path behavior. Continue on error (best-effort).
224+ cmd .Env = prepareEnvironmentForMCP (ctx )
218225
219226 var stdout , stderr bytes.Buffer
220227 cmd .Stdout = & stdout
@@ -283,8 +290,13 @@ func handleGetEnvironment(_ context.Context, _ azdext.ToolArgs) (*mcp.CallToolRe
283290 continue
284291 }
285292
286- // Exclude known secret-bearing variable names
287- secretPatterns := []string {"SECRET" , "PASSWORD" , "KEY" , "TOKEN" , "CREDENTIAL" , "CERTIFICATE" , "CONNECTION_STRING" , "CONNSTR" }
293+ // Exclude known secret-bearing variable names.
294+ // This denylist covers common Azure, cloud, and application secret patterns.
295+ secretPatterns := []string {
296+ "SECRET" , "PASSWORD" , "KEY" , "TOKEN" , "CREDENTIAL" , "CERTIFICATE" ,
297+ "CONNECTION_STRING" , "CONNSTR" , "PAT" , "SAS" , "SIGNING" ,
298+ "PRIVATE" , "PASSPHRASE" , "AUTH" ,
299+ }
288300 isSecret := false
289301 upperName := strings .ToUpper (name )
290302 for _ , pattern := range secretPatterns {
@@ -306,6 +318,41 @@ func handleGetEnvironment(_ context.Context, _ azdext.ToolArgs) (*mcp.CallToolRe
306318
307319// --- Helpers ---
308320
321+ // prepareEnvironmentForMCP resolves Key Vault references in environment variables.
322+ // This mirrors the CLI execution path (executor.prepareEnvironment) to ensure
323+ // consistent behavior between CLI and MCP invocations. Operates in best-effort
324+ // mode: if resolution fails, the original environment is returned unchanged.
325+ func prepareEnvironmentForMCP (ctx context.Context ) []string {
326+ envVars := os .Environ ()
327+
328+ // Quick check: skip resolver setup if no Key Vault references are present.
329+ hasRef := false
330+ for _ , envVar := range envVars {
331+ if parts := strings .SplitN (envVar , "=" , 2 ); len (parts ) == 2 && keyvault .IsKeyVaultReference (parts [1 ]) {
332+ hasRef = true
333+ break
334+ }
335+ }
336+ if ! hasRef {
337+ return envVars
338+ }
339+
340+ resolver , err := keyvault .NewKeyVaultResolver ()
341+ if err != nil {
342+ // Cannot create resolver — fall back to raw environment.
343+ fmt .Fprintf (os .Stderr , "Warning: failed to create Key Vault resolver: %v\n " , err )
344+ return envVars
345+ }
346+
347+ resolved , _ , err := resolver .ResolveEnvironmentVariables (ctx , envVars , keyvault.ResolveEnvironmentOptions {StopOnError : false })
348+ if err != nil {
349+ fmt .Fprintf (os .Stderr , "Warning: Key Vault resolution error: %v\n " , err )
350+ return envVars
351+ }
352+
353+ return resolved
354+ }
355+
309356type execResult struct {
310357 Stdout string `json:"stdout"`
311358 Stderr string `json:"stderr"`
0 commit comments