Skip to main content
Glama
znehraks

MCP Notepad Server

by znehraks
noteStore.ts4.46 kB
/** * 메모 저장소 - 파일 기반 영속화 * * 📚 학습 포인트: * - MCP 서버는 상태를 가질 수 있음 (이 경우 메모 데이터) * - JSON 파일로 데이터를 영속화하여 서버 재시작 후에도 유지 */ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs"; import { dirname, join } from "path"; import { fileURLToPath } from "url"; // 메모 타입 정의 export interface Note { id: string; title: string; content: string; tags: string[]; createdAt: Date; updatedAt: Date; } // 파일 저장용 타입 (Date를 string으로) interface NoteData { id: string; title: string; content: string; tags: string[]; createdAt: string; updatedAt: string; } interface StoreData { idCounter: number; notes: NoteData[]; } // 저장 파일 경로 설정 const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const DATA_DIR = join(__dirname, "../../data"); const DATA_FILE = join(DATA_DIR, "notes.json"); // 인메모리 저장소 const notes: Map<string, Note> = new Map(); // ID 카운터 let idCounter = 0; /** * 데이터 디렉토리 확인 및 생성 */ function ensureDataDir(): void { if (!existsSync(DATA_DIR)) { mkdirSync(DATA_DIR, { recursive: true }); console.error(`[Store] 데이터 디렉토리 생성: ${DATA_DIR}`); } } /** * 파일에서 데이터 로드 */ function loadFromFile(): void { ensureDataDir(); if (!existsSync(DATA_FILE)) { console.error("[Store] 저장된 데이터 없음, 빈 저장소로 시작"); return; } try { const raw = readFileSync(DATA_FILE, "utf-8"); const data: StoreData = JSON.parse(raw); idCounter = data.idCounter || 0; notes.clear(); for (const noteData of data.notes) { const note: Note = { ...noteData, createdAt: new Date(noteData.createdAt), updatedAt: new Date(noteData.updatedAt), }; notes.set(note.id, note); } console.error(`[Store] ${notes.size}개의 메모 로드 완료`); } catch (error) { console.error("[Store] 데이터 로드 실패:", error); } } /** * 파일에 데이터 저장 */ function saveToFile(): void { ensureDataDir(); const data: StoreData = { idCounter, notes: Array.from(notes.values()).map(note => ({ ...note, createdAt: note.createdAt.toISOString(), updatedAt: note.updatedAt.toISOString(), })), }; try { writeFileSync(DATA_FILE, JSON.stringify(data, null, 2), "utf-8"); console.error(`[Store] 데이터 저장 완료: ${DATA_FILE}`); } catch (error) { console.error("[Store] 데이터 저장 실패:", error); } } // 서버 시작 시 데이터 로드 loadFromFile(); // ID 생성 헬퍼 function generateId(): string { return `note_${++idCounter}_${Date.now()}`; } /** * 새 메모 생성 */ export function createNote(title: string, content: string, tags: string[] = []): Note { const id = generateId(); const now = new Date(); const note: Note = { id, title, content, tags, createdAt: now, updatedAt: now, }; notes.set(id, note); saveToFile(); // 파일에 저장 return note; } /** * 메모 조회 */ export function getNote(id: string): Note | undefined { return notes.get(id); } /** * 전체 메모 목록 조회 */ export function getAllNotes(): Note[] { return Array.from(notes.values()).sort( (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime() ); } /** * 메모 수정 */ export function updateNote( id: string, updates: { title?: string; content?: string; tags?: string[] } ): Note | undefined { const note = notes.get(id); if (!note) return undefined; const updatedNote: Note = { ...note, ...updates, updatedAt: new Date(), }; notes.set(id, updatedNote); saveToFile(); // 파일에 저장 return updatedNote; } /** * 메모 삭제 */ export function deleteNote(id: string): boolean { const result = notes.delete(id); if (result) { saveToFile(); // 파일에 저장 } return result; } /** * 키워드로 메모 검색 */ export function searchNotes(keyword: string): Note[] { const lowerKeyword = keyword.toLowerCase(); return getAllNotes().filter(note => note.title.toLowerCase().includes(lowerKeyword) || note.content.toLowerCase().includes(lowerKeyword) || note.tags.some(tag => tag.toLowerCase().includes(lowerKeyword)) ); }

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/znehraks/mcp-poc'

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