automagik-genie
Version:
Self-evolving AI agent orchestration framework with Model Context Protocol support
142 lines (141 loc) • 4.42 kB
JavaScript
;
/**
* Configuration Manager for Genie MCP Server
*
* Handles loading and saving of ~/.genie/config.yaml with OAuth2.1 support:
* - OAuth2 client credentials (client_id, client_secret)
* - JWT signing keys (RSA key pair)
* - Tunnel configuration
* - Server settings
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadConfig = loadConfig;
exports.loadOAuth2Config = loadOAuth2Config;
exports.saveConfig = saveConfig;
exports.createDefaultConfig = createDefaultConfig;
exports.loadOrCreateConfig = loadOrCreateConfig;
exports.getConfigPath = getConfigPath;
const fs_1 = __importDefault(require("fs"));
const service_config_js_1 = require("./service-config.js");
const path_1 = __importDefault(require("path"));
const yaml_1 = __importDefault(require("yaml"));
const os_1 = __importDefault(require("os"));
const CONFIG_FILE = path_1.default.join(os_1.default.homedir(), '.genie', 'config.yaml');
/**
* Ensure config directory exists
*/
function ensureConfigDir() {
const configDir = path_1.default.dirname(CONFIG_FILE);
if (!fs_1.default.existsSync(configDir)) {
fs_1.default.mkdirSync(configDir, { recursive: true, mode: 0o700 });
}
}
/**
* Load configuration from ~/.genie/config.yaml
* Returns null if file doesn't exist
*/
function loadConfig() {
try {
if (!fs_1.default.existsSync(CONFIG_FILE)) {
return null;
}
const content = fs_1.default.readFileSync(CONFIG_FILE, 'utf8');
const config = yaml_1.default.parse(content);
// Validate required OAuth2 structure
if (!config.mcp?.auth?.oauth2?.clientId) {
throw new Error('Invalid config: missing OAuth2 configuration');
}
return config;
}
catch (error) {
throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Load OAuth2 config from config file
* Returns null if not configured
*/
function loadOAuth2Config() {
try {
const config = loadConfig();
return config?.mcp?.auth?.oauth2 || null;
}
catch {
return null;
}
}
/**
* Save configuration to ~/.genie/config.yaml
* Sets restrictive permissions (0o600) for security
*/
function saveConfig(config) {
try {
ensureConfigDir();
// Convert to YAML
const yaml = yaml_1.default.stringify(config);
// Write with restrictive permissions for security
fs_1.default.writeFileSync(CONFIG_FILE, yaml, { mode: 0o600 });
}
catch (error) {
throw new Error(`Failed to save config: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Create default configuration with OAuth2.1 credentials (async)
*/
async function createDefaultConfig(ngrokToken) {
const oauth2Utils = require('./oauth2-utils');
const { clientId, clientSecret } = oauth2Utils.generateClientCredentials();
const { privateKey, publicKey } = await oauth2Utils.generateKeyPair();
return {
mcp: {
auth: {
oauth2: {
clientId,
clientSecret,
signingKey: privateKey,
publicKey: publicKey,
tokenExpiry: 3600, // 1 hour
issuer: 'genie-mcp-server'
},
created: new Date().toISOString()
},
tunnel: {
enabled: !!ngrokToken,
provider: 'ngrok',
token: ngrokToken || null
},
server: {
port: (0, service_config_js_1.getMcpConfig)().port,
transport: 'httpStream'
}
}
};
}
/**
* Load or create config (async)
* Returns existing config if present, creates default if missing
*/
async function loadOrCreateConfig(ngrokToken) {
try {
const existing = loadConfig();
if (existing) {
return existing;
}
}
catch {
// Config exists but is invalid, create new
}
const config = await createDefaultConfig(ngrokToken);
saveConfig(config);
return config;
}
/**
* Get config file path (for display/debugging)
*/
function getConfigPath() {
return CONFIG_FILE;
}