Skip to content

Commit

Permalink
Merge pull request #36 from modelcontextprotocol/justin/env-var-inher…
Browse files Browse the repository at this point in the history
…itance

Inherit environment variables deemed safe by default
  • Loading branch information
jspahrsummers authored Nov 5, 2024
2 parents bfb6ffc + 08b8940 commit 844d69d
Showing 1 changed file with 48 additions and 7 deletions.
55 changes: 48 additions & 7 deletions src/client/stdio.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ChildProcess, spawn } from "node:child_process";
import process from "node:process";
import { ReadBuffer, serializeMessage } from "../shared/stdio.js";
import { JSONRPCMessage } from "../types.js";
import { Transport } from "../shared/transport.js";
Expand All @@ -17,11 +18,55 @@ export type StdioServerParameters = {
/**
* The environment to use when spawning the process.
*
* The environment is NOT inherited from the parent process by default.
* If not specified, the result of getDefaultEnvironment() will be used.
*/
env?: object;
env?: Record<string, string>;
};

/**
* Environment variables to inherit by default, if an environment is not explicitly given.
*/
export const DEFAULT_INHERITED_ENV_VARS =
process.platform === "win32"
? [
"APPDATA",
"HOMEDRIVE",
"HOMEPATH",
"LOCALAPPDATA",
"PATH",
"PROCESSOR_ARCHITECTURE",
"SYSTEMDRIVE",
"SYSTEMROOT",
"TEMP",
"USERNAME",
"USERPROFILE",
]
: /* list inspired by the default env inheritance of sudo */
["HOME", "LOGNAME", "PATH", "SHELL", "TERM", "USER"];

/**
* Returns a default environment object including only environment variables deemed safe to inherit.
*/
export function getDefaultEnvironment(): Record<string, string> {
const env: Record<string, string> = {};

for (const key of DEFAULT_INHERITED_ENV_VARS) {
const value = process.env[key];
if (value === undefined) {
continue;
}

if (value.startsWith("()")) {
// Skip functions, which are a security risk.
continue;
}

env[key] = value;
}

return env;
}

/**
* Client transport for stdio: this will connect to a server by spawning a process and communicating with it over stdin/stdout.
*
Expand Down Expand Up @@ -56,11 +101,7 @@ export class StdioClientTransport implements Transport {
this._serverParams.command,
this._serverParams.args ?? [],
{
// The parent process may have sensitive secrets in its env, so don't inherit it automatically.
env:
this._serverParams.env === undefined
? {}
: { ...this._serverParams.env },
env: this._serverParams.env ?? getDefaultEnvironment(),
stdio: ["pipe", "pipe", "inherit"],
signal: this._abortController.signal,
},
Expand Down

0 comments on commit 844d69d

Please sign in to comment.