UNPKG

@geekmai/anteey-mcp-client

Version:

Anteey MCP 客户端 - 连接外部 AI 工具与 Anteey 笔记应用

280 lines (236 loc) 6.95 kB
#!/usr/bin/env node /** * @file discover.js * @description 自动发现本地 Anteey 实例 */ const http = require("http"); const chalk = require("chalk"); const ora = require("ora"); const { loadConfig, saveConfig } = require("./config"); // 常见的 Anteey 服务端口 const COMMON_PORTS = [43211, 3690, 8080, 8000, 3000, 5000]; // 服务发现超时时间 const DISCOVERY_TIMEOUT = 3000; /** * 检查指定端口是否有 Anteey 服务 */ function checkPort(port) { return new Promise((resolve) => { const startTime = Date.now(); const req = http.get( `http://localhost:${port}/api/mcp/notes/search?query=test&limit=1`, { timeout: DISCOVERY_TIMEOUT, }, (res) => { let data = ""; res.on("data", (chunk) => { data += chunk; }); res.on("end", () => { const responseTime = Date.now() - startTime; try { const response = JSON.parse(data); if (response.success || res.statusCode === 401) { // 401 表示服务存在但需要认证 resolve({ port, url: `http://localhost:${port}/api/mcp`, status: res.statusCode, responseTime, available: true, }); } else { resolve({ port, available: false }); } } catch (error) { resolve({ port, available: false }); } }); } ); req.on("error", () => { resolve({ port, available: false }); }); req.on("timeout", () => { req.destroy(); resolve({ port, available: false }); }); req.end(); }); } /** * 扫描常见端口寻找 Anteey 服务 */ async function scanPorts() { const spinner = ora("正在扫描本地 Anteey 服务...").start(); try { const results = await Promise.all( COMMON_PORTS.map((port) => checkPort(port)) ); const availableServices = results.filter((result) => result.available); spinner.stop(); if (availableServices.length === 0) { console.log(chalk.yellow("⚠️ 未发现运行中的 Anteey 服务")); console.log(chalk.gray("请确保 Anteey 应用已启动并开启了 MCP 服务")); return []; } console.log( chalk.green(`🎉 发现 ${availableServices.length} 个 Anteey 服务:`) ); availableServices.forEach((service, index) => { console.log(chalk.cyan(` ${index + 1}. ${service.url}`)); console.log( chalk.gray(` 状态: ${service.status === 401 ? "需要认证" : "正常"}`) ); console.log(chalk.gray(` 响应时间: ${service.responseTime}ms`)); console.log(""); }); return availableServices; } catch (error) { spinner.stop(); console.error(chalk.red("扫描服务时出错:"), error.message); return []; } } /** * 测试服务连接 */ async function testService(url, apiKey) { return new Promise((resolve) => { const req = http.get( `${url}/notes/search?query=test&limit=1`, { headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : {}, timeout: 5000, }, (res) => { let data = ""; res.on("data", (chunk) => { data += chunk; }); res.on("end", () => { try { const response = JSON.parse(data); resolve({ success: res.statusCode === 200, status: res.statusCode, response: response, }); } catch (error) { resolve({ success: false, status: res.statusCode, error: "无法解析响应", }); } }); } ); req.on("error", (error) => { resolve({ success: false, error: error.message, }); }); req.on("timeout", () => { req.destroy(); resolve({ success: false, error: "连接超时", }); }); req.end(); }); } /** * 自动配置服务 */ async function autoConfig(service) { const config = await loadConfig(); console.log(chalk.cyan("🔧 自动配置服务...")); // 更新服务器地址 config.serverUrl = service.url; // 如果有 API 密钥,测试连接 if (config.apiKey) { console.log(chalk.gray("正在测试 API 密钥...")); const testResult = await testService(service.url, config.apiKey); if (testResult.success) { console.log(chalk.green("✅ API 密钥验证成功")); } else { console.log(chalk.yellow("⚠️ API 密钥验证失败,请检查密钥是否正确")); } } else { console.log(chalk.yellow("⚠️ 未配置 API 密钥")); console.log(chalk.gray('请使用 "anteey-mcp config" 设置 API 密钥')); } await saveConfig(config); console.log(chalk.green("✅ 配置已更新")); } /** * 主发现函数 */ async function discover() { try { console.log(chalk.cyan("🔍 正在搜索本地 Anteey 服务...\n")); const services = await scanPorts(); if (services.length === 0) { console.log(chalk.yellow("💡 启动建议:")); console.log(chalk.gray(" 1. 确保 Anteey 应用已启动")); console.log(chalk.gray(" 2. 在 Anteey 设置中启用 MCP 服务")); console.log(chalk.gray(" 3. 检查防火墙设置")); console.log(""); return; } if (services.length === 1) { // 只有一个服务,自动配置 await autoConfig(services[0]); } else { // 多个服务,让用户选择 const inquirer = require("inquirer"); const choices = services.map((service) => ({ name: `${service.url} (${ service.status === 401 ? "需要认证" : "正常" })`, value: service, })); choices.push({ name: "跳过自动配置", value: null, }); const { selectedService } = await inquirer.prompt([ { type: "list", name: "selectedService", message: "选择要配置的服务:", choices, }, ]); if (selectedService) { await autoConfig(selectedService); } else { console.log(chalk.gray("已跳过自动配置")); } } console.log(chalk.cyan("\n🎯 下一步:")); console.log(chalk.gray(' 1. 使用 "anteey-mcp config" 设置 API 密钥')); console.log(chalk.gray(' 2. 使用 "anteey-mcp test" 测试连接')); console.log( chalk.gray(' 3. 使用 "anteey-mcp raycast" 启动 Raycast 适配器') ); console.log(""); } catch (error) { console.error(chalk.red("发现服务时出错:"), error.message); process.exit(1); } } // 如果直接运行此文件 if (require.main === module) { discover(); } module.exports = { discover, scanPorts, testService, checkPort, };