AI 에이전트 영구 메모리 추가 방법: 어제 기억하기

Ashley Innocent

Ashley Innocent

19 March 2026

AI 에이전트 영구 메모리 추가 방법: 어제 기억하기

요약

AI 에이전트에 영구 메모리를 4단계로 추가합니다: (1) `remember`, `recall`, `search`, `rollback` 도구가 있는 MCP 메모리 서버를 설정하고, (2) 에이전트 프롬프트에 메모리 지침을 추가하며, (3) Claude Code의 경우 `~/.claude/settings.json`을, Cursor의 경우 `.cursor/mcp.json`을 구성하고, (4) 의사결정 로깅, 에이전트 인계, 세션 체크포인트에 메모리 패턴을 사용합니다. 에이전트는 세션 간에 컨텍스트를 유지하므로 더 이상 이전 대화를 복사-붙여넣기 할 필요가 없습니다.

"어제 일을 기억하지 못하는 문제"를 해결하세요. MCP 프로토콜을 사용하여 AI 에이전트에 영구 메모리를 추가하면, 에이전트가 이전 세션의 결정, 결과물 및 컨텍스트를 기억할 것입니다.

익숙한 상황일 겁니다:

1일차: "사용자 인증 시스템을 구축하세요"
에이전트: [JWT 인증 구축, 사용자 테이블 생성, 새로 고침 토큰 구현]

2일차: "어제부터 계속 진행하세요"
에이전트: "이전 세션의 컨텍스트가 없습니다. 무엇을 했는지 붙여넣어 주시겠어요?"

이전 대화를 복사-붙여넣기합니다. 에이전트가 2000줄의 컨텍스트를 읽습니다. 둘 다 속도를 다시 맞추는 데 15분을 낭비합니다.

영구 메모리가 이 문제를 해결합니다. MCP(모델 컨텍스트 프로토콜) 메모리를 사용하면 에이전트가 결정을 자동으로 저장하고 필요할 때 회상합니다. 복사-붙여넣기 없이, 재설명할 필요 없이.

이 튜토리얼에서는 AI 에이전트를 위한 MCP 메모리를 설정하는 방법을 배웁니다. 백엔드 아키텍트 세션의 결정을 저장하고, 데이터베이스 옵티마이저로 전환할 때 컨텍스트를 회상하며, 프론트엔드 개발자에게 결과물을 인계하는 방법을 모두 컨텍스트 손실 없이 배웁니다. Apidog 통합으로 API를 구축하든, 여러 날에 걸친 개발 스프린트를 관리하든 동일한 메모리 패턴이 작동합니다.

button

MCP 메모리란 무엇인가요?

MCP 메모리는 AI 에이전트가 세션 간에 정보를 저장하고 검색할 수 있도록 합니다. 에이전트가 쓰고 읽을 수 있는 공유 노트북이라고 생각하면 됩니다.

네 가지 도구가 MCP 메모리를 구동합니다:

도구 목적 예시
remember 태그와 함께 정보 저장 "UUID, bcrypt가 있는 사용자 테이블" 저장
recall 키워드 또는 태그로 검색 "인증 결정" 찾기
rollback 이전 상태로 복원 잘못된 스키마 변경 되돌리기
search 세션 전체에서 찾기 "백엔드 아키텍트가 무엇을 결정했는가?"
┌─────────────────┐         ┌──────────────────┐         ┌─────────────┐
│  AI 에이전트    │         │  MCP 메모리      │         │  저장소     │
│  (Claude Code)  │◄───────►│  서버            │◄───────►│  (SQLite)   │
└─────────────────┘   JSON  └──────────────────┘  I/O    └─────────────┘

1단계: MCP 메모리 서버 설정

메모리 도구를 노출하는 MCP 서버가 필요합니다. 여러 오픈 소스 구현체가 존재합니다.

옵션 A: 호스팅된 메모리 서버 사용

npm install -g @example/mcp-memory-server

옵션 B: 간단한 로컬 서버 실행

`memory-server.js` 생성:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import fs from "fs/promises";
import path from "path";

const MEMORY_FILE = path.join(process.env.HOME, ".mcp-memory", "memories.json");

const server = new McpServer({
  name: "memory",
  version: "1.0.0"
});

// Ensure memory file exists
async function initMemory() {
  await fs.mkdir(path.dirname(MEMORY_FILE), { recursive: true });
  try {
    await fs.access(MEMORY_FILE);
  } catch {
    await fs.writeFile(MEMORY_FILE, JSON.stringify([]));
  }
}

// Tool: remember
server.tool(
  "remember",
  {
    content: z.string().describe("정보 저장"),
    tags: z.array(z.string()).describe("검색을 위한 태그 (예: ['backend', 'auth'])"),
    agent: z.string().optional().describe("태그 지정을 위한 에이전트 이름")
  },
  async ({ content, tags, agent }) => {
    await initMemory();
    const memories = JSON.parse(await fs.readFile(MEMORY_FILE, "utf-8"));
    const memory = {
      id: Date.now().toString(),
      content,
      tags,
      agent,
      timestamp: new Date().toISOString()
    };
    memories.push(memory);
    await fs.writeFile(MEMORY_FILE, JSON.stringify(memories, null, 2));
    return { content: [{ type: "text", text: `태그와 함께 메모리 저장: ${tags.join(", ")}` }] };
  }
);

// Tool: recall
server.tool(
  "recall",
  {
    query: z.string().describe("검색 쿼리 또는 찾을 태그"),
    agent: z.string().optional().describe("에이전트 이름으로 필터링")
  },
  async ({ query, agent }) => {
    await initMemory();
    const memories = JSON.parse(await fs.readFile(MEMORY_FILE, "utf-8"));
    const results = memories.filter(m => {
      const matchesQuery = m.content.toLowerCase().includes(query.toLowerCase()) ||
                          m.tags.some(t => t.toLowerCase().includes(query.toLowerCase()));
      const matchesAgent = !agent || m.agent === agent;
      return matchesQuery && matchesAgent;
    });
    return {
      content: [{
        type: "text",
        text: results.length === 0
          ? "메모리가 없습니다."
          : results.map(m => `[${m.timestamp}] ${m.content}`).join("\n\n")
      }]
    };
  }
);

// Tool: search
server.tool(
  "search",
  {
    tags: z.array(z.string()).describe("검색할 태그"),
    limit: z.number().optional().default(10)
  },
  async ({ tags, limit }) => {
    await initMemory();
    const memories = JSON.parse(await fs.readFile(MEMORY_FILE, "utf-8"));
    const results = memories
      .filter(m => tags.some(t => m.tags.includes(t)))
      .slice(0, limit);
    return {
      content: [{
        type: "text",
        text: results.map(m => `[${m.agent || "알 수 없음"}] ${m.content}`).join("\n\n")
      }]
    };
  }
);

// Tool: rollback
server.tool(
  "rollback",
  {
    agent: z.string().describe("롤백할 에이전트 이름"),
    timestamp: z.string().describe("이 타임스탬프로 롤백")
  },
  async ({ agent, timestamp }) => {
    await initMemory();
    const memories = JSON.parse(await fs.readFile(MEMORY_FILE, "utf-8"));
    const rolledBack = memories.filter(m =>
      m.agent !== agent || new Date(m.timestamp) <= new Date(timestamp)
    );
    await fs.writeFile(MEMORY_FILE, JSON.stringify(rolledBack, null, 2));
    return {
      content: [{
        type: "text",
        text: `${agent}를 ${timestamp}로 롤백했습니다.`
      }]
    };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);

서버 실행:

node memory-server.js

2단계: 모든 에이전트에 메모리 지침 추가

에이전트 파일을 수정할 필요가 없습니다. 프롬프트에 메모리 지침을 추가하세요:

MCP 메모리 도구(remember, recall, search, rollback)를 사용할 수 있습니다.

다음 메모리 프로토콜을 따르세요:

**세션을 시작할 때:**
1. 컨텍스트 회상: recall(query="ecommerce-api", agent="Backend Architect")
2. 지난 세션의 보류 중인 항목 검토

**작업을 완료할 때:**
1. 태그와 함께 결과물 기억:
   - remember(content="UUID 기본 키, bcrypt 비밀번호 해싱, 새로 고침 토큰을 사용한 JWT 인증으로 사용자 테이블 생성", tags=["ecommerce-api", "database", "auth"], agent="Backend Architect")
2. 결정 사항과 보류 중인 항목 포함

**다른 에이전트에 인계할 때:**
1. 인계받을 에이전트를 위한 컨텍스트 남기기:
   - remember(content="API 엔드포인트: /auth/login, /auth/register, /products, /orders. 인증 흐름: JWT 액세스 토큰 (15분) + 새로 고침 토큰 (7일). 알려진 문제: 속도 제한이 아직 구현되지 않음", tags=["ecommerce-api", "handoff"], agent="Backend Architect", for="Frontend Developer")

**문제가 발생할 때:**
1. 마지막으로 알려진 정상 상태 검색
2. 롤백을 사용하여 복원

실행 예시:

당신: "백엔드 아키텍트 모드를 활성화하세요. 우리 전자상거래 API를 위한 사용자 시스템을 설계하세요."

[에이전트가 시스템을 설계하고, 스키마를 생성하고, 인증을 구현합니다]

에이전트: "사용자 시스템 완료. 메모리 저장 중..."
→ 호출: remember("UUID, bcrypt, JWT + 새로 고침 토큰이 있는 사용자 테이블", tags: ["ecommerce-api", "auth", "database"])

[세션 종료]

[다음 날]

당신: "어제부터 계속 진행하세요"

에이전트: "컨텍스트 회상 중..."
→ 호출: recall(query="ecommerce-api")
→ 반환: "UUID, bcrypt, JWT + 새로 고침 토큰이 있는 사용자 테이블"

에이전트: "어제 UUID 기본 키로 사용자 테이블을 설계했고, bcrypt 비밀번호 해싱을 구현했으며, 새로 고침 토큰으로 JWT 인증을 설정했습니다. 다음 단계: 제품 카탈로그 스키마. 계속 진행할 준비가 되었습니다."

3단계: Claude Code 구성

MCP 구성에 메모리 서버를 추가하세요:

`~/.claude/settings.json` 편집:

{
  "mcpServers": {
    "memory": {
      "command": "node",
      "args": ["/absolute/path/to/memory-server.js"],
      "env": {
        "HOME": "/Users/your-username"
      }
    }
  }
}

Claude Code를 다시 시작하세요. 이제 메모리 도구를 사용할 수 있을 것입니다.

테스트:

remember 도구를 사용하여 다음을 저장하세요: "전자상거래 프로젝트를 위한 테스트 메모리"
태그: ["test", "ecommerce-api"]
recall 도구를 사용하여 "test"에 대한 메모리를 찾으세요.

4단계: Cursor 구성

프로젝트에 `.cursor/mcp.json` 파일을 생성하세요:

{
  "mcpServers": {
    "memory": {
      "command": "node",
      "args": ["/absolute/path/to/memory-server.js"]
    }
  }
}

테스트:

@memory remember "PostgreSQL로 전자상거래 API 프로젝트 시작"
태그: ["ecommerce-api", "setup"]
@memory recall query="ecommerce"

실제 워크플로우를 위한 메모리 패턴

패턴 1: 의사결정 로깅

기술적 결정을 내릴 때마다 기록하세요:

remember({
  content: "PostgreSQL을 MySQL 대신 선택한 이유: (1) 유연한 제품 속성을 위한 JSONB 지원, (2) 더 나은 전체 텍스트 검색, (3) UUID 네이티브 지원",
  tags: ["ecommerce-api", "database", "decision"],
  agent: "Backend Architect"
})

나중에 누군가 "왜 PostgreSQL인가요?"라고 물으면:

recall(query="PostgreSQL MySQL decision")

패턴 2: 에이전트 인계

에이전트를 전환할 때, 인계 노트를 남기세요:

remember({
  content: "백엔드 완료. 엔드포인트: POST /auth/login, POST /auth/register, GET /products, POST /orders. 인증: JWT 15분 액세스 + 7일 새로 고침. 보류 중: 속도 제한, 이메일 확인. 프론트엔드 필요: 로그인 폼, 제품 목록, 장바구니, 결제.",
  tags: ["ecommerce-api", "handoff", "backend-complete"],
  agent: "Backend Architect",
  for: "Frontend Developer"
})

프론트엔드 개발자는 다음으로 시작합니다:

recall(query="handoff", agent="Backend Architect")

패턴 3: 세션 체크포인트

각 작업 세션이 끝날 때:

remember({
  content: "세션 완료. 완료: 사용자 테이블, 인증 엔드포인트, 제품 스키마. 다음 세션: 주문 시스템, 결제 웹훅. 블로커: Stripe API 키 대기 중.",
  tags: ["ecommerce-api", "checkpoint", "session-1"],
  agent: "Backend Architect"
})

다음 세션 재개:

recall(query="checkpoint session-1")

패턴 4: 버그 추적

버그를 발견할 때:

remember({
  content: "버그: 로그아웃 후 새로 고침 토큰이 만료되지 않음. 토큰이 메모리에 저장되어 있고, 영구 저장되지 않음. 수정: TTL을 사용하여 Redis로 이동.",
  tags: ["ecommerce-api", "bug", "auth"],
  agent: "Code Reviewer",
  severity: "high"
})

나중에 버그 검색:

search(tags=["bug", "ecommerce-api"])

문제 해결

메모리가 유지되지 않음:

회상 시 결과가 너무 많음:

메모리 파일이 너무 커짐:

구축한 것

구성 요소 목적
MCP 메모리 서버 세션 간에 정보 저장/검색
remember 도구 결정, 결과물, 인계 사항 기록
recall 도구 이전 세션의 컨텍스트 찾기
search 도구 모든 메모리에서 태그별로 쿼리
rollback 도구 필요할 때 이전 상태로 복원
메모리 패턴 의사결정 로깅, 인계, 체크포인트, 버그 추적

다음 단계

메모리 서버 확장:

팀 메모리 구축:

도구와 통합:

일반적인 문제 해결

세션 간에 메모리가 유지되지 않음:

회상 시 빈 결과가 반환됨:

메모리 파일이 너무 커짐:

서버 시작 실패:

여러 에이전트가 서로의 메모리를 덮어씀:

메모리 서버 보안 고려 사항

API 키 저장: 메모리 서버가 민감한 데이터(API 키, 비밀번호)를 저장하는 경우, 암호화를 구현하세요:

import crypto from 'crypto';

const ENCRYPTION_KEY = process.env.MEMORY_ENCRYPTION_KEY;
const ALGORITHM = 'aes-256-gcm';

function encrypt(text) {
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv(ALGORITHM, Buffer.from(ENCRYPTION_KEY), iv);
  const encrypted = cipher.update(text, 'utf8', 'hex');
  return {
    encryptedData: encrypted + cipher.final('hex'),
    iv: iv.toString('hex'),
    authTag: cipher.getAuthTag().toString('hex')
  };
}

function decrypt(encrypted) {
  const decipher = crypto.createDecipheriv(
    ALGORITHM,
    Buffer.from(ENCRYPTION_KEY),
    Buffer.from(encrypted.iv, 'hex')
  );
  decipher.setAuthTag(Buffer.from(encrypted.authTag, 'hex'));
  return decipher.update(encrypted.encryptedData, 'hex', 'utf8') + decipher.final('utf8');
}

접근 제어: 팀 메모리 서버의 경우, 인증을 추가하세요:

이제 AI 에이전트가 영구 메모리를 갖게 됩니다. 어제 일을 기억하고, 결정을 회상하며, 복사-붙여넣기 없이 컨텍스트를 인계합니다.

더 이상 "이전 세션의 컨텍스트가 없습니다"라는 말은 없습니다. 더 이상 재설명할 필요도, 시간 낭비도 없습니다.

이것이 바로 MCP 메모리의 힘입니다. 에이전트에게 공유 노트북을 제공하고, 여러 날에 걸친 프로젝트에서 에이전트가 실제로 유용해지는 것을 지켜보세요.

button

자주 묻는 질문

MCP 메모리란 무엇인가요? MCP 메모리는 AI 에이전트가 세션 간에 정보를 저장하고 검색할 수 있도록 하는 프로토콜 구현입니다. 에이전트가 쓰고 읽을 수 있는 공유 노트북으로, 단일 대화를 넘어 컨텍스트를 유지한다고 생각하면 됩니다.

Claude Code에 영구 메모리를 어떻게 설정하나요? MCP 메모리 서버를 설치한 다음, 서버 명령과 경로를 사용하여 `~/.claude/settings.json`에 추가하세요. Claude Code를 다시 시작하면 메모리 도구(`remember`, `recall`, `search`, `rollback`)를 사용할 수 있습니다.

어떤 AI 에이전트가 MCP 메모리를 지원하나요? MCP 호환 클라이언트(Claude Code, Cursor, Windsurf)에서 실행되는 모든 에이전트는 메모리 도구를 사용할 수 있습니다. 에이전트 파일을 수정할 필요 없이 프롬프트에 메모리 지침만 추가하면 됩니다.

에이전트 인계를 위한 가장 좋은 메모리 패턴은 무엇인가요? `["handoff", "project-name"]`과 같은 태그와 함께 `remember`를 사용하여 다음 에이전트를 위한 컨텍스트를 남기세요. 완료된 작업, 보류 중인 항목 및 알려진 문제를 포함하세요. 인계받는 에이전트는 `recall(query="handoff")`를 호출하여 이를 검색합니다.

MCP 서버는 얼마나 많은 메모리를 저장할 수 있나요? 구현에 따라 다릅니다. 참조 서버는 무한히 커지는 JSON 파일을 사용합니다. 프로덕션 서버는 대규모 사용을 위해 만료 정책, 자동 보관 또는 데이터베이스 백엔드를 추가해야 합니다.

팀이 중앙 메모리 서버를 공유할 수 있나요? 예. 공유 머신 또는 클라우드 인스턴스에서 메모리 서버를 실행하고, 모든 팀원의 클라이언트를 서버에 연결하도록 구성하며, 체계적인 검색을 위해 프로젝트 및 개발자별로 메모리에 태그를 지정하세요.

메모리 회상 시 결과가 너무 많이 반환되면 어떻게 해야 하나요? 메모리를 저장할 때 더 구체적인 태그를 추가하세요. 회상 쿼리에서 에이전트 이름으로 필터링하세요. 따옴표로 정확한 구문을 사용하세요. 더 스마트한 검색을 위해 임베딩을 사용한 의미론적 검색 구현을 고려하세요.

Apidog에서 API 설계-첫 번째 연습

API를 더 쉽게 구축하고 사용하는 방법을 발견하세요