@geekmai/anteey-mcp-client
Version:
Anteey MCP 客户端 - 连接外部 AI 工具与 Anteey 笔记应用
248 lines (219 loc) • 5.63 kB
JavaScript
/**
* @file config.js
* @description Anteey MCP 客户端配置管理
*/
const fs = require('fs-extra')
const path = require('path')
const os = require('os')
const chalk = require('chalk')
const inquirer = require('inquirer')
// 配置文件路径
const CONFIG_DIR = path.join(os.homedir(), '.anteey-mcp')
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json')
// 默认配置
const DEFAULT_CONFIG = {
apiKey: '',
serverUrl: 'http://localhost:43211/api/mcp',
timeout: 30000,
retries: 3,
logLevel: 'info'
}
/**
* 确保配置目录存在
*/
async function ensureConfigDir() {
try {
await fs.ensureDir(CONFIG_DIR)
} catch (error) {
console.error(chalk.red('创建配置目录失败:'), error.message)
process.exit(1)
}
}
/**
* 加载配置
*/
async function loadConfig() {
try {
await ensureConfigDir()
if (await fs.pathExists(CONFIG_FILE)) {
const configData = await fs.readJson(CONFIG_FILE)
return { ...DEFAULT_CONFIG, ...configData }
}
return DEFAULT_CONFIG
} catch (error) {
console.error(chalk.red('加载配置失败:'), error.message)
return DEFAULT_CONFIG
}
}
/**
* 保存配置
*/
async function saveConfig(config) {
try {
await ensureConfigDir()
await fs.writeJson(CONFIG_FILE, config, { spaces: 2 })
console.log(chalk.green('配置已保存'))
} catch (error) {
console.error(chalk.red('保存配置失败:'), error.message)
process.exit(1)
}
}
/**
* 显示当前配置
*/
async function showConfig() {
const config = await loadConfig()
console.log(chalk.cyan('\n📋 当前配置:'))
console.log(chalk.yellow('API 密钥:'), config.apiKey || chalk.gray('(未设置)'))
console.log(chalk.yellow('服务器地址:'), config.serverUrl)
console.log(chalk.yellow('超时时间:'), `${config.timeout}ms`)
console.log(chalk.yellow('重试次数:'), config.retries)
console.log(chalk.yellow('日志级别:'), config.logLevel)
console.log(chalk.yellow('配置文件位置:'), CONFIG_FILE)
console.log('')
}
/**
* 交互式配置
*/
async function interactiveConfig() {
const config = await loadConfig()
console.log(chalk.cyan('\n🛠️ 配置 Anteey MCP 客户端\n'))
const questions = [
{
type: 'input',
name: 'apiKey',
message: 'API 密钥:',
default: config.apiKey,
validate: (input) => {
if (!input.trim()) {
return '请输入有效的 API 密钥'
}
if (!input.startsWith('anteey_')) {
return 'API 密钥应该以 "anteey_" 开头'
}
return true
}
},
{
type: 'input',
name: 'serverUrl',
message: '服务器地址:',
default: config.serverUrl,
validate: (input) => {
try {
new URL(input)
return true
} catch {
return '请输入有效的服务器地址 (例如: http://localhost:43211/api/mcp)'
}
}
},
{
type: 'number',
name: 'timeout',
message: '请求超时时间 (毫秒):',
default: config.timeout,
validate: (input) => input > 0 || '超时时间必须大于 0'
},
{
type: 'number',
name: 'retries',
message: '重试次数:',
default: config.retries,
validate: (input) => input >= 0 || '重试次数不能为负数'
},
{
type: 'list',
name: 'logLevel',
message: '日志级别:',
choices: ['error', 'warn', 'info', 'debug'],
default: config.logLevel
}
]
const answers = await inquirer.prompt(questions)
const newConfig = { ...config, ...answers }
await saveConfig(newConfig)
console.log(chalk.green('\n✅ 配置完成!'))
console.log(chalk.gray('使用 "anteey-mcp test" 测试连接\n'))
}
/**
* 处理配置命令
*/
async function handleConfig(options) {
try {
// 如果只是列出配置
if (options.list) {
await showConfig()
return
}
// 如果有命令行参数,直接设置
if (options.apiKey || options.server) {
const config = await loadConfig()
if (options.apiKey) {
if (!options.apiKey.startsWith('anteey_')) {
console.error(chalk.red('错误: API 密钥应该以 "anteey_" 开头'))
process.exit(1)
}
config.apiKey = options.apiKey
}
if (options.server) {
try {
new URL(options.server)
config.serverUrl = options.server
} catch {
console.error(chalk.red('错误: 无效的服务器地址'))
process.exit(1)
}
}
await saveConfig(config)
await showConfig()
return
}
// 交互式配置
await interactiveConfig()
} catch (error) {
console.error(chalk.red('配置时出错:'), error.message)
process.exit(1)
}
}
/**
* 获取配置
*/
function getConfig() {
return loadConfig()
}
/**
* 重置配置
*/
async function resetConfig() {
try {
await saveConfig(DEFAULT_CONFIG)
console.log(chalk.green('配置已重置为默认值'))
} catch (error) {
console.error(chalk.red('重置配置失败:'), error.message)
process.exit(1)
}
}
// 如果直接运行此文件
if (require.main === module) {
const args = process.argv.slice(2)
if (args.includes('--list') || args.includes('-l')) {
showConfig()
} else if (args.includes('--reset')) {
resetConfig()
} else {
interactiveConfig()
}
}
module.exports = {
loadConfig,
saveConfig,
showConfig,
interactiveConfig,
handleConfig,
getConfig,
resetConfig,
CONFIG_FILE,
CONFIG_DIR
}