UNPKG

@ankimcp/anki-mcp-server

Version:

Model Context Protocol server for Anki - enables AI assistants to interact with your Anki flashcards

74 lines • 3.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const core_1 = require("@nestjs/core"); const common_1 = require("@nestjs/common"); const app_module_1 = require("./app.module"); const bootstrap_1 = require("./bootstrap"); const cli_1 = require("./cli"); const cli_2 = require("./cli/index.js"); const ngrok_service_1 = require("./services/ngrok.service"); const config_1 = require("./config"); const host_validation_guard_1 = require("./http/guards/host-validation.guard"); const mcp_http_factory_1 = require("./http/mcp-http.factory"); async function bootstrap() { (0, cli_1.checkForUpdates)(); const options = (0, cli_1.parseCliArgs)(); const cli = (0, cli_2.createCli)(options.debug); const tunnelUrl = (0, cli_1.parseOptionalUrl)(options.tunnel, "--tunnel", cli); const configInput = (0, config_1.buildConfigInput)({ port: options.port, host: options.host, ankiConnect: options.ankiConnect, readOnly: options.readOnly, tunnel: tunnelUrl, ngrok: options.ngrok, debug: options.debug, }); const validatedConfig = config_1.configSchema.parse((0, config_1.transformEnvToConfig)(configInput)); const pinoLogger = (0, bootstrap_1.createPinoLogger)(bootstrap_1.LOG_DESTINATION.STDOUT, configInput.LOG_LEVEL || "info"); const loggerService = (0, bootstrap_1.createLoggerService)(pinoLogger); const mcpHttp = (0, mcp_http_factory_1.createMcpHttpServer)(validatedConfig.mcpServer); const app = await core_1.NestFactory.create(app_module_1.AppModule.forHttp(mcpHttp, configInput), { logger: loggerService, bufferLogs: true, }); const boundHost = validatedConfig.host; if ((0, host_validation_guard_1.shouldWarnLoopbackOnly)(boundHost, validatedConfig.allowedHosts)) { new common_1.Logger("HttpBootstrap").warn(`Server is bound to ${boundHost} but ALLOWED_HOSTS is not set. ` + `For DNS-rebinding protection, only loopback Host headers ` + `(localhost, 127.0.0.1, ::1) are accepted — requests via a LAN or ` + `public hostname will be rejected with 403. Set ALLOWED_HOSTS ` + `(comma-separated hostnames) to permit them.`); } mcpHttp.strategy.setHttpAdapter(app.getHttpAdapter()); app.connectMicroservice({ strategy: mcpHttp.strategy }); await app.startAllMicroservices(); await app.listen(validatedConfig.port, validatedConfig.host); let ngrokUrl; if (options.ngrok) { try { const ngrokService = new ngrok_service_1.NgrokService(); const tunnelInfo = await ngrokService.start(validatedConfig.port); ngrokUrl = tunnelInfo.publicUrl; } catch (err) { cli.blank(); cli.error(`Failed to start ngrok: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : undefined); cli.blank(); cli.info("Server is still running locally without tunnel."); cli.blank(); } } (0, cli_1.displayStartupBanner)(cli, { port: validatedConfig.port, host: validatedConfig.host, ankiConnect: validatedConfig.ankiConnect.url, readOnly: validatedConfig.readOnly, }, ngrokUrl); } bootstrap().catch((err) => { const cli = (0, cli_2.createCli)(false); cli.error(`Failed to start MCP HTTP server: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : undefined); process.exit(1); }); //# sourceMappingURL=main-http.js.map