DEV Community

Cover image for AIエージェントに永続的メモリを追加する方法:昨日を覚えさせる
Akira
Akira

Posted on • Originally published at apidog.com

AIエージェントに永続的メモリを追加する方法:昨日を覚えさせる

要約

AIエージェントに永続メモリを4つのステップで追加します。(1) rememberrecallsearchrollbackツールを備えたMCPメモリサーバーをセットアップし、(2) エージェントプロンプトにメモリ指示を追加し、(3) Claude Codeの場合は~/.claude/settings.jsonを、Cursorの場合は.cursor/mcp.jsonを設定し、(4) 意思決定ログ、エージェントの引き継ぎ、セッションのチェックポイントにメモリパターンを使用します。エージェントはセッション間でコンテキストを保持するため、以前の会話をコピー&ペーストする必要がなくなります。

Apidog を今すぐ試す

「昨日を覚えていない」問題を解決します。MCPプロトコルを使用してAIエージェントに永続メモリを追加すると、以前のセッションからの決定、成果物、およびコンテキストを想起できるようになります。

よくある問題の例です。

Day 1: "Build the user authentication system"
Agent: [ユーザー認証システムを構築し、usersテーブルを作成し、リフレッシュトークンを実装する]

Day 2: "Continue from yesterday"
Agent: "I don't have context from previous sessions. Can you paste what we did?"
         (前回のセッションからのコンテキストがありません。何をしたかペーストしてもらえますか?)
Enter fullscreen mode Exit fullscreen mode

このように、会話履歴を毎回貼り付ける手間が発生し、エージェントも開発者も状況把握に時間がかかります。

永続メモリはこの問題を解決します。MCP(Model Context Protocol)メモリを導入することで、エージェントは決定事項や成果物を自動的に保存・呼び出せるようになり、コピー&ペーストや再説明が不要になります。

本記事では、AIエージェント用MCPメモリの構築方法を具体的に解説します。Backend Architectセッションからの決定保存、Database Optimizerへの引き継ぎ、Frontend Developerへの成果物渡しなど、連続した開発ワークフローの中でコンテキストを失わずにやりとりできます。同様のメモリパターンはApidog連携や長期開発の管理にも応用可能です。

MCPメモリとは?

MCPメモリは、AIエージェントがセッション間で情報を保存・取得できる仕組みです。エージェントが自由に書き込み・読み取りできる共有ノートブックのようなものです。

MCPメモリには4つの主要ツールがあります。

ツール 目的
remember タグ付きで情報を保存 「UUID, bcrypt付きユーザーテーブル」を保存
recall キーワードやタグで検索 「認証決定」を検索
rollback 以前の状態に復元 間違ったスキーマ変更を元に戻す
search セッションを横断して検索 「Backend Architectは何を決定したか?」
┌─────────────────┐         ┌──────────────────┐         ┌─────────────┐
│  AI Agent       │         │  MCP Memory      │         │  Storage    │
│  (Claude Code)  │◄───────►│  Server          │◄───────►│  (SQLite)   │
└─────────────────┘   JSON  └──────────────────┘  I/O    └─────────────┘
Enter fullscreen mode Exit fullscreen mode

ステップ1: MCPメモリサーバーのセットアップ

まずはMCPサーバーを用意します。OSS実装 or シンプルなローカルサーバーが選べます。

オプションA: ホストされたメモリサーバー

npm install -g @example/mcp-memory-server
Enter fullscreen mode Exit fullscreen mode

オプション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("Information to store"),
    tags: z.array(z.string()).describe("Tags for retrieval (e.g., ['backend', 'auth'])"),
    agent: z.string().optional().describe("Agent name for tagging")
  },
  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: `Stored memory with tags: ${tags.join(", ")}` }] };
  }
);

// Tool: recall
server.tool(
  "recall",
  {
    query: z.string().describe("Search query or tag to find"),
    agent: z.string().optional().describe("Filter by agent name")
  },
  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
          ? "No memories found"
          : results.map(m => `[${m.timestamp}] ${m.content}`).join("\n\n")
      }]
    };
  }
);

// Tool: search
server.tool(
  "search",
  {
    tags: z.array(z.string()).describe("Tags to search for"),
    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 || "unknown"}] ${m.content}`).join("\n\n")
      }]
    };
  }
);

// Tool: rollback
server.tool(
  "rollback",
  {
    agent: z.string().describe("Agent name to rollback"),
    timestamp: z.string().describe("Rollback to this timestamp")
  },
  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: `Rolled back ${agent} to ${timestamp}`
      }]
    };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);
Enter fullscreen mode Exit fullscreen mode

サーバー起動:

node memory-server.js
Enter fullscreen mode Exit fullscreen mode

ステップ2: 任意のエージェントにメモリ指示を追加

エージェント本体のコード修正は不要です。プロンプトに以下のメモリ指示を入れるだけでOKです。

あなたはMCPメモリツール (remember, recall, search, rollback) にアクセスできます。

以下のメモリプロトコルに従ってください。

**セッションを開始するとき:**
1. コンテキストを呼び出す: recall(query="ecommerce-api", agent="Backend Architect")
2. 前回のセッションからの保留中の項目を確認する

**作業を完了するとき:**
1. 成果物をタグ付きで記憶する:
   - remember(content="Created users table with UUID primary key, bcrypt password hashing, JWT auth with refresh tokens", tags=["ecommerce-api", "database", "auth"], agent="Backend Architect")
2. 行われた決定と保留中の項目を含める

**他のエージェントに引き継ぐとき:**
1. 受信側のエージェントのためにコンテキストを残す:
   - remember(content="API endpoints: /auth/login, /auth/register, /products, /orders. Auth flow: JWT access token (15min) + refresh token (7 days). Known issue: rate limiting not yet implemented", tags=["ecommerce-api", "handoff"], agent="Backend Architect", for="Frontend Developer")

**何かが失敗したとき:**
1. 最後の既知の良好な状態を検索する
2. ロールバックを使用して復元する
Enter fullscreen mode Exit fullscreen mode

実行例

You: "Activate Backend Architect mode. Design the user system for our e-commerce API."
         (「Backend Architectモードをアクティブにしてください。eコマースAPIのユーザーシステムを設計してください。」)

[Agent designs the system, creates schema, implements auth]
(エージェントがシステムを設計し、スキーマを作成し、認証を実装する)

Agent: "User system complete. Storing memory..."
         (「ユーザーシステムが完了しました。メモリに保存しています...」)
→ Calls: remember("users table with UUID, bcrypt, JWT + refresh tokens", tags: ["ecommerce-api", "auth", "database"])

[Session ends]
(セッション終了)

[Next day]
(翌日)

You: "Continue from yesterday"
         (「昨日から続けてください」)

Agent: "Recalling context..."
         (「コンテキストを呼び出しています...」)
→ Calls: recall(query="ecommerce-api")
→ Returns: "users table with UUID, bcrypt, JWT + refresh tokens"

Agent: "Yesterday I designed the users table with UUID primary keys, implemented bcrypt password hashing, and set up JWT authentication with refresh tokens. Next step: product catalog schema. Ready to continue."
         (「昨日、私はUUID主キーを持つusersテーブルを設計し、bcryptパスワードハッシュを実装し、リフレッシュトークン付きのJWT認証を設定しました。次のステップは商品カタログのスキーマです。続行する準備ができています。」)
Enter fullscreen mode Exit fullscreen mode

ステップ3: Claude Code向けの設定

MCP構成にメモリサーバーを追加します。

~/.claude/settings.json を編集し、下記のように追記します。

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

Claude Codeを再起動してください。メモリツールが利用可能になります。

テスト例:

rememberツールで「eコマースプロジェクトのテストメモリ」を保存
タグ: ["test", "ecommerce-api"]
Enter fullscreen mode Exit fullscreen mode
recallツールで「test」に関するメモリを検索
Enter fullscreen mode Exit fullscreen mode

ステップ4: Cursor向けの設定

.cursor/mcp.json ファイルを作成します。

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

テスト例:

@memory remember "Starting ecommerce API project with PostgreSQL"
Tags: ["ecommerce-api", "setup"]
Enter fullscreen mode Exit fullscreen mode
@memory recall query="ecommerce"
Enter fullscreen mode Exit fullscreen mode

実際のワークフローのためのメモリパターン

パターン1: 決定のログ記録

技術的な意思決定は必ずログ化します。

remember({
  content: "Chose PostgreSQL over MySQL for: (1) JSONB support for flexible product attributes, (2) better full-text search, (3) UUID native support",
  tags: ["ecommerce-api", "database", "decision"],
  agent: "Backend Architect"
})
Enter fullscreen mode Exit fullscreen mode

後から「なぜPostgreSQL?」と聞かれた場合:

recall(query="PostgreSQL MySQL decision")
Enter fullscreen mode Exit fullscreen mode

パターン2: エージェントの引き継ぎ

エージェント切替時に、引き継ぎノートを残します。

remember({
  content: "Backend complete. Endpoints: POST /auth/login, POST /auth/register, GET /products, POST /orders. Auth: JWT 15min access + 7 day refresh. Pending: rate limiting, email verification. Frontend needs: login form, product list, cart, checkout.",
  tags: ["ecommerce-api", "handoff", "backend-complete"],
  agent: "Backend Architect",
  for: "Frontend Developer"
})
Enter fullscreen mode Exit fullscreen mode

Frontend Developerは下記で開始:

recall(query="handoff", agent="Backend Architect")
Enter fullscreen mode Exit fullscreen mode

パターン3: セッションのチェックポイント

各作業セッション終了時にチェックポイントを記録します。

remember({
  content: "Session complete. Done: users table, auth endpoints, product schema. Next session: order system, payment webhook. Blockers: waiting for Stripe API keys.",
  tags: ["ecommerce-api", "checkpoint", "session-1"],
  agent: "Backend Architect"
})
Enter fullscreen mode Exit fullscreen mode

次回再開時:

recall(query="checkpoint session-1")
Enter fullscreen mode Exit fullscreen mode

パターン4: バグの追跡

バグ発見時:

remember({
  content: "BUG: Refresh token not expiring after logout. Token stored in memory, not persisted. Fix: move to Redis with TTL.",
  tags: ["ecommerce-api", "bug", "auth"],
  agent: "Code Reviewer",
  severity: "high"
})
Enter fullscreen mode Exit fullscreen mode

後でバグ一覧取得:

search(tags=["bug", "ecommerce-api"])
Enter fullscreen mode Exit fullscreen mode

トラブルシューティング

メモリが永続化されない場合:

  • メモリファイルのパス(~/.mcp-memory/memories.json)を確認
  • MCPサーバーが実行中か確認
  • Claude Code/CursorのMCP設定を再確認

recallで結果が多すぎる場合:

  • より具体的なタグを利用
  • エージェント名でフィルタ
  • フレーズを引用符で囲って検索

メモリファイルが肥大化する場合:

  • 古いメモリは定期的にアーカイブ
  • rollbackで完了済みプロジェクトをクリーンアップ
  • 有効期限(expire)をメモリスキーマに追加

構築したもの

コンポーネント 目的
MCPメモリサーバー セッション間で情報を保存/取得
rememberツール 決定・成果物・引き継ぎの記録
recallツール 過去セッションからのコンテキスト検索
searchツール タグで全メモリをクエリ
rollbackツール 必要に応じて以前の状態に復元
メモリパターン 決定ログ・引き継ぎ・チェックポイント・バグ追跡

次のステップ

メモリサーバーの拡張例:

  • 埋め込み技術でセマンティック検索を追加
  • メモリの有効期限(例: 30日後アーカイブ)自動化
  • 長期セッション向けの要約機能実装

チーム全体での活用:

  • チーム用中央メモリサーバーの構築
  • プロジェクト・開発者ごとのタグ付け
  • 新規メンバー用のオンボーディングフロー作成

他ツールとの統合:

  • Gitコミット自動記録
  • プロジェクト管理ツール(Jira, Linear)との同期
  • メモリをドキュメントとしてエクスポート

よくある問題のトラブルシューティング

セッション間でメモリが永続化されない場合:

  • Claude Code起動前にMCPサーバーが動作しているか確認
  • メモリファイルパスが存在するか: ls -la ~/.mcp-memory/memories.json
  • ファイル権限の確認: chmod 644 ~/.mcp-memory/memories.json
  • ~/.claude/settings.jsonのパス設定が合っているか

recallが空の結果を返す場合:

  • クエリがタグと一致しているか確認(大文字・小文字区別あり)
  • 検索語を広げる、またはsearchでタグ検索
  • メモリが保存されたか: cat ~/.mcp-memory/memories.json
  • agentパラメータの指定を再確認

メモリファイル肥大化対策:

  • 30日以上前のメモリは自動アーカイブ機能を実装
  • pruneツールで日付範囲削除を追加
  • プロジェクト/日付ごとにファイル分割
  • 大規模用途はJSONでなくSQLite等DBを利用

サーバーが起動しない場合:

  • Node.jsバージョン確認: node --version(18以上)
  • 依存パッケージのインストール: npm install @modelcontextprotocol/sdk zod
  • サーバーコードの構文エラー確認
  • 直接実行してエラー出力を確認: node memory-server.js

複数エージェントでメモリ上書きされる場合:

  • remember時は必ずagentフィールドを指定
  • プロジェクトごとに一意なタグ設計: ["project-x", "backend", "auth"]
  • エージェント名でフィルタ取得
  • プロジェクト単位でメモリファイル分割も検討

メモリサーバーのセキュリティに関する考慮事項

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');
}
Enter fullscreen mode Exit fullscreen mode

チーム用メモリサーバー:アクセス制御

  • ツール呼び出し時にAPIキー必須化
  • ユーザーごとの名前空間実装
  • 全操作の監査ログ記録
  • リクエストのレートリミット

AIエージェントに永続メモリを実装することで、「前回のセッションからのコンテキストがありません」と言われることはなくなります。決定事項や状況を都度コピー&ペーストする手間も省け、プロジェクト全体の生産性が上がります。

これがMCPメモリの実践的な威力です。ぜひ自分のワークフローやチーム開発に取り入れてみてください。

よくある質問

MCPメモリとは何ですか?

MCPメモリは、AIエージェントがセッション間で情報を保存・取得できるプロトコル実装です。エージェントが書き込み・読み取りできる共有ノートブックの役割を果たし、会話をまたいだコンテキスト永続化が可能になります。

Claude Codeに永続メモリを設定するには?

MCPメモリサーバーをインストールし、~/.claude/settings.jsonにサーバーコマンドとパスを記載。Claude Codeを再起動すると、rememberrecallsearchrollbackツールが利用可能になります。

どのAIエージェントがMCPメモリをサポートしていますか?

MCP互換クライアント(Claude Code、Cursor、Windsurfなど)で動作するエージェントは、メモリツールを使用できます。エージェント本体のコードは不要で、プロンプト指示のみで利用可能。

エージェントの引き継ぎに最適なメモリパターンは?

remember["handoff", "project-name"]のようなタグを使い、完了した作業・保留項目・既知の問題を残します。受信エージェントはrecall(query="handoff")で取得。

MCPサーバーはどれだけのメモリを保存できますか?

実装次第。リファレンス実装は肥大化するJSONファイル方式。本番運用は有効期限・自動アーカイブ・DBバックエンド導入推奨。

チームで中央メモリサーバーを共有できますか?

はい。共有マシンやクラウドでメモリサーバーを立て、全員のクライアントが接続。プロジェクトや開発者ごとにタグ付けし、整理された取得が可能です。

メモリ呼び出しで結果が多すぎる場合は?

保存時に具体的なタグを追加。呼び出し時にエージェント名でフィルタ。フレーズを引用符で囲む。必要なら埋め込みによるセマンティック検索導入を検討。


Apidog を活用したAPI自動化・ドキュメント生成にも、このパターンをぜひ応用してください。

Top comments (0)