Zenn
📚

[Cline] Memory Bank を一括読み込みする MCP を作ってみた

2025/03/29に公開
2

TL;DR

  • Cline の Memory Bank は複数ファイルの読み込みが必要で、毎チャット5回程度のチャットのラリーが発生する
  • MCP で簡単なツールを作り、一回のやり取りで前ファイルの読み込みが可能になった。
  • MCP は一種の Custom Instructions のようにも使える

課題

Cline で Memory Bank という、Cline にプロジェクトの知識を外部化して持たせるプラクティスがあるが、これをやっていると毎回チャットの初めにファイルの読み込みためのラリーが発生してしまいます。

これは Cline が使える read_file というツールが単一のファイル読み込みで、かつ、Cline は一回のチャットのラリーで一つのツールを一回しか使えないからです。

https://github.com/cline/cline/blob/7a1e757a2cc1987751e4ff9357070ff7770c3996/src/core/prompts/system.ts#L366

解決策

そこで今回は MCP で Memory Bank の一括読み込み用のツールを作ることで、このやりとりが一回で済むように作ってみました。
このスクリーンショットのように、チャットの一番初めに MCP を使って一括で Memory Bank のファイルを読み込んでくれるようになりました。

コード例

複雑なことはやっていませんがコード例を載せておきます。Deno で fastmcp を使って書いてます。

#!/usr/bin/env deno run --allow-read
import * as fs from "node:fs/promises";
import * as path from "node:path";
import { FastMCP } from "npm:fastmcp@1.20.5";
import { z } from "npm:zod@3.24.2";

// MCPサーバー設定
const server = new FastMCP({
	name: "Memory Bank Loader",
	version: "1.0.0",
});

// ツール定義
server.addTool({
	name: "get_memory_bank",
	description:
		"指定されたメモリーバンク用のディレクトリ(絶対パス指定)のファイルをすべて読み込み、一つの文字列として返す",
	parameters: z.object({
		directory: z.string().optional(), // ディレクトリのみのパラメータ
	}),
	execute: async (params) => {
		try {
			// パラメータで指定されたディレクトリか、デフォルト値を使用
			const memoryBankDir = params.directory;
			if (!memoryBankDir) {
				throw new Error("ディレクトリが指定されていません");
			}
			const contents: string[] = [];

			// ディレクトリ内のファイル一覧を取得
			const files = await fs.readdir(memoryBankDir);

			// ファイルリストを保持する配列
			const fileList = [];

			// ファイルの内容を読み込む
			for (const filename of files) {
				try {
					const filePath = path.join(memoryBankDir, filename);
					// ファイルの情報を取得
					const stat = await fs.stat(filePath);

					// ディレクトリの場合はスキップ
					if (stat.isDirectory()) {
						continue;
					}

					// ファイルリストに追加
					fileList.push(filename);

					const content = await fs.readFile(filePath, "utf-8");
					contents.push(`# ${filePath}\n\n${content}\n\n---\n\n`);
				} catch (fileError) {
					console.error(`Error reading file ${filename}:`, fileError);
					contents.push(
						`# ${filename}\n\n**ファイルの読み込みに失敗しました**\n\n---\n\n`,
					);
				}
			}

			return JSON.stringify({
				contents: contents.join(""),
				files: fileList,
			});
		} catch (error) {
			console.error("Error in get_memory_bank:", error);
			return JSON.stringify({
				error: "メモリーバンクファイルの読み込みに失敗しました",
				message: error instanceof Error ? error.message : String(error),
			});
		}
	},
});

// サーバー起動
server.start({
	transportType: "stdio",
});

console.info("Memory Bank Loader MCP サーバーが起動しました");

まとめ

Cline などの AI 開発エージェントは、 read_file などの汎用的なツールを持っていますが、ある程度作業のフローが固定化した時に Memory Bank の読み込みのように非効率になる場合があります。

今回追加した Memory Bank Loader は実質 read_file を一括で読んでいるだけに過ぎませんが、Cline に「Memory Bank Loader とい MCP が存在する」と伝えることで、効率的に作業してもらえるようになりました。実質 MCP を作業フローの Custom Instructions として活用したような気がしてます。こういう手法もアリかも

2

Discussion

ログインするとコメントできます