Skip to content

Commit 467c52f

Browse files
authored
refactor(mcp): use getDefaultEnvironment for stdio client transport (#4259)
- Replace manual PATH and HOME env var handling with getDefaultEnvironment() - Improves consistency and reliability of MCP client environment setup - Leverages SDK's built-in environment configuration
1 parent 815a0fb commit 467c52f

File tree

2 files changed

+126
-6
lines changed

2 files changed

+126
-6
lines changed

src/services/mcp/McpHub.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
2-
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
2+
import { StdioClientTransport, getDefaultEnvironment } from "@modelcontextprotocol/sdk/client/stdio.js"
33
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
44
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
55
import ReconnectingEventSource from "reconnecting-eventsource"
@@ -483,9 +483,8 @@ export class McpHub {
483483
args: configInjected.args,
484484
cwd: configInjected.cwd,
485485
env: {
486+
...getDefaultEnvironment(),
486487
...(configInjected.env || {}),
487-
...(process.env.PATH ? { PATH: process.env.PATH } : {}),
488-
...(process.env.HOME ? { HOME: process.env.HOME } : {}),
489488
},
490489
stderr: "pipe",
491490
})

src/services/mcp/__tests__/McpHub.test.ts

Lines changed: 124 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,20 @@ describe("McpHub", () => {
128128
// Mock reading initial config
129129
;(fs.readFile as jest.Mock).mockResolvedValueOnce(JSON.stringify(mockConfig))
130130

131+
// Set up mock connection without alwaysAllow
132+
const mockConnection: McpConnection = {
133+
server: {
134+
name: "test-server",
135+
type: "stdio",
136+
command: "node",
137+
args: ["test.js"],
138+
source: "global",
139+
} as any,
140+
client: {} as any,
141+
transport: {} as any,
142+
}
143+
mcpHub.connections = [mockConnection]
144+
131145
await mcpHub.toggleToolAlwaysAllow("test-server", "global", "new-tool", true)
132146

133147
// Verify the config was updated correctly
@@ -162,6 +176,21 @@ describe("McpHub", () => {
162176
// Mock reading initial config
163177
;(fs.readFile as jest.Mock).mockResolvedValueOnce(JSON.stringify(mockConfig))
164178

179+
// Set up mock connection
180+
const mockConnection: McpConnection = {
181+
server: {
182+
name: "test-server",
183+
type: "stdio",
184+
command: "node",
185+
args: ["test.js"],
186+
alwaysAllow: ["existing-tool"],
187+
source: "global",
188+
} as any,
189+
client: {} as any,
190+
transport: {} as any,
191+
}
192+
mcpHub.connections = [mockConnection]
193+
165194
await mcpHub.toggleToolAlwaysAllow("test-server", "global", "existing-tool", false)
166195

167196
// Verify the config was updated correctly
@@ -195,6 +224,21 @@ describe("McpHub", () => {
195224
// Mock reading initial config
196225
;(fs.readFile as jest.Mock).mockResolvedValueOnce(JSON.stringify(mockConfig))
197226

227+
// Set up mock connection
228+
const mockConnection: McpConnection = {
229+
server: {
230+
name: "test-server",
231+
type: "stdio",
232+
command: "node",
233+
args: ["test.js"],
234+
alwaysAllow: [],
235+
source: "global",
236+
} as any,
237+
client: {} as any,
238+
transport: {} as any,
239+
}
240+
mcpHub.connections = [mockConnection]
241+
198242
await mcpHub.toggleToolAlwaysAllow("test-server", "global", "new-tool", true)
199243

200244
// Verify the config was updated with initialized alwaysAllow
@@ -228,6 +272,21 @@ describe("McpHub", () => {
228272
// Mock reading initial config
229273
;(fs.readFile as jest.Mock).mockResolvedValueOnce(JSON.stringify(mockConfig))
230274

275+
// Set up mock connection
276+
const mockConnection: McpConnection = {
277+
server: {
278+
name: "test-server",
279+
type: "stdio",
280+
command: "node",
281+
args: ["test.js"],
282+
disabled: false,
283+
source: "global",
284+
} as any,
285+
client: {} as any,
286+
transport: {} as any,
287+
}
288+
mcpHub.connections = [mockConnection]
289+
231290
await mcpHub.toggleServerDisabled("test-server", true)
232291

233292
// Verify the config was updated correctly
@@ -445,6 +504,21 @@ describe("McpHub", () => {
445504
// Mock reading initial config
446505
;(fs.readFile as jest.Mock).mockResolvedValueOnce(JSON.stringify(mockConfig))
447506

507+
// Set up mock connection
508+
const mockConnection: McpConnection = {
509+
server: {
510+
name: "test-server",
511+
type: "stdio",
512+
command: "node",
513+
args: ["test.js"],
514+
timeout: 60,
515+
source: "global",
516+
} as any,
517+
client: {} as any,
518+
transport: {} as any,
519+
}
520+
mcpHub.connections = [mockConnection]
521+
448522
await mcpHub.updateServerTimeout("test-server", 120)
449523

450524
// Verify the config was updated correctly
@@ -475,14 +549,31 @@ describe("McpHub", () => {
475549
// Mock initial read
476550
;(fs.readFile as jest.Mock).mockResolvedValueOnce(JSON.stringify(mockConfig))
477551

552+
// Set up mock connection before updating
553+
const mockConnectionInitial: McpConnection = {
554+
server: {
555+
name: "test-server",
556+
type: "stdio",
557+
command: "node",
558+
args: ["test.js"],
559+
timeout: 60,
560+
source: "global",
561+
} as any,
562+
client: {
563+
request: jest.fn().mockResolvedValue({ content: [] }),
564+
} as any,
565+
transport: {} as any,
566+
}
567+
mcpHub.connections = [mockConnectionInitial]
568+
478569
// Update with invalid timeout
479570
await mcpHub.updateServerTimeout("test-server", 3601)
480571

481572
// Config is written
482573
expect(fs.writeFile).toHaveBeenCalled()
483574

484575
// Setup connection with invalid timeout
485-
const mockConnection: McpConnection = {
576+
const mockConnectionInvalid: McpConnection = {
486577
server: {
487578
name: "test-server",
488579
config: JSON.stringify({
@@ -499,13 +590,13 @@ describe("McpHub", () => {
499590
transport: {} as any,
500591
}
501592

502-
mcpHub.connections = [mockConnection]
593+
mcpHub.connections = [mockConnectionInvalid]
503594

504595
// Call tool - should use default timeout
505596
await mcpHub.callTool("test-server", "test-tool")
506597

507598
// Verify default timeout was used
508-
expect(mockConnection.client.request).toHaveBeenCalledWith(
599+
expect(mockConnectionInvalid.client.request).toHaveBeenCalledWith(
509600
expect.anything(),
510601
expect.anything(),
511602
expect.objectContaining({ timeout: 60000 }), // Default 60 seconds
@@ -526,6 +617,21 @@ describe("McpHub", () => {
526617

527618
;(fs.readFile as jest.Mock).mockResolvedValueOnce(JSON.stringify(mockConfig))
528619

620+
// Set up mock connection
621+
const mockConnection: McpConnection = {
622+
server: {
623+
name: "test-server",
624+
type: "stdio",
625+
command: "node",
626+
args: ["test.js"],
627+
timeout: 60,
628+
source: "global",
629+
} as any,
630+
client: {} as any,
631+
transport: {} as any,
632+
}
633+
mcpHub.connections = [mockConnection]
634+
529635
// Test valid timeout values
530636
const validTimeouts = [1, 60, 3600]
531637
for (const timeout of validTimeouts) {
@@ -550,6 +656,21 @@ describe("McpHub", () => {
550656

551657
;(fs.readFile as jest.Mock).mockResolvedValueOnce(JSON.stringify(mockConfig))
552658

659+
// Set up mock connection
660+
const mockConnection: McpConnection = {
661+
server: {
662+
name: "test-server",
663+
type: "stdio",
664+
command: "node",
665+
args: ["test.js"],
666+
timeout: 60,
667+
source: "global",
668+
} as any,
669+
client: {} as any,
670+
transport: {} as any,
671+
}
672+
mcpHub.connections = [mockConnection]
673+
553674
await mcpHub.updateServerTimeout("test-server", 120)
554675

555676
expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith(

0 commit comments

Comments
 (0)