feat: add server toggle functionality

This commit is contained in:
samanhappy@qq.com
2025-04-14 22:25:07 +08:00
parent 40d8792294
commit 2e1f73ef64
9 changed files with 264 additions and 50 deletions

View File

@@ -6,6 +6,7 @@ import {
removeServer,
updateMcpServer,
recreateMcpServer,
toggleServerStatus,
} from '../services/mcpService.js';
import { loadSettings } from '../config/index.js';
@@ -207,3 +208,46 @@ export const getServerConfig = (req: Request, res: Response): void => {
});
}
};
export const toggleServer = async (req: Request, res: Response): Promise<void> => {
try {
const { name } = req.params;
const { enabled } = req.body;
if (!name) {
res.status(400).json({
success: false,
message: 'Server name is required',
});
return;
}
if (typeof enabled !== 'boolean') {
res.status(400).json({
success: false,
message: 'Enabled status must be a boolean',
});
return;
}
const result = await toggleServerStatus(name, enabled);
if (result.success) {
recreateMcpServer();
res.json({
success: true,
message: result.message || `Server ${enabled ? 'enabled' : 'disabled'} successfully`,
});
} else {
res.status(404).json({
success: false,
message: result.message || 'Server not found or failed to toggle status',
});
}
} catch (error) {
res.status(500).json({
success: false,
message: 'Internal server error',
});
}
};

View File

@@ -6,6 +6,7 @@ import {
createServer,
updateServer,
deleteServer,
toggleServer,
} from '../controllers/serverController.js';
import {
login,
@@ -24,6 +25,7 @@ export const initRoutes = (app: express.Application): void => {
router.post('/servers', createServer);
router.put('/servers/:name', updateServer);
router.delete('/servers/:name', deleteServer);
router.post('/servers/:name/toggle', toggleServer);
// Auth routes (these will NOT be protected by auth middleware)
app.post('/auth/login', [

View File

@@ -44,12 +44,28 @@ export const initializeClientsFromSettings = (): ServerInfo[] => {
serverInfos = [];
for (const [name, conf] of Object.entries(settings.mcpServers)) {
// Skip disabled servers
if (conf.enabled === false) {
console.log(`Skipping disabled server: ${name}`);
serverInfos.push({
name,
status: 'disconnected',
tools: [],
createTime: Date.now(),
enabled: false
});
continue;
}
// Check if server is already connected
const existingServer = existingServerInfos.find(
(s) => s.name === name && s.status === 'connected',
);
if (existingServer) {
serverInfos.push(existingServer);
serverInfos.push({
...existingServer,
enabled: conf.enabled === undefined ? true : conf.enabled
});
console.log(`Server '${name}' is already connected.`);
continue;
}
@@ -160,12 +176,18 @@ export const registerAllTools = async (server: McpServer, forceInit: boolean): P
// Get all server information
export const getServersInfo = (): Omit<ServerInfo, 'client' | 'transport'>[] => {
return serverInfos.map(({ name, status, tools, createTime }) => ({
name,
status,
tools,
createTime,
}));
const settings = loadSettings();
return serverInfos.map(({ name, status, tools, createTime }) => {
const serverConfig = settings.mcpServers[name];
const enabled = serverConfig ? (serverConfig.enabled !== false) : true;
return {
name,
status,
tools,
createTime,
enabled,
};
});
};
// Get server information by name
@@ -252,6 +274,51 @@ export const updateMcpServer = async (
}
};
// Toggle server enabled status
export const toggleServerStatus = async (
name: string,
enabled: boolean
): Promise<{ success: boolean; message?: string }> => {
try {
const settings = loadSettings();
if (!settings.mcpServers[name]) {
return { success: false, message: 'Server not found' };
}
// Update the enabled status in settings
settings.mcpServers[name].enabled = enabled;
if (!saveSettings(settings)) {
return { success: false, message: 'Failed to save settings' };
}
// If disabling, disconnect the server and remove from active servers
if (!enabled) {
const serverInfo = serverInfos.find((serverInfo) => serverInfo.name === name);
if (serverInfo && serverInfo.client && serverInfo.transport) {
serverInfo.client.close();
serverInfo.transport.close();
console.log(`Closed client and transport for server: ${name}`);
}
// Update the server info to show as disconnected and disabled
const index = serverInfos.findIndex(s => s.name === name);
if (index !== -1) {
serverInfos[index] = {
...serverInfos[index],
status: 'disconnected',
enabled: false,
};
}
}
return { success: true, message: `Server ${enabled ? 'enabled' : 'disabled'} successfully` };
} catch (error) {
console.error(`Failed to toggle server status: ${name}`, error);
return { success: false, message: 'Failed to toggle server status' };
}
};
// Create McpServer instance
export const createMcpServer = (name: string, version: string): McpServer => {
return new McpServer({ name, version });

View File

@@ -23,6 +23,7 @@ export interface ServerConfig {
command?: string; // Command to execute for stdio-based servers
args?: string[]; // Arguments for the command
env?: Record<string, string>; // Environment variables
enabled?: boolean; // Flag to enable/disable the server
}
// Information about a server's status and tools
@@ -33,6 +34,7 @@ export interface ServerInfo {
client?: Client; // Client instance for communication
transport?: SSEClientTransport | StdioClientTransport; // Transport mechanism used
createTime: number; // Timestamp of when the server was created
enabled?: boolean; // Flag to indicate if the server is enabled
}
// Details about a tool available on the server