Skip to main content
Glama
cli.ts4.87 kB
#!/usr/bin/env node /** * @inchankang/zettel-memory * CLI 진입점 - Commander.js 기반 */ import { Command } from "commander"; import { logger } from "@inchankang/zettel-memory-common"; import { startServer, type MemoryMcpServerOptions } from "./server.js"; const program = new Command(); /** * CLI 버전 정보 */ const PACKAGE_VERSION = "0.0.1"; function parseInteger(value: string, defaultValue: number): number { const parsed = Number.parseInt(value, 10); return Number.isNaN(parsed) ? defaultValue : parsed; } /** * 서버 옵션 빌드 헬퍼 */ function buildServerOptions(options: { verbose?: boolean; vault?: string; index?: string; mode?: string; timeout?: number; retries?: number; }): MemoryMcpServerOptions { if (options.verbose) { logger.setLevel("debug"); } return { vaultPath: options.vault ?? "./vault", indexPath: options.index ?? "./.memory-index.db", mode: (options.mode ?? "dev") as "dev" | "prod", policy: { timeoutMs: options.timeout ?? 5_000, maxRetries: options.retries ?? 2, }, }; } /** * CLI 프로그램 설정 * 루트 레벨에 모든 서버 옵션 정의 (Claude Desktop 호환) */ program .name("memory-mcp") .description("Memory MCP Server - 로컬 퍼시스턴트 메모리를 MCP 서버로 노출") .version(PACKAGE_VERSION) // 루트 레벨 옵션: 서브커맨드 없이 직접 실행 가능 .option("--verbose", "상세 로그 출력", false) .option("--vault <path>", "볼트 디렉토리 경로", "./vault") .option("--index <path>", "인덱스 데이터베이스 경로", "./.memory-index.db") .option("--mode <mode>", "동작 모드 (dev|prod)", "dev") .option( "--timeout <ms>", "툴 실행 타임아웃 (ms)", (value) => parseInteger(value, 5_000), 5_000 ) .option( "--retries <count>", "툴 실행 재시도 횟수", (value) => parseInteger(value, 2), 2 ) .action(async (options) => { // 루트 레벨 기본 action: 옵션으로 서버 시작 const serverOptions = buildServerOptions(options); logger.info("Memory MCP Server 시작 중...", serverOptions); try { await startServer(serverOptions); } catch (error) { logger.error("서버 시작 실패:", error); process.exit(1); } }); /** * 서버 시작 명령 (하위 호환성을 위한 별칭) * Codex 권장: cmd.parent?.optsWithGlobals() 사용 */ program .command("server") .description("MCP 서버 시작 (별칭 - 루트 레벨 실행 권장)") .action(async function (this: Command) { // 부모 옵션 상속 (Codex 피드백 반영) const opts = this.optsWithGlobals?.() ?? this.opts(); const serverOptions = buildServerOptions(opts); logger.info("Memory MCP Server 시작 중 (server 커맨드)...", serverOptions); try { await startServer(serverOptions); } catch (error) { logger.error("서버 시작 실패:", error); process.exit(1); } }); /** * 버전 정보 명령 */ program .command("version") .description("버전 정보 출력") .action(() => { // MCP 호환: stderr로 출력 (stdout은 JSON-RPC 전용) console.error(`Memory MCP Server v${PACKAGE_VERSION}`); console.error("- MCP 프로토콜 호환"); console.error("- JSON-RPC 2.0 stdin/stdout 통신"); console.error("- PARA + Zettelkasten 조직 체계"); console.error("- SQLite FTS5 전문 검색"); }); /** * 헬스체크 명령 * Codex 피드백: 루트 옵션 상속, 보안을 위해 검증만 수행 (파일 열지 않음) */ program .command("healthcheck") .description("시스템 상태 확인") .action(async function (this: Command) { // 부모 옵션 상속 (필요한 옵션만 사용) const opts = this.optsWithGlobals?.() ?? this.opts(); logger.info("시스템 헬스체크 중..."); // MCP 호환: stderr로 출력 (stdout은 JSON-RPC 전용) console.error("✅ Memory MCP Server 상태: 정상"); console.error(`✅ 볼트 경로: ${opts.vault ?? "./vault"}`); console.error(`✅ 인덱스 경로: ${opts.index ?? "./.memory-index.db"}`); console.error("✅ 의존성: 모두 로드됨"); logger.info("헬스체크 완료"); }); /** * 에러 핸들링 */ program.exitOverride((err) => { if (err.code === "commander.version" || err.code === "commander.helpDisplayed") { process.exit(0); } logger.error("CLI 오류:", err); process.exit(1); }); /** * 글로벌 에러 핸들러 */ process.on("unhandledRejection", (reason, promise) => { logger.error("Unhandled Rejection at:", promise, "reason:", reason); process.exit(1); }); process.on("uncaughtException", (error) => { logger.error("Uncaught Exception:", error); process.exit(1); }); /** * CLI 시작 */ if (require.main === module) { program.parse(process.argv); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/inchan/memory-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server