Skip to content

Commit a5ed497

Browse files
illumeashu8912
andcommitted
app: MCPClient: MCPSettings: Add setupIpcHandlers and ipc methods
Added these ipc methods: mcp-execute-tool mcp-get-status mcp-reset-client mcp-update-config mcp-get-config mcp-get-tools-config mcp-update-tools-config mcp-set-tool-enabled mcp-get-tool-stats mcp-cluster-change These will be used via Electron ipc from the frontend/. Co-Authored-By: Ashu Ghildiyal <aghildiyal@microsoft.com>
1 parent eb30409 commit a5ed497

File tree

2 files changed

+262
-4
lines changed

2 files changed

+262
-4
lines changed

app/electron/mcp/MCPClient.ts

Lines changed: 261 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,22 @@
1616

1717
import type { DynamicStructuredTool } from '@langchain/core/dist/tools/index';
1818
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
19-
import { type BrowserWindow, dialog } from 'electron';
20-
import { hasClusterDependentServers, makeMcpServersFromSettings } from './MCPSettings';
21-
import { MCPToolStateStore, parseServerNameToolName, validateToolArgs } from './MCPToolStateStore';
19+
import { type BrowserWindow, dialog, ipcMain } from 'electron';
20+
import {
21+
hasClusterDependentServers,
22+
loadMCPSettings,
23+
makeMcpServersFromSettings,
24+
MCPSettings,
25+
saveMCPSettings,
26+
showSettingsChangeDialog,
27+
} from './MCPSettings';
28+
import {
29+
MCPToolsConfig,
30+
MCPToolStateStore,
31+
parseServerNameToolName,
32+
showToolsConfigConfirmationDialog,
33+
validateToolArgs,
34+
} from './MCPToolStateStore';
2235

2336
const DEBUG = true;
2437

@@ -64,6 +77,7 @@ export default class MCPClient {
6477
constructor(configPath: string, settingsPath: string) {
6578
this.configPath = configPath;
6679
this.settingsPath = settingsPath;
80+
this.setupIpcHandlers();
6781
}
6882

6983
/**
@@ -306,6 +320,250 @@ export default class MCPClient {
306320
};
307321
}
308322
}
323+
324+
private async mcpGetStatus() {
325+
return {
326+
isInitialized: this.isInitialized,
327+
hasClient: this.client !== null,
328+
};
329+
}
330+
331+
private async mcpResetClient() {
332+
try {
333+
if (!this.mainWindow) {
334+
throw new Error('Main window not set for MCP client');
335+
}
336+
// Show confirmation dialog
337+
const userConfirmed = await showConfirmationDialog(
338+
this.mainWindow,
339+
'MCP Client Reset',
340+
'The application wants to reset the MCP client. This will restart all MCP server connections.',
341+
'Reset MCP client'
342+
);
343+
344+
if (!userConfirmed) {
345+
return {
346+
success: false,
347+
error: 'User cancelled the operation',
348+
};
349+
}
350+
351+
console.log('Resetting MCP client...');
352+
353+
if (this.client) {
354+
// If the client has a close/dispose method, call it
355+
if (typeof (this.client as any).close === 'function') {
356+
await (this.client as any).close();
357+
}
358+
}
359+
360+
this.client = null;
361+
this.isInitialized = false;
362+
this.initializationPromise = null;
363+
364+
// Re-initialize
365+
await this.initializeClient();
366+
367+
return { success: true };
368+
} catch (error) {
369+
console.error('Error resetting MCP client:', error);
370+
return {
371+
success: false,
372+
error: error instanceof Error ? error.message : 'Unknown error',
373+
};
374+
}
375+
}
376+
377+
private async mcpUpdateConfig(mcpSettings: MCPSettings) {
378+
try {
379+
if (!this.mainWindow) {
380+
throw new Error('Main window not set for MCP client');
381+
}
382+
// Get current configuration for comparison
383+
const currentSettings = loadMCPSettings(this.settingsPath);
384+
console.log('Requested MCP configuration update:', mcpSettings);
385+
// Show detailed confirmation dialog with changes
386+
const userConfirmed = await showSettingsChangeDialog(
387+
this.mainWindow,
388+
currentSettings,
389+
mcpSettings
390+
);
391+
392+
if (!userConfirmed) {
393+
return {
394+
success: false,
395+
error: 'User cancelled the configuration update',
396+
};
397+
}
398+
399+
console.log('Updating MCP configuration with user confirmation...');
400+
saveMCPSettings(this.settingsPath, mcpSettings);
401+
402+
// Reset and reinitialize client with new config
403+
if (this.client && typeof this.client.close === 'function') {
404+
await this.client.close();
405+
}
406+
this.client = null;
407+
this.isInitialized = false;
408+
this.initializationPromise = null;
409+
410+
// Re-initialize with new config
411+
await this.initializeClient();
412+
413+
console.log('MCP configuration updated successfully');
414+
return { success: true };
415+
} catch (error) {
416+
console.error('Error updating MCP configuration:', error);
417+
return {
418+
success: false,
419+
error: error instanceof Error ? error.message : 'Unknown error',
420+
};
421+
}
422+
}
423+
424+
private async mcpGetConfig() {
425+
try {
426+
const currentSettings = loadMCPSettings(this.settingsPath);
427+
428+
return {
429+
success: true,
430+
config: currentSettings || { enabled: false, servers: [] },
431+
};
432+
} catch (error) {
433+
console.error('Error getting MCP configuration:', error);
434+
return {
435+
success: false,
436+
error: error instanceof Error ? error.message : 'Unknown error',
437+
config: { enabled: false, servers: [] },
438+
};
439+
}
440+
}
441+
442+
private async mcpGetToolsConfig() {
443+
try {
444+
const toolsConfig = this.mcpToolState?.getConfig();
445+
return {
446+
success: true,
447+
config: toolsConfig,
448+
};
449+
} catch (error) {
450+
console.error('Error getting MCP tools configuration:', error);
451+
return {
452+
success: false,
453+
error: error instanceof Error ? error.message : 'Unknown error',
454+
config: {},
455+
};
456+
}
457+
}
458+
459+
private async mcpUpdateToolsConfig(toolsConfig: MCPToolsConfig) {
460+
console.log('Requested MCP tools configuration update:', toolsConfig);
461+
try {
462+
if (!this.mainWindow) {
463+
throw new Error('Main window not set for MCP client');
464+
}
465+
// Show confirmation dialog with detailed changes
466+
const currentToolsConfig = this.mcpToolState?.getConfig() || {};
467+
const userConfirmed = await showToolsConfigConfirmationDialog(
468+
this.mainWindow,
469+
currentToolsConfig,
470+
toolsConfig
471+
);
472+
473+
if (!userConfirmed) {
474+
return {
475+
success: false,
476+
error: 'User cancelled the operation',
477+
};
478+
}
479+
480+
this.mcpToolState?.setConfig(toolsConfig);
481+
return { success: true };
482+
} catch (error) {
483+
console.error('Error updating MCP tools configuration:', error);
484+
return {
485+
success: false,
486+
error: error instanceof Error ? error.message : 'Unknown error',
487+
};
488+
}
489+
}
490+
491+
private async mcpSetToolEnabled(serverName: string, toolName: string, enabled: boolean) {
492+
try {
493+
this.mcpToolState?.setToolEnabled(serverName, toolName, enabled);
494+
return { success: true };
495+
} catch (error) {
496+
console.error('Error setting tool enabled state:', error);
497+
return {
498+
success: false,
499+
error: error instanceof Error ? error.message : 'Unknown error',
500+
};
501+
}
502+
}
503+
504+
private async mcpGetToolStats(serverName: string, toolName: string) {
505+
try {
506+
const stats = this.mcpToolState?.getToolStats(serverName, toolName);
507+
return {
508+
success: true,
509+
stats,
510+
};
511+
} catch (error) {
512+
console.error('Error getting tool statistics:', error);
513+
return {
514+
success: false,
515+
error: error instanceof Error ? error.message : 'Unknown error',
516+
stats: null,
517+
};
518+
}
519+
}
520+
521+
private async mcpClusterChange(cluster: string | null) {
522+
try {
523+
console.log('Received cluster change event:', cluster);
524+
if (cluster !== null) {
525+
// @todo: support multiple clusters
526+
await this.handleClustersChange([cluster]);
527+
}
528+
return {
529+
success: true,
530+
};
531+
} catch (error) {
532+
console.error('Error handling cluster change:', error);
533+
return {
534+
success: false,
535+
error: error instanceof Error ? error.message : 'Unknown error',
536+
};
537+
}
538+
}
539+
540+
/**
541+
* Setup IPC handlers for MCP operations.
542+
*/
543+
private setupIpcHandlers(): void {
544+
ipcMain?.handle('mcp-execute-tool', async (event, { toolName, args, toolCallId }) =>
545+
this.mcpExecuteTool(toolName, args, toolCallId)
546+
);
547+
ipcMain?.handle('mcp-get-status', async () => this.mcpGetStatus());
548+
ipcMain?.handle('mcp-reset-client', async () => this.mcpResetClient());
549+
ipcMain?.handle('mcp-update-config', async (event, mcpSettings: MCPSettings) =>
550+
this.mcpUpdateConfig(mcpSettings)
551+
);
552+
ipcMain?.handle('mcp-get-config', async () => this.mcpGetConfig());
553+
ipcMain?.handle('mcp-get-tools-config', async () => this.mcpGetToolsConfig());
554+
ipcMain?.handle('mcp-update-tools-config', async (event, toolsConfig: MCPToolsConfig) =>
555+
this.mcpUpdateToolsConfig(toolsConfig)
556+
);
557+
ipcMain?.handle('mcp-set-tool-enabled', async (event, { serverName, toolName, enabled }) =>
558+
this.mcpSetToolEnabled(serverName, toolName, enabled)
559+
);
560+
ipcMain?.handle('mcp-get-tool-stats', async (event, { serverName, toolName }) =>
561+
this.mcpGetToolStats(serverName, toolName)
562+
);
563+
ipcMain?.handle('mcp-cluster-change', async (event, { cluster }) =>
564+
this.mcpClusterChange(cluster)
565+
);
566+
}
309567
}
310568

311569
/**

app/electron/mcp/MCPSettings.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { loadSettings, saveSettings } from '../settings';
2222

2323
const DEBUG = true;
2424

25-
interface MCPSettings {
25+
export interface MCPSettings {
2626
/**
2727
* Whether MCP is enabled or not
2828
*/

0 commit comments

Comments
 (0)