Skip to content

Commit 4dce299

Browse files
committed
feat: add toggle functionality for enabling/disabling all global MCP servers with configuration reload + Tests
1 parent 305185c commit 4dce299

File tree

2 files changed

+113
-6
lines changed

2 files changed

+113
-6
lines changed

src/services/mcp/McpHub.ts

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -941,20 +941,26 @@ export class McpHub {
941941

942942
// Update the connection object
943943
if (connection) {
944-
try {
945-
connection.server.disabled = disabled
944+
const wasDisabled = connection.server.disabled
945+
connection.server.disabled = disabled
946+
947+
// When the server is activated, reload the configuration
948+
if (wasDisabled && !disabled) {
949+
await this.initializeMcpServers(serverSource)
950+
}
946951

947-
// Only refresh capabilities if connected
948-
if (connection.server.status === "connected") {
952+
// Only refresh capabilities if connected
953+
if (connection.server.status === "connected") {
954+
try {
949955
connection.server.tools = await this.fetchToolsList(serverName, serverSource)
950956
connection.server.resources = await this.fetchResourcesList(serverName, serverSource)
951957
connection.server.resourceTemplates = await this.fetchResourceTemplatesList(
952958
serverName,
953959
serverSource,
954960
)
961+
} catch (error) {
962+
console.error(`Failed to refresh capabilities for ${serverName}:`, error)
955963
}
956-
} catch (error) {
957-
console.error(`Failed to refresh capabilities for ${serverName}:`, error)
958964
}
959965
}
960966

@@ -1287,4 +1293,33 @@ export class McpHub {
12871293
}
12881294
this.disposables.forEach((d) => d.dispose())
12891295
}
1296+
1297+
/**
1298+
* Enables or disables all global MCP servers at once.
1299+
* When activated, the configuration is reloaded.
1300+
* @param disabled true = disable all, false = enable all
1301+
*/
1302+
public async toggleAllServersDisabled(disabled: boolean): Promise<void> {
1303+
// Collect all global server names
1304+
const globalConnections = this.connections.filter(
1305+
(conn) => conn.server.source === "global" || !conn.server.source,
1306+
)
1307+
const serverNames = globalConnections.map((conn) => conn.server.name)
1308+
1309+
// Set the Disabled flag for all serversv
1310+
for (const name of serverNames) {
1311+
await this.updateServerConfig(name, { disabled }, "global")
1312+
const conn = this.findConnection(name, "global")
1313+
if (conn) {
1314+
conn.server.disabled = disabled
1315+
}
1316+
}
1317+
1318+
// If activated, reload configuration
1319+
if (!disabled) {
1320+
await this.initializeMcpServers("global")
1321+
}
1322+
1323+
await this.notifyWebviewOfServerChanges()
1324+
}
12901325
}

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

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,5 +560,77 @@ describe("McpHub", () => {
560560
)
561561
})
562562
})
563+
describe("toggleServerDisabled (Configuration reload)", () => {
564+
it("should reload configuration when enabling a server (calls initializeMcpServers)", async () => {
565+
const mockConfig: any = {
566+
mcpServers: {
567+
"test-server": {
568+
type: "stdio",
569+
command: "node",
570+
args: ["test.js"],
571+
disabled: true,
572+
},
573+
},
574+
}
575+
576+
;(fs.readFile as jest.Mock).mockResolvedValueOnce(JSON.stringify(mockConfig))
577+
578+
mcpHub.connections = [
579+
{
580+
server: {
581+
name: "test-server",
582+
config: JSON.stringify(mockConfig.mcpServers["test-server"]),
583+
status: "connected",
584+
disabled: true,
585+
},
586+
client: { request: jest.fn() },
587+
transport: { close: jest.fn() },
588+
} as any,
589+
]
590+
591+
const spy = jest.spyOn(mcpHub as any, "initializeMcpServers").mockResolvedValue(undefined)
592+
593+
await mcpHub.toggleServerDisabled("test-server", false)
594+
// Expectation: initializeMcpServers was called
595+
expect(spy).toHaveBeenCalledWith("global")
596+
spy.mockRestore()
597+
})
598+
})
599+
describe("toggleAllServersDisabled (global enable/disable)", () => {
600+
it("should reload configuration when globally enabling all servers (calls initializeMcpServers)", async () => {
601+
// Two global servers, both disabled
602+
mcpHub.connections = [
603+
{
604+
server: {
605+
name: "server1",
606+
config: JSON.stringify({ type: "stdio", command: "node", args: ["a.js"], disabled: true }),
607+
status: "disconnected",
608+
disabled: true,
609+
source: "global",
610+
},
611+
client: { request: jest.fn() },
612+
transport: { close: jest.fn() },
613+
} as any,
614+
{
615+
server: {
616+
name: "server2",
617+
config: JSON.stringify({ type: "stdio", command: "node", args: ["b.js"], disabled: true }),
618+
status: "disconnected",
619+
disabled: true,
620+
source: "global",
621+
},
622+
client: { request: jest.fn() },
623+
transport: { close: jest.fn() },
624+
} as any,
625+
]
626+
627+
const spy = jest.spyOn(mcpHub as any, "initializeMcpServers").mockResolvedValue(undefined)
628+
629+
await mcpHub.toggleAllServersDisabled(false) // actiate global
630+
631+
expect(spy).toHaveBeenCalledWith("global")
632+
spy.mockRestore()
633+
})
634+
})
563635
})
564636
})

0 commit comments

Comments
 (0)