Skip to content

Add InheritEnvironmentVariables to StdioClientTransportOptions#1563

Open
halter73 wants to merge 8 commits intomainfrom
halter73/stdio-env-inherit-option
Open

Add InheritEnvironmentVariables to StdioClientTransportOptions#1563
halter73 wants to merge 8 commits intomainfrom
halter73/stdio-env-inherit-option

Conversation

@halter73
Copy link
Copy Markdown
Contributor

@halter73 halter73 commented May 6, 2026

Summary

Introduces a new bool InheritEnvironmentVariables { get; set; } = true property on StdioClientTransportOptions that controls whether the child server process inherits the current process's environment variables.

Motivation

Previously, EnvironmentVariables only augmented/overwrote inherited vars — there was no way to start the server with a clean environment. Retconning the dictionary to mean "only these vars" would be breaking.

Behavior

InheritEnvironmentVariables EnvironmentVariables Result
true (default) null Child inherits all parent env vars (unchanged)
true (default) { "X": "y" } Child inherits all + X=y on top
false null Child starts with empty environment
false { "PATH": "...", "API_KEY": "..." } Child only sees the explicitly provided vars

When false, startInfo.Environment.Clear() is called before any EnvironmentVariables entries are applied.

Security / Compatibility note

The docs and XML comments explain both sides:

  • Security risk (inheriting): Credentials like AWS_SECRET_ACCESS_KEY, GITHUB_TOKEN, OPENAI_API_KEY automatically flow into the child process.
  • Compatibility risk (disabling): PATH, HOME, DOTNET_ROOT, LD_LIBRARY_PATH, JAVA_HOME, proxy vars etc. are required by many tools — forgetting them causes the process to fail to start.

Changes

  • StdioClientTransportOptions.cs — new InheritEnvironmentVariables property with comprehensive XML docs
  • StdioClientTransport.cs — calls startInfo.Environment.Clear() when !InheritEnvironmentVariables
  • StdioClientTransportTests.cs — 3 new tests verifying inherit, block, and explicit-only scenarios
  • transports.md — new property in the options table + "Environment variable inheritance" section with code sample and [!WARNING] callout

halter73 and others added 2 commits May 5, 2026 22:34
Introduces a new bool property InheritEnvironmentVariables (default: true)
on StdioClientTransportOptions that controls whether the child server
process inherits the current process's environment variables.

When false, startInfo.Environment.Clear() is called before any
EnvironmentVariables entries are applied, giving the child process a
completely clean environment. This allows callers to prevent unintentional
leakage of credentials, tokens, and proxy settings into third-party or
untrusted MCP server processes.

The new property is backward-compatible: the default (true) preserves
the existing behavior of inheriting all parent env vars and then
layering EnvironmentVariables on top.

Three tests are added to StdioClientTransportTests:
- InheritEnvironmentVariables_DefaultTrue_ChildSeesParentEnvVars
- InheritEnvironmentVariables_False_ChildDoesNotSeeParentEnvVars
- InheritEnvironmentVariables_False_WithExplicitVars_ChildSeesOnlyExplicitVars

Documentation in transports.md is updated with:
- New property in the stdio options table
- A dedicated 'Environment variable inheritance' section with a code
  sample and a WARNING callout explaining both the security risk of
  inheriting (credential leakage) and the compatibility risk of
  disabling (PATH, HOME, DOTNET_ROOT etc. required by many tools).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Instead of calling Environment.SetEnvironmentVariable (which is process-global
and can cause race conditions with parallel tests), rely on PATH which is always
present in a real process environment as the 'known parent variable'.

For the no-inherit tests, use absolute shell paths (/bin/sh on Unix, full
cmd.exe path on Windows from SystemRoot) so the child can launch even with
a completely empty environment — no PATH needed.

Test 1: default inheritance → child sees PATH (no parent env mutation)
Test 2: InheritEnvironmentVariables=false → child does NOT see PATH
Test 3: InheritEnvironmentVariables=false + explicit var → PATH absent,
        explicit MCP_STDIO_TEST_EXPLICIT_VAR is present

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
halter73 and others added 6 commits May 5, 2026 23:08
…te paths

Use PATH (passed explicitly when InheritEnvironmentVariables=false) to find
cmd/sh rather than hardcoded absolute paths. Verify inheritance by checking
variables that are always present in a real process but deliberately omitted
from the explicit EnvironmentVariables dict: HOME (Unix) and USERNAME (Windows).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Both QuickstartClient and ChatWithTools now disable environment variable
inheritance and forward only the variables their server processes require:
PATH, HOME/USERPROFILE, APPDATA, LOCALAPPDATA, TEMP/TMPDIR for Node/npm;
plus DOTNET_ROOT and NUGET_PACKAGES for the dotnet case.

This prevents credentials, tokens, and other sensitive parent-process
variables from leaking into third-party MCP server processes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…se test

Both DefaultTrue and False tests now check HOME (Unix) / USERNAME (Windows)
so they form a symmetric pair asserting opposite outcomes on the same signal.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Returns a curated allowlist of env vars (PATH, HOME, system dirs, etc.)
safe to forward to child processes, aligned with the TypeScript and Python
MCP SDK defaults. Replaces the duplicated MinimalEnvironment() helpers in
the samples and updates transports.md to demonstrate the new API.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ocs and XML

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
OrdinalIgnoreCase on Windows to match ProcessStartInfo.Environment behavior,
Ordinal on Unix where env var names are case-sensitive.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tarekgh
Copy link
Copy Markdown

tarekgh commented May 6, 2026

Do we have an option to exclude specific environment variables? For example, could we inherit all variables via InheritEnvironmentVariables while explicitly excluding a subset? Alternatively, is this something that must be handled manually? I’m asking because this capability could help mitigate the security risk mentioned here.

| `Name` | Optional transport identifier for logging |

#### Environment variable inheritance

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to mention anything regarding Windows shell wrapping?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants