diff --git a/src/client/cross-spawn.test.ts b/src/client/cross-spawn.test.ts index 11e81bf6..98454a9a 100644 --- a/src/client/cross-spawn.test.ts +++ b/src/client/cross-spawn.test.ts @@ -1,4 +1,4 @@ -import { StdioClientTransport } from "./stdio.js"; +import { getDefaultEnvironment, StdioClientTransport } from "./stdio.js"; import spawn from "cross-spawn"; import { JSONRPCMessage } from "../types.js"; import { ChildProcess } from "node:child_process"; @@ -72,7 +72,10 @@ describe("StdioClientTransport using cross-spawn", () => { "test-command", [], expect.objectContaining({ - env: customEnv + env: { + ...customEnv, + ...getDefaultEnvironment() + } }) ); }); diff --git a/src/client/stdio.test.ts b/src/client/stdio.test.ts index e6ccb347..cc3731fb 100644 --- a/src/client/stdio.test.ts +++ b/src/client/stdio.test.ts @@ -1,10 +1,21 @@ import { JSONRPCMessage } from "../types.js"; -import { StdioClientTransport, StdioServerParameters } from "./stdio.js"; +import { StdioClientTransport, StdioServerParameters, DEFAULT_INHERITED_ENV_VARS, getDefaultEnvironment } from "./stdio.js"; const serverParameters: StdioServerParameters = { command: "/usr/bin/tee", }; + +let spawnEnv: Record | undefined; + +jest.mock('cross-spawn', () => { + const originalSpawn = jest.requireActual('cross-spawn'); + return jest.fn((command, args, options) => { + spawnEnv = options.env; + return originalSpawn(command, args, options); + }); +}); + test("should start then close cleanly", async () => { const client = new StdioClientTransport(serverParameters); client.onerror = (error) => { @@ -60,32 +71,51 @@ test("should read messages", async () => { await client.close(); }); -test("should work with actual node mcp server", async () => { - const client = new StdioClientTransport({ - command: "npx", - args: ["-y", "@wrtnlabs/calculator-mcp"], - }); - +test("should properly set default environment variables in spawned process", async () => { + const client = new StdioClientTransport(serverParameters); + await client.start(); await client.close(); + + // Get the default environment variables + const defaultEnv = getDefaultEnvironment(); + + // Verify that all default environment variables are present + for (const key of DEFAULT_INHERITED_ENV_VARS) { + if (process.env[key] && !process.env[key].startsWith("()")) { + expect(spawnEnv).toHaveProperty(key); + expect(spawnEnv![key]).toBe(process.env[key]); + expect(spawnEnv![key]).toBe(defaultEnv[key]); + } + } }); -test("should work with actual node mcp server and empty env", async () => { - const client = new StdioClientTransport({ - command: "npx", - args: ["-y", "@wrtnlabs/calculator-mcp"], - env: {}, - }); - await client.start(); - await client.close(); -}); +test("should override default environment variables with custom ones", async () => { + const customEnv = { + HOME: "/custom/home", + PATH: "/custom/path", + USER: "custom_user" + }; -test("should work with actual node mcp server and custom env", async () => { const client = new StdioClientTransport({ - command: "npx", - args: ["-y", "@wrtnlabs/calculator-mcp"], - env: {TEST_VAR: "test-value"}, + ...serverParameters, + env: customEnv }); + await client.start(); await client.close(); + + // Verify that custom environment variables override default ones + for (const [key, value] of Object.entries(customEnv)) { + expect(spawnEnv).toHaveProperty(key); + expect(spawnEnv![key]).toBe(value); + } + + // Verify that other default environment variables are still present + for (const key of DEFAULT_INHERITED_ENV_VARS) { + if (!(key in customEnv) && process.env[key] && !process.env[key].startsWith("()")) { + expect(spawnEnv).toHaveProperty(key); + expect(spawnEnv![key]).toBe(process.env[key]); + } + } });