mirror of
https://github.com/samanhappy/mcphub.git
synced 2025-12-24 02:39:19 -05:00
feat: add API endpoints for managing servers and settings
This commit is contained in:
55
src/index.ts
55
src/index.ts
@@ -2,7 +2,7 @@ import express, { Request, Response } from 'express';
|
||||
import dotenv from 'dotenv';
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
||||
import { registerAllTools, getServersInfo } from './server.js';
|
||||
import { registerAllTools, getServersInfo, getServersSettings, addServer, removeServer } from './server.js';
|
||||
import path from 'path';
|
||||
|
||||
dotenv.config();
|
||||
@@ -21,6 +21,9 @@ const PORT = process.env.PORT || 3000;
|
||||
// Serve static files from the public directory
|
||||
app.use(express.static('public'));
|
||||
|
||||
// Parse JSON request body
|
||||
app.use(express.json());
|
||||
|
||||
// to support multiple simultaneous connections we have a lookup object from sessionId to transport
|
||||
const transports: { [sessionId: string]: SSEServerTransport } = {};
|
||||
|
||||
@@ -30,6 +33,56 @@ app.get('/api/servers', (req: Request, res: Response) => {
|
||||
res.json(serversInfo);
|
||||
});
|
||||
|
||||
// API endpoint to get all server settings
|
||||
app.get('/api/settings', (req: Request, res: Response) => {
|
||||
const settings = getServersSettings();
|
||||
res.json(settings);
|
||||
});
|
||||
|
||||
// API endpoint to add a new server
|
||||
app.post('/api/servers', async (req: Request, res: Response) => {
|
||||
const { name, config } = req.body;
|
||||
|
||||
if (!name || typeof name !== 'string') {
|
||||
return res.status(400).json({ success: false, message: 'Server name is required' });
|
||||
}
|
||||
|
||||
if (!config || typeof config !== 'object') {
|
||||
return res.status(400).json({ success: false, message: 'Server configuration is required' });
|
||||
}
|
||||
|
||||
// Validate config has either url or command+args
|
||||
if (!config.url && (!config.command || !config.args)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Server configuration must include either a URL or command with arguments',
|
||||
});
|
||||
}
|
||||
|
||||
const success = await addServer(server, name, config);
|
||||
if (success) {
|
||||
res.json({ success: true, message: 'Server added successfully' });
|
||||
} else {
|
||||
res.status(400).json({ success: false, message: 'Failed to add server' });
|
||||
}
|
||||
});
|
||||
|
||||
// API endpoint to remove a server
|
||||
app.delete('/api/servers/:name', (req: Request, res: Response) => {
|
||||
const { name } = req.params;
|
||||
|
||||
if (!name) {
|
||||
return res.status(400).json({ success: false, message: 'Server name is required' });
|
||||
}
|
||||
|
||||
const success = removeServer(name);
|
||||
if (success) {
|
||||
res.json({ success: true, message: 'Server removed successfully' });
|
||||
} else {
|
||||
res.status(404).json({ success: false, message: 'Server not found or failed to remove' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/sse', async (_: Request, res: Response) => {
|
||||
const transport = new SSEServerTransport('/messages', res);
|
||||
transports[transport.sessionId] = transport;
|
||||
|
||||
@@ -45,6 +45,18 @@ function loadSettings(): McpSettings {
|
||||
}
|
||||
}
|
||||
|
||||
// Function to save settings to file
|
||||
export function saveSettings(settings: McpSettings): boolean {
|
||||
const settingsPath = path.resolve(process.cwd(), 'mcp_settings.json');
|
||||
try {
|
||||
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`Failed to save settings to ${settingsPath}:`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize clients and transports from settings
|
||||
function initializeClientsFromSettings(): {
|
||||
servers: string[];
|
||||
@@ -98,7 +110,7 @@ function initializeClientsFromSettings(): {
|
||||
}
|
||||
|
||||
// Initialize clients and transports
|
||||
const { servers, clients, transports } = initializeClientsFromSettings();
|
||||
let { servers, clients, transports } = initializeClientsFromSettings();
|
||||
|
||||
// Keep track of connected clients and their tools
|
||||
const clientTools: { [clientIndex: number]: ToolInfo[] } = {};
|
||||
@@ -149,6 +161,78 @@ export function getServersInfo(): ServerInfo[] {
|
||||
}));
|
||||
}
|
||||
|
||||
// Add function to get all server settings
|
||||
export function getServersSettings(): McpSettings {
|
||||
return loadSettings();
|
||||
}
|
||||
|
||||
// Add function to add a new server
|
||||
export async function addServer(mcpServer: McpServer, name: string, config: { url?: string; command?: string; args?: string[]; env?: Record<string, string> }): Promise<boolean> {
|
||||
try {
|
||||
// Load current settings
|
||||
const settings = loadSettings();
|
||||
|
||||
// Check if server with this name already exists
|
||||
if (settings.mcpServers[name]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add new server to settings
|
||||
settings.mcpServers[name] = config;
|
||||
|
||||
// Save updated settings
|
||||
if (!saveSettings(settings)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Re-initialize clients with updated settings
|
||||
const result = initializeClientsFromSettings();
|
||||
servers = result.servers;
|
||||
clients = result.clients;
|
||||
transports = result.transports;
|
||||
|
||||
// Register tools for the new server
|
||||
await registerAllTools(mcpServer);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`Failed to add server: ${name}`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Add function to remove a server
|
||||
export function removeServer(name: string): boolean {
|
||||
try {
|
||||
// Load current settings
|
||||
const settings = loadSettings();
|
||||
|
||||
// Check if server exists
|
||||
if (!settings.mcpServers[name]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove server from settings
|
||||
delete settings.mcpServers[name];
|
||||
|
||||
// Save updated settings
|
||||
if (!saveSettings(settings)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Re-initialize clients with updated settings
|
||||
const result = initializeClientsFromSettings();
|
||||
servers = result.servers;
|
||||
clients = result.clients;
|
||||
transports = result.transports;
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`Failed to remove server: ${name}`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function cast(inputSchema: unknown): ZodRawShape {
|
||||
if (typeof inputSchema !== 'object' || inputSchema === null) {
|
||||
throw new Error('Invalid input schema');
|
||||
|
||||
Reference in New Issue
Block a user