@geekmai/anteey-mcp-client
Version:
Anteey MCP 客户端 - 连接外部 AI 工具与 Anteey 笔记应用
280 lines (236 loc) • 6.95 kB
JavaScript
/**
* @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,
};