mirror of
https://github.com/hanzoai/code.git
synced 2026-09-30 20:53:35 +00:00
Added toggle service to turn mcp servers on and off
This commit is contained in:
+23
-6
@@ -3,6 +3,7 @@ import { MCPConfigParseError, MCPServerEventParam, MCPServerObject, MCPServers }
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useAccessor } from '../util/services.js';
|
||||
import { IDisposable } from '../../../../../../../base/common/lifecycle.js';
|
||||
import { off } from 'process';
|
||||
|
||||
export interface Tool {
|
||||
/** Unique tool identifier */
|
||||
@@ -33,11 +34,29 @@ interface MCPServerProps {
|
||||
// MCP Server component
|
||||
const MCPServer = ({ name, server }: MCPServerProps) => {
|
||||
|
||||
const accessor = useAccessor();
|
||||
const mcpService = accessor.get('IMCPService');
|
||||
|
||||
const handleChangeEvent = (e: boolean) => {
|
||||
// Handle the change event
|
||||
mcpService.toggleServer(name, e);
|
||||
}
|
||||
|
||||
// Needs to be raw CSS because
|
||||
// Tailwind won't compile the colors
|
||||
// dynamically
|
||||
const serverStatusColorStyles = {
|
||||
success: { backgroundColor: '#10B981' }, // green-500 equivalent
|
||||
error: { backgroundColor: '#EF4444' }, // red-500 equivalent
|
||||
loading: { backgroundColor: '#F59E0B' }, // yellow-500 equivalent
|
||||
offline: { backgroundColor: '#6B7280' } // gray-500 equivalent
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="border-b border-gray-800 bg-gray-300/10 py-4 rounded-lg ">
|
||||
<div className="flex items-center mx-4">
|
||||
{/* Status indicator */}
|
||||
<div className={`w-2 h-2 rounded-full mr-2 ${server.status === 'success' ? 'bg-green-500' : server.status === 'error' ? 'bg-red-500' : 'bg-yellow-500'}`}></div>
|
||||
<div className={`w-2 h-2 rounded-full mr-2`} style={serverStatusColorStyles[server.status]}></div>
|
||||
|
||||
{/* Server name */}
|
||||
<div className="text-sm font-medium mr-2">{name}</div>
|
||||
@@ -47,9 +66,7 @@ const MCPServer = ({ name, server }: MCPServerProps) => {
|
||||
<VoidSwitch
|
||||
value={server.isOn}
|
||||
disabled={server.status === 'error'}
|
||||
onChange={() => {
|
||||
server.isOn = !server.isOn;
|
||||
}}
|
||||
onChange={handleChangeEvent}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -57,7 +74,7 @@ const MCPServer = ({ name, server }: MCPServerProps) => {
|
||||
{/* Tools section */}
|
||||
<div className="mt-1 mx-4">
|
||||
<div className="flex flex-wrap gap-2 max-h-32 overflow-y-auto pb-1">
|
||||
{server.tools.length > 0 ? (
|
||||
{server.isOn && server.tools.length > 0 ? (
|
||||
server.tools.map((tool) => (
|
||||
<span
|
||||
key={tool.name}
|
||||
@@ -74,7 +91,7 @@ const MCPServer = ({ name, server }: MCPServerProps) => {
|
||||
</div>
|
||||
|
||||
{/* Command display */}
|
||||
{server.command && (
|
||||
{server.isOn && server.command && (
|
||||
<div className="mt-2 mx-4">
|
||||
<div className="text-xs text-gray-400">Command:</div>
|
||||
<CommandDisplay command={server.command} />
|
||||
|
||||
@@ -24,6 +24,7 @@ export interface IMCPService {
|
||||
openMCPConfigFile(): Promise<void>;
|
||||
getMCPServers(): MCPServers;
|
||||
getAllToolsFormatted(): InternalToolInfo[];
|
||||
toggleServer(serverName: string, isOn: boolean): Promise<void>;
|
||||
onDidAddServer: Event<MCPServerEventAddParam>;
|
||||
onDidUpdateServer: Event<MCPServerEventUpdateParam>;
|
||||
onDidDeleteServer: Event<MCPServerEventDeleteParam>;
|
||||
@@ -215,7 +216,7 @@ class MCPService extends Disposable implements IMCPService {
|
||||
if (e.contains(mcpConfigUri)) {
|
||||
const mcpConfig = await this._parseMCPConfigFile();
|
||||
if (mcpConfig && mcpConfig.mcpServers) {
|
||||
// Call the setupServers method in the main process
|
||||
// Set up the server list
|
||||
this.channel.call('setupServers', mcpConfig)
|
||||
}
|
||||
}
|
||||
@@ -280,6 +281,10 @@ class MCPService extends Disposable implements IMCPService {
|
||||
return allTools;
|
||||
}
|
||||
|
||||
public async toggleServer(serverName: string, isOn: boolean): Promise<void> {
|
||||
this.channel.call('toggleServer', { serverName, isOn })
|
||||
}
|
||||
|
||||
// utility functions
|
||||
|
||||
private async _getMCPConfigPath(): Promise<URI> {
|
||||
|
||||
@@ -147,7 +147,7 @@ export interface MCPConfigParseError {
|
||||
export interface MCPServerObject {
|
||||
// Command-based server properties
|
||||
tools: Tool[],
|
||||
status: 'loading' | 'error' | 'success',
|
||||
status: 'loading' | 'error' | 'success' | 'offline',
|
||||
isOn: boolean,
|
||||
command?: string,
|
||||
error?: string,
|
||||
|
||||
@@ -77,7 +77,7 @@ export class MCPChannel implements IServerChannel {
|
||||
await this._callCloseAllServers()
|
||||
}
|
||||
else if (command === 'toggleServer') {
|
||||
// TODO: HANDLE THIS
|
||||
await this._handleToggleServer(params.serverName, params.isOn)
|
||||
}
|
||||
else if (command === 'callTool') {
|
||||
// TODO: HANDLE THIS
|
||||
@@ -179,6 +179,7 @@ export class MCPChannel implements IServerChannel {
|
||||
const deletePromises: Promise<MCPDeleteResponse>[] = deletedServers.map(async (serverName) => {
|
||||
const prevServer = this.clients[serverName]?.formattedServer;
|
||||
await this._callCloseServer(serverName)
|
||||
this._callRemoveServer(serverName)
|
||||
return {
|
||||
event: 'delete',
|
||||
prevServer,
|
||||
@@ -292,6 +293,7 @@ export class MCPChannel implements IServerChannel {
|
||||
private async _callCloseAllServers() {
|
||||
for (const serverName in this.clients) {
|
||||
await this._callCloseServer(serverName)
|
||||
this._callRemoveServer(serverName)
|
||||
}
|
||||
console.log('Closed all MCP servers');
|
||||
}
|
||||
@@ -302,21 +304,64 @@ export class MCPChannel implements IServerChannel {
|
||||
if (client) {
|
||||
await client.close()
|
||||
}
|
||||
delete this.clients[serverName]
|
||||
console.log(`Closed MCP server ${serverName}`);
|
||||
}
|
||||
}
|
||||
|
||||
private _callRemoveServer(serverName: string) {
|
||||
if (this.clients[serverName]) {
|
||||
delete this.clients[serverName]
|
||||
console.log(`Removed MCP server ${serverName}`);
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleToggleServer(serverName: string, isOn: boolean) {
|
||||
const prevServer = this.clients[serverName]?.formattedServer
|
||||
if (isOn) {
|
||||
// Handle turning on the server
|
||||
this.mcpEmitters.serverEvent.loading.fire(this._getLoadingServerObject(serverName, isOn))
|
||||
const formattedServer = await this._callSetupServer(this.clients[serverName].mcpConfig, serverName)
|
||||
this.mcpEmitters.serverEvent.update.fire({
|
||||
response: {
|
||||
event: 'update',
|
||||
name: serverName,
|
||||
newServer: formattedServer,
|
||||
prevServer: prevServer,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// Handle turning off the server
|
||||
this.mcpEmitters.serverEvent.loading.fire(this._getLoadingServerObject(serverName, isOn))
|
||||
this._callCloseServer(serverName)
|
||||
this.mcpEmitters.serverEvent.update.fire({
|
||||
response: {
|
||||
event: 'update',
|
||||
name: serverName,
|
||||
newServer: {
|
||||
status: 'offline',
|
||||
isOn,
|
||||
tools: [],
|
||||
command: '',
|
||||
// Explicitly set error to undefined
|
||||
// to reset the error state
|
||||
error: undefined,
|
||||
},
|
||||
prevServer: prevServer,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Util functions
|
||||
|
||||
private _getLoadingServerObject(serverName: string): MCPServerEventLoadingParam {
|
||||
private _getLoadingServerObject(serverName: string, isOn = true): MCPServerEventLoadingParam {
|
||||
return {
|
||||
response: {
|
||||
event: 'loading',
|
||||
name: serverName,
|
||||
newServer: {
|
||||
status: 'loading',
|
||||
isOn: false,
|
||||
isOn,
|
||||
tools: [],
|
||||
command: '',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user