aios-core
Version:
Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework
370 lines (322 loc) • 8.91 kB
JavaScript
/**
* Global Config Manager
*
* Manages the global MCP configuration at ~/.aios/mcp/
* Handles creation, reading, updating of global config.
*
* @module core/mcp/global-config-manager
* @version 1.0.0
* @story 2.11 - MCP System Global
*/
const fs = require('fs');
const path = require('path');
const {
getGlobalAiosDir,
getGlobalMcpDir,
getGlobalConfigPath,
getServersDir,
getCacheDir,
getCredentialsDir,
} = require('./os-detector');
/**
* Default global config structure
*/
const DEFAULT_CONFIG = {
version: '1.0',
servers: {},
defaults: {
timeout: 30000,
retries: 3,
},
};
/**
* Default server templates for common MCP servers
*/
const SERVER_TEMPLATES = {
context7: {
type: 'sse',
url: 'https://mcp.context7.com/sse',
enabled: true,
},
exa: {
command: 'npx',
args: ['-y', 'exa-mcp-server'],
env: {
EXA_API_KEY: '${EXA_API_KEY}',
},
enabled: true,
},
github: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-github'],
env: {
GITHUB_TOKEN: '${GITHUB_TOKEN}',
},
enabled: true,
},
puppeteer: {
command: 'npx',
args: ['-y', '@anthropic-ai/mcp-server-puppeteer'],
enabled: true,
},
'desktop-commander': {
command: 'npx',
args: ['-y', '@anthropic-ai/mcp-server-desktop-commander'],
enabled: true,
},
filesystem: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem'],
enabled: true,
},
memory: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-memory'],
enabled: true,
},
};
/**
* Check if global AIOS directory exists
* @returns {boolean}
*/
function globalDirExists() {
return fs.existsSync(getGlobalAiosDir());
}
/**
* Check if global MCP directory exists
* @returns {boolean}
*/
function globalMcpDirExists() {
return fs.existsSync(getGlobalMcpDir());
}
/**
* Check if global config file exists
* @returns {boolean}
*/
function globalConfigExists() {
return fs.existsSync(getGlobalConfigPath());
}
/**
* Create the global directory structure
* @returns {Object} Result with created directories
*/
function createGlobalStructure() {
const created = [];
const errors = [];
const directories = [
getGlobalAiosDir(),
getGlobalMcpDir(),
getServersDir(),
getCacheDir(),
getCredentialsDir(),
];
for (const dir of directories) {
try {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
created.push(dir);
}
} catch (error) {
errors.push({ dir, error: error.message });
}
}
// Create .gitignore in credentials directory
const credentialsGitignore = path.join(getCredentialsDir(), '.gitignore');
try {
if (!fs.existsSync(credentialsGitignore)) {
fs.writeFileSync(credentialsGitignore, '*\n!.gitignore\n');
created.push(credentialsGitignore);
}
} catch (error) {
errors.push({ file: credentialsGitignore, error: error.message });
}
return { created, errors, success: errors.length === 0 };
}
/**
* Create default global config file
* @param {Object} initialServers - Optional initial servers to include
* @returns {Object} Result with config path
*/
function createGlobalConfig(initialServers = {}) {
const configPath = getGlobalConfigPath();
if (fs.existsSync(configPath)) {
return { success: false, error: 'Config already exists', configPath };
}
const config = {
...DEFAULT_CONFIG,
servers: { ...initialServers },
};
try {
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
return { success: true, configPath };
} catch (error) {
return { success: false, error: error.message, configPath };
}
}
/**
* Read global config
* @returns {Object|null} Config object or null if not exists
*/
function readGlobalConfig() {
const configPath = getGlobalConfigPath();
if (!fs.existsSync(configPath)) {
return null;
}
try {
const content = fs.readFileSync(configPath, 'utf8');
return JSON.parse(content);
} catch (error) {
console.error(`Error reading global config: ${error.message}`);
return null;
}
}
/**
* Write global config
* @param {Object} config - Config object to write
* @returns {Object} Result with success status
*/
function writeGlobalConfig(config) {
const configPath = getGlobalConfigPath();
try {
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
return { success: true, configPath };
} catch (error) {
return { success: false, error: error.message };
}
}
/**
* Add a server to global config
* @param {string} serverName - Name of the server
* @param {Object} serverConfig - Server configuration (optional, uses template if available)
* @returns {Object} Result with success status
*/
function addServer(serverName, serverConfig = null) {
const config = readGlobalConfig();
if (!config) {
return { success: false, error: 'Global config not found. Run "aios mcp setup" first.' };
}
// Use template if available and no config provided
if (!serverConfig && SERVER_TEMPLATES[serverName]) {
serverConfig = { ...SERVER_TEMPLATES[serverName] };
} else if (!serverConfig) {
return { success: false, error: `No template available for "${serverName}". Provide server configuration.` };
}
// Check if server already exists
if (config.servers[serverName]) {
return { success: false, error: `Server "${serverName}" already exists in config.` };
}
config.servers[serverName] = serverConfig;
const writeResult = writeGlobalConfig(config);
if (!writeResult.success) {
return writeResult;
}
// Also create individual server config file
const serverFilePath = path.join(getServersDir(), `${serverName}.json`);
try {
fs.writeFileSync(serverFilePath, JSON.stringify(serverConfig, null, 2), 'utf8');
} catch (error) {
// Non-critical error, main config is updated
console.warn(`Warning: Could not create server file: ${error.message}`);
}
return { success: true, server: serverName };
}
/**
* Remove a server from global config
* @param {string} serverName - Name of the server to remove
* @returns {Object} Result with success status
*/
function removeServer(serverName) {
const config = readGlobalConfig();
if (!config) {
return { success: false, error: 'Global config not found.' };
}
if (!config.servers[serverName]) {
return { success: false, error: `Server "${serverName}" not found in config.` };
}
delete config.servers[serverName];
const writeResult = writeGlobalConfig(config);
if (!writeResult.success) {
return writeResult;
}
// Also remove individual server config file
const serverFilePath = path.join(getServersDir(), `${serverName}.json`);
try {
if (fs.existsSync(serverFilePath)) {
fs.unlinkSync(serverFilePath);
}
} catch (error) {
console.warn(`Warning: Could not remove server file: ${error.message}`);
}
return { success: true, server: serverName };
}
/**
* Enable/disable a server
* @param {string} serverName - Name of the server
* @param {boolean} enabled - Enable or disable
* @returns {Object} Result with success status
*/
function setServerEnabled(serverName, enabled) {
const config = readGlobalConfig();
if (!config) {
return { success: false, error: 'Global config not found.' };
}
if (!config.servers[serverName]) {
return { success: false, error: `Server "${serverName}" not found in config.` };
}
config.servers[serverName].enabled = enabled;
return writeGlobalConfig(config);
}
/**
* Get list of configured servers
* @returns {Object} Object with server names and their enabled status
*/
function listServers() {
const config = readGlobalConfig();
if (!config) {
return { servers: [], total: 0, enabled: 0 };
}
const servers = Object.entries(config.servers).map(([name, cfg]) => ({
name,
type: cfg.type || 'command',
enabled: cfg.enabled !== false,
url: cfg.url,
command: cfg.command,
}));
return {
servers,
total: servers.length,
enabled: servers.filter(s => s.enabled).length,
};
}
/**
* Get available server templates
* @returns {string[]} List of available template names
*/
function getAvailableTemplates() {
return Object.keys(SERVER_TEMPLATES);
}
/**
* Get a server template
* @param {string} name - Template name
* @returns {Object|null} Template config or null
*/
function getServerTemplate(name) {
return SERVER_TEMPLATES[name] ? { ...SERVER_TEMPLATES[name] } : null;
}
module.exports = {
DEFAULT_CONFIG,
SERVER_TEMPLATES,
globalDirExists,
globalMcpDirExists,
globalConfigExists,
createGlobalStructure,
createGlobalConfig,
readGlobalConfig,
writeGlobalConfig,
addServer,
removeServer,
setServerEnabled,
listServers,
getAvailableTemplates,
getServerTemplate,
};