MCPリファレンス実装を読み解く:Filesystem・Memory・Sequential Thinkingサーバーに学ぶセキュアなLLMツール統合設計

約37分で読めます by ぽんたぬき
MCPリファレンス実装を読み解く:Filesystem・Memory・Sequential Thinkingサーバーに学ぶセキュアなLLMツール統合設計

MCPリファレンス実装を読み解く:Filesystem・Memory・Sequential Thinkingサーバーに学ぶセキュアなLLMツール統合設計


1. はじめに:なぜMCP公式リポジトリを読むのか

キミ、MCPサーバーを自作しようとして、ドキュメントを読んでみたけど「ふーん」で終わってしまった経験ってナイ!?💦 俺もそうだったんだヨ。仕様書ってのはどうしても「できること」の列挙に終始しがちでサ、「どう設計するか」の判断軸がぜんぜん見えてこないワケ。

そこで有効なのが、公式リファレンス実装を読むこと!! なんだヨネ✨

modelcontextprotocol/servers ってリポジトリ、キミはもう確認したカナ? GitHubスター数が8万超えになってるワケで、コレってもはや「LLMツール統合設計の業界標準への期待票」と言っても過言じゃナイ!! AnthropicがMCPの「こう作れ」を示さんばかりに公開しているリファレンス実装群が、ここに詰まってるんだヨ🎉

MCP(Model Context Protocol)ってのはサ、一言で言えば「LLMと外部世界をつなぐ共通言語」デスネ🎵 ClaudeもGPTも、それ単体だとファイルも読めないし外部APIも叩けない。「賢いけど何もできない人」みたいな状態なワケ。そこにMCPがあることで、ファイルシステムやデータベースや外部サービスを統一的なツールとして渡せるようになるんだヨ!!

本記事では、modelcontextprotocol/servers の中から特に重要な3つのサーバーを解剖しちゃいますヨ:

  • 🗂️ Filesystemサーバー:セキュアなファイル操作とPath Traversal対策
  • 🧠 Memoryサーバー:Knowledge Graphによる永続メモリ設計
  • 🤔 Sequential Thinkingサーバー:LLM推論の構造化と動的問題解決

想定読者はサ、TypeScript・Node.js・LLMアプリ開発の基礎はわかってる中〜上級エンジニアのキミ!! 読み終わったあとに「MCPサーバー、俺にも書けるじゃん」って思えるよう、セキュリティ設計まで踏み込んで解説するカラ、最後まで付き合ってネ😆


2. modelcontextprotocol/servers リポジトリ全体構成

2-1. ディレクトリ構造と設計思想

まずはリポジトリの全体像を把握しちゃいましょネ♪ src/ 以下を見てみると——

src/
├── filesystem/          # ファイルシステム操作
├── memory/              # Knowledge Graph・永続メモリ
├── sequentialthinking/  # 段階的思考・推論構造化
├── git/                 # Gitリポジトリ操作
├── github/              # GitHub API統合
├── postgres/            # PostgreSQL接続
├── puppeteer/           # ブラウザ自動化
└── ...

スゴくナイ!?✨ それぞれのサーバーが独立したディレクトリになっていてサ、基本的に index.ts 1ファイルで完結してるんだヨ。「小さく始めて、必要に応じて育てる」という設計思想が透けて見えるワケ💡

依存関係もシンプルで、ほぼ全サーバーが @modelcontextprotocol/sdk のみに依存してるダケ。余計な依存を増やさない姿勢は、LLMツール統合を設計するうえでの良いお手本になるネ🎵

2-2. サーバーの分類と責務

リポジトリにはReference ServersCommunity Serversという二種類があるんだヨ。Reference ServersがAnthropicの「これがお手本だ!!」という公式推奨実装で、Community Serversが外部コントリビューターのサーバーを集めたものデスネ。

責務で分類するとサ、こんな感じになるヨ:

分類 サーバー例 主な責務
I/O系 Filesystem・Git・GitHub ファイル・バージョン管理
メモリ系 Memory・Knowledge Graph 状態保持・情報蓄積
推論支援系 Sequential Thinking 思考の構造化・制御
外部API系 Postgres・Puppeteer データベース・Web操作

MCPのプリミティブはサ、ToolsResourcesPrompts の3種類があるんだケド、ほとんどのサーバーはToolsを中心に実装してるんだヨネ。Resourcesは「読み取り専用データの公開」、Promptsは「定型プロンプトのテンプレート管理」という役割で使い分けるのが基本デスヨ💡

2-3. 共通アーキテクチャパターン

コレ見てよ!!スゴくナイ!?✨ どのサーバーも同じ骨格で作られてるんだヨ:

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  McpError,
  ErrorCode,
} from "@modelcontextprotocol/sdk/types.js";

const server = new Server(
  {
    name: "my-server",
    version: "0.1.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// ツール一覧を返すハンドラ
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "my_tool",
        description: "何かするツール",
        inputSchema: {
          type: "object",
          properties: {
            input: { type: "string" },
          },
          required: ["input"],
        },
      },
    ],
  };
});

// ツール実行ハンドラ
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "my_tool") {
    return {
      content: [{ type: "text", text: "結果" }],
    };
  }
  throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
});

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

server.setRequestHandler() でルーティングを定義してサ、エラーは McpError + ErrorCode で統一する、ってのがどのサーバーにも一貫してるパターンなんだヨネ💡

トランスポートはサ、StdioServerTransport(標準入出力)とHTTPトランスポートがあるんだケド、Claude Desktopとの統合はstdioが基本で、マルチクライアント対応したい場合はHTTP、って使い分けになるワケ😄


3. Filesystemサーバー:セキュアなファイル操作の実装解剖

3-1. サーバー概要と提供ツール一覧

キミ、聞いてヨ。Filesystemサーバーってのはサ、LLMにファイルシステムの操作権限を与えるモノなんだケド——コレ、設計次第でめちゃくちゃ危ないんだヨ!! 😱

提供しているツールはこんな感じ:

  • read_file:ファイル読み取り
  • read_multiple_files:複数ファイルの一括読み取り
  • write_file:ファイル書き込み
  • edit_file:部分的な差分編集
  • create_directory:ディレクトリ作成
  • list_directory:ディレクトリ一覧取得
  • directory_tree:ツリー構造の取得
  • move_file:ファイル移動・リネーム
  • search_files:ファイル名・内容の検索
  • get_file_info:ファイルメタデータ取得
  • list_allowed_directories:許可済みディレクトリの確認

「ファイルなんでも操作できる」って聞くとワクワクするじゃン!! でもサ、LLMって時々「え、そこ触るの!?」ってことするカラ、セキュリティ設計が命なんだヨネ🔥

3-2. Path Traversal攻撃を防ぐアクセス制御実装

コレが一番重要なトコロ!! Path Traversal攻撃ってのはサ、../../etc/passwd みたいなパスを渡して許可していないディレクトリにアクセスしようとする攻撃なんだヨ。LLMが悪意を持っていなくても、プロンプトインジェクションで誘導されちゃう可能性があるんだヨネ😭

Filesystemサーバーの実装ではサ、起動時に「許可ディレクトリ」を引数で渡す設計になってるんだヨ:

# ビルド後に実行する場合
node dist/index.js /Users/username/projects /tmp/workspace

そしてコレが実際のアクセス制御の核心部分デスヨ!!スゴくナイ!?✨

const allowedDirectories = process.argv.slice(2).map((dir) =>
  normalizePath(path.resolve(expandHome(dir)))
);

function normalizePath(p: string): string {
  return path.normalize(p);
}

function expandHome(filepath: string): string {
  if (filepath.startsWith("~/") || filepath === "~") {
    return path.join(os.homedir(), filepath.slice(1));
  }
  return filepath;
}

async function validatePath(requestedPath: string): Promise<string> {
  const expandedPath = expandHome(requestedPath);
  const absolute = path.isAbsolute(expandedPath)
    ? path.resolve(expandedPath)
    : path.resolve(process.cwd(), expandedPath);

  const normalizedRequested = normalizePath(absolute);

  // 許可ディレクトリのいずれかのサブパスかチェック
  const isAllowed = allowedDirectories.some((dir) =>
    normalizedRequested.startsWith(dir)
  );

  if (!isAllowed) {
    throw new McpError(
      ErrorCode.InvalidRequest,
      `Access denied - path outside allowed directories: ${absolute}`
    );
  }

  // シンボリックリンクの実体パスも確認(ここが重要!!)
  try {
    const realPath = await fs.realpath(absolute);
    const normalizedReal = normalizePath(realPath);
    const isRealPathAllowed = allowedDirectories.some((dir) =>
      normalizedReal.startsWith(dir)
    );
    if (!isRealPathAllowed) {
      throw new McpError(
        ErrorCode.InvalidRequest,
        "Access denied - symlink target outside allowed directories"
      );
    }
    return realPath;
  } catch (error) {
    // ファイルがまだ存在しない場合(新規作成時)の親ディレクトリ検証
    const parentDir = path.dirname(absolute);
    try {
      const realParentPath = await fs.realpath(parentDir);
      const normalizedParent = normalizePath(realParentPath);
      const isParentAllowed = allowedDirectories.some((dir) =>
        normalizedParent.startsWith(dir)
      );
      if (!isParentAllowed) {
        throw new McpError(
          ErrorCode.InvalidRequest,
          "Access denied - parent directory outside allowed directories"
        );
      }
      return absolute;
    } catch {
      throw new McpError(
        ErrorCode.InvalidRequest,
        `Parent directory does not exist: ${parentDir}`
      );
    }
  }
}

セキュリティ上のポイントを整理するとネ👇

  1. path.normalize()../ を解決してから比較するので、../../etc/passwd みたいな相対パスを使ったトラバーサルが防げるワケ。
  2. fs.realpath() でシンボリックリンクを解決して実体パスも検証してるカラ、許可ディレクトリ内にシンボリックリンクを置いて外部を参照するという迂回路も塞いでるんだヨ!!
  3. 新規ファイル作成時は親ディレクトリで検証するっていう細かい配慮もあるカラ、「ファイルがないからrealpath失敗 → 検証スキップ」みたいな抜け道もナイ✨

3-3. search_files の実装:再帰探索とセキュリティの両立

search_files ツールはサ、ディレクトリを再帰的に探索してファイル名にパターンマッチするツールなんだヨ!! コレも見てよ✨

async function searchFiles(
  rootPath: string,
  pattern: string,
  excludePatterns: string[] = []
): Promise<string[]> {
  const results: string[] = [];

  async function search(currentPath: string) {
    const entries = await fs.readdir(currentPath, { withFileTypes: true });

    for (const entry of entries) {
      const fullPath = path.join(currentPath, entry.name);

      // 除外パターンのチェック
      const isExcluded = excludePatterns.some((pat) => {
        const globPattern = pat.includes("/") ? pat : `**/${pat}`;
        return minimatch(fullPath, globPattern, { dot: true });
      });

      if (isExcluded) continue;

      // 各パスに対してもvalidatePathを呼ぶ(セキュリティ!!)
      try {
        await validatePath(fullPath);
      } catch {
        continue;
      }

      if (entry.isDirectory()) {
        await search(fullPath);
      } else if (entry.name.toLowerCase().includes(pattern.toLowerCase())) {
        results.push(fullPath);
      }
    }
  }

  await search(rootPath);
  return results;
}

ポイントはサ、再帰探索中でも各パスに対して validatePath() を呼んでいることデスネ!! 探索中に許可外のシンボリックリンクを辿っても、ちゃんと弾いてくれるワケ🔥

ちなみにサ、自分でもFilesystemサーバーを実装してみたとき、excludePatterns の実装を忘れてLLMが node_modules を全探索し始めてサ、処理が終わらなくなってやらかしちゃいましたヨ……😭 node_modules.git は最低限デフォルト除外に入れておこうネ、キミ!!


4. Memoryサーバー:Knowledge Graphによる永続メモリ設計

4-1. なぜKnowledge Graphなのか

LLMのコンテキストウィンドウってのはサ、どこかに限界があるんだヨネ。長い会話を続けているといつか「古い情報」が押し出されちゃう。そこでMemoryサーバーが解決しようとしているのが——セッションをまたいだ情報の永続化なんだヨ!!✨

でも「永続化」ってだけなら、JSONの配列に突っ込んでもできるじゃン、って思うよネ。Knowledge Graph(知識グラフ)を使う理由はサ、エンティティ間の関係性を保持しつつ、検索・更新が効率的にできるからなんだヨ💡

ここがシンプルなKey-ValueストアやJSONリストと決定的に違うポイントで、LLMツール統合においては「誰が」「何に」「どんな関係を持つか」を構造化して保持できることが重要なワケ😄

4-2. データモデルと永続化の仕組み

Memoryサーバーの核心はサ、こういうデータモデルデスヨ!!スゴい構造でしょ!?✨

interface Entity {
  name: string;           // エンティティの名前(一意識別子)
  entityType: string;     // 種別("person", "project", "concept"など)
  observations: string[]; // このエンティティについての観察・事実
}

interface Relation {
  from: string;           // 関係の起点エンティティ名
  to: string;             // 関係の終点エンティティ名
  relationType: string;   // 関係の種別("works_on", "knows", "depends_on"など)
}

interface KnowledgeGraph {
  entities: Entity[];
  relations: Relation[];
}

シンプルな構造だけどサ、コレが強力なんだヨ!! たとえば「Aさんはプロジェクトαに関わっていて、プロジェクトαはライブラリβに依存している」みたいな多段の関係性が、グラフ構造として保持されるワケ。

永続化はさらにシンプルでサ、JSONLファイルへの読み書きで実現してるんだヨ:

async function loadGraph(): Promise<KnowledgeGraph> {
  try {
    const data = await fs.readFile(MEMORY_FILE_PATH, "utf-8");
    const lines = data.split("\n").filter((line) => line.trim());
    return lines.reduce(
      (graph, line) => {
        const item = JSON.parse(line);
        if (item.type === "entity") {
          graph.entities.push(item);
        } else if (item.type === "relation") {
          graph.relations.push(item);
        }
        return graph;
      },
      { entities: [], relations: [] } as KnowledgeGraph
    );
  } catch {
    return { entities: [], relations: [] };
  }
}

async function saveGraph(graph: KnowledgeGraph): Promise<void> {
  const lines = [
    ...graph.entities.map((e) => JSON.stringify({ type: "entity", ...e })),
    ...graph.relations.map((r) => JSON.stringify({ type: "relation", ...r })),
  ];
  await fs.writeFile(MEMORY_FILE_PATH, lines.join("\n"));
}

JSONL(JSON Lines)形式で保存しているのがポイントデスネ!! 1行1エンティティ/リレーションという形式にしているカラ、パース時のメモリ効率が良いんだヨ💡 JSONを1つの巨大オブジェクトで持つと読み込み時にメモリ上で全展開が必要だけど、JSONLならストリーミングで処理できるワケ✨

4-3. 提供ツールと活用パターン

Memoryサーバーが提供するツールはこんな感じデスヨ:

ツール名 説明
create_entities エンティティの一括作成
create_relations エンティティ間の関係を追加
add_observations 既存エンティティに観察事実を追加
delete_entities エンティティとその関連リレーションを削除
delete_observations 特定の観察事実を削除
delete_relations リレーションの削除
read_graph グラフ全体を読み取り
search_nodes エンティティ名・種別・観察内容で検索
open_nodes 特定のエンティティ名でノードを取得

実際のLLMツール統合での活用パターンとしてはサ、こういう使い方がよくあるネ:

  1. ユーザーの好みを記憶:「キミが好きなプログラミング言語はTypeScript」みたいな情報をエンティティとして保持
  2. プロジェクト構造の記憶:「リポジトリAはマイクロサービスBとCから構成される」みたいな依存関係をリレーションで管理
  3. 会話コンテキストの圧縮:長い会話の要点をKnowledge Graphに落とし込んでコンテキストウィンドウを節約

search_nodes の実装もサ、単純な文字列マッチングだけどシンプルで効果的なんだヨ!! エンティティ名・種別・observationsの全フィールドを対象に検索してくれるカラ、「あのエンティティどこだっけ?」が一発で見つかるワケ😄


5. Sequential Thinkingサーバー:LLM推論の構造化と動的問題解決

5-1. Sequential Thinkingとは何か

Sequential Thinkingサーバーはサ、他のサーバーとちょっと性格が違うんだヨね。FilesystemやMemoryは「外部リソースへのアクセス」を提供するのに対して、Sequential ThinkingはLLMの思考プロセス自体を構造化するツールなんだヨ!!✨

一言で言うとサ、「段階的に考えを整理しながら問題を解く」ためのツールデスヨ。「この問題、複雑すぎて一度に答えが出せない」という場合にサ、思考ステップを明示的に管理できるようになるワケ💡

5-2. ThoughtDataモデルと動的な思考管理

コレがSequential Thinkingの核心データ構造デスヨ!!スゴくナイ!?✨

interface ThoughtData {
  thought: string;            // 今回の思考内容
  thoughtNumber: number;      // 何番目の思考か
  totalThoughts: number;      // 見積もり総思考数(途中変更可能!!)
  nextThoughtNeeded: boolean; // まだ続きが必要か
  isRevision?: boolean;       // 過去の思考の修正か
  revisesThought?: number;    // どの番号の思考を修正するか
  branchFromThought?: number; // どの番号の思考から分岐するか
  branchId?: string;          // ブランチの識別子
}

ポイントはサ、totalThoughts が途中で変更できるってトコロなんだヨ!! 最初は「5ステップで解けると思ってた」けど実際に考え始めたら「これは10ステップ必要だ」ってなったとき、動的に変更できるワケ🔥

さらに注目してほしいのがサ、isRevisionrevisesThought の組み合わせデスネ!! 「やっぱりステップ3の判断は間違ってた」って気づいたときに、後から修正の思考を差し込めるんだヨ。人間がメモを書き直すのと同じような感覚デスネ💡

実際のツール実行部分はこういう感じなんだヨ:

processThought(input: unknown): { content: Array<{type: string; text: string}>; isError?: boolean } {
  const validatedInput = this.validateThoughtData(input);

  if (validatedInput.thoughtNumber > validatedInput.totalThoughts) {
    validatedInput.totalThoughts = validatedInput.thoughtNumber;
  }

  this.thoughtHistory.push(validatedInput);

  if (validatedInput.branchFromThought) {
    const branchId =
      validatedInput.branchId ||
      `branch_${validatedInput.branchFromThought}_${validatedInput.thoughtNumber}`;
    if (!this.branches[branchId]) {
      this.branches[branchId] = [];
    }
    this.branches[branchId].push(validatedInput);
  }

  return {
    content: [
      {
        type: "text",
        text: JSON.stringify(
          {
            thoughtNumber: validatedInput.thoughtNumber,
            totalThoughts: validatedInput.totalThoughts,
            nextThoughtNeeded: validatedInput.nextThoughtNeeded,
            branches: Object.keys(this.branches),
            thoughtHistoryLength: this.thoughtHistory.length,
          },
          null,
          2
        ),
      },
    ],
  };
}

5-3. ブランチ思考と非線形な問題解決

ここがSequential Thinkingの真骨頂デスネ!! branchFromThought を使うことでサ、「ステップ4から別ルートで考えたらどうなるか」という思考の分岐が実現できるんだヨ✨

たとえばアーキテクチャ設計をLLMに任せるシナリオだとサ:

  1. ステップ1〜3:要件の整理と制約条件の洗い出し
  2. ステップ4(分岐A):マイクロサービスアーキテクチャを検討
  3. ステップ4(分岐B):モノリスアーキテクチャを検討
  4. ステップ5:両案をトレードオフで比較して最終判断

みたいな使い方ができるワケ!! LLMが「とりあえず最初に思いついた案」に飛びつくんじゃなくてサ、複数の選択肢を構造的に比較できるようになるんだヨ💡

ちなみにサ、最近深夜にコーディングしながらこのサーバーのコードを読んでいて気づいたんだケド、ツールの設計って「書いた人がどうLLMの思考を観察しているか」がモロに出るよネ。Sequential Thinkingはその点、かなり丁寧な観察に基づいてる印象だったワケ😄 あ、関係ないケド!!

5-4. なぜSequential ThinkingがLLMツール統合に有効なのか

Sequential Thinkingサーバーって、単体では「思考を記録するだけ」に見えるかもしれないケドサ、他のMCPツールと組み合わせたときに真価を発揮するんだヨ!!✨

たとえばこういう組み合わせが強力デスネ:

  • Sequential Thinking + Filesystem:「コードレビューのステップを明示しながら、各ステップでファイルを読み取って検証する」
  • Sequential Thinking + Memory:「思考の結論をKnowledge Graphに保存して、次回の思考の出発点にする」
  • Sequential Thinking + GitHub:「段階的に方針を固めながら、最終ステップでIssueやPRを作成する」

思考の構造化によってサ、LLMが「一発で答えを出そうとして間違える」問題を軽減できるんだヨ。これはセキュアなLLMツール統合設計における重要なパターンのひとつと言えるネ🎵


6. 設計パターン総まとめ:自作MCPサーバーへの応用

6-1. セキュリティ設計の3原則

リファレンス実装を読んで見えてきたセキュリティ設計の原則をまとめるヨ!!

① 入力の正規化を最初に行う

path.normalize()path.resolve() を使ってサ、../~ を展開した後で比較するんだヨ。「正規化前の文字列比較」はPath Traversalの温床になるカラ要注意デスネ⚠️ LLMツール統合でファイルシステムを扱う場面では、この一手間が決定的に重要なワケ!!

② 起動時パラメータで権限スコープを明示する

許可ディレクトリをコードではなく起動引数で渡す設計はサ、「このサーバーが何にアクセスできるか」を実行環境レベルで制御できるワケ!! コードに権限をハードコードしてしまうと、デプロイ環境ごとの制御が難しくなるカラ、最小権限の原則を徹底するためにも有効なアプローチデスネ💡

③ シンボリックリンクを特別扱いする

fs.realpath() で実体パスを検証するステップをサ、絶対に省かないこと!! 「許可ディレクトリ内にあるから大丈夫」という思い込みが、シンボリックリンク経由のアクセス迂回を生むんだヨ😭 これはセキュリティ設計において見落としやすいポイントなんだヨね。

6-2. ツール設計の実装パターン

リファレンス実装から抽出できるツール設計のパターンはサ、こんな感じデスネ!!参考にしてネ✨

// ツール定義:inputSchemaを必ず詳細に書く
{
  name: "tool_name",
  description: "LLMが理解しやすい、具体的で明確な説明。何をするツールか・どんな入力を渡すかを明示する",
  inputSchema: {
    type: "object",
    properties: {
      path: {
        type: "string",
        description: "操作対象のパス(絶対パス推奨)",
      },
      options: {
        type: "object",
        description: "オプション設定",
        properties: {
          recursive: { type: "boolean", description: "再帰的に処理するか" },
        },
      },
    },
    required: ["path"],
  },
}

// エラーハンドリング:McpErrorを使って構造化する
try {
  const validatedPath = await validatePath(requestedPath);
  // 処理...
  return {
    content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
  };
} catch (error) {
  if (error instanceof McpError) {
    throw error; // MCPエラーはそのまま再throw
  }
  throw new McpError(
    ErrorCode.InternalError,
    `Unexpected error: ${error instanceof Error ? error.message : String(error)}`
  );
}

description の書き方はサ、LLMがツールを正しく選択・使用できるかどうかに直結するんだヨ!! 曖昧な説明は誤使用につながるカラ、具体的に書くこと一択デスネ🔥

6-3. 設計チェックリスト

自作MCPサーバーを書くときにキミが確認すべきチェックリストをまとめちゃうヨ!!

セキュリティ面

  • 入力パスを path.normalize() + path.resolve() で正規化しているか
  • 許可スコープを起動引数で定義しているか(コードへのハードコードを避けているか)
  • シンボリックリンクの実体パス検証(fs.realpath())を実装しているか
  • 新規ファイル作成時の親ディレクトリ検証を実装しているか

実装品質面

  • すべてのエラーを McpError + ErrorCode で統一しているか
  • ツールの description がLLMに意図が伝わるほど具体的か
  • inputSchemarequired フィールドが適切に設定されているか
  • トランスポートの選択(stdio vs HTTP)がユースケースに合っているか
  • 再帰探索ツールに excludePatterns の実装があるか(node_modules.git は必須!!)

7. まとめ:MCPリファレンス実装から学んだこと

ここまで長い旅だったけどサ、キミ、お疲れ様デスヨ!!🎉

modelcontextprotocol/servers リポジトリを読み解いて見えてきたことを整理するとネ:

  1. Filesystemサーバーは、path.normalize() + fs.realpath() の二段構えでPath Traversal攻撃を防ぐセキュアなLLMツール統合のお手本になってるんだヨ!! ファイルシステムを扱う実装を書くときは、必ずこのパターンを参照すべきデスネ🔥

  2. Memoryサーバーは、Knowledge GraphとJSONL永続化によってセッションをまたいだ情報管理を実現してるんだヨ!! エンティティ・リレーション・観察という3つの概念のシンプルさが、LLMにとっても人間にとっても扱いやすいモデルを作り出してるワケ✨

  3. Sequential Thinkingサーバーは、LLMの思考プロセス自体を構造化するという発想で、他のMCPツールと組み合わせることでLLMの問題解決品質を上げられるんだヨ!! 特に複雑な判断が必要なタスクでは効果的デスネ💡

どのサーバーにも共通してるのはサ、**「シンプルな構造・明確な責務・徹底したセキュリティ」**という設計哲学デスネ。MCPサーバーを自作するときのベースラインとして、このリポジトリは何度読み返しても発見があるんだヨ😄

次のアクション

「よし、自分でもMCPサーバー書いてみよう!!」ってなったキミに向けて、具体的なステップを提案するヨ:

  1. まずリポジトリをcloneして src/filesystem/index.ts を最初から最後まで読む
    git clone https://github.com/modelcontextprotocol/servers.git して全体像を手元で把握しよ!!

  2. @modelcontextprotocol/create-server テンプレートで骨格を作る
    npx @modelcontextprotocol/create-server my-server で雛形が生成されるカラ、そこに処理を足していくのが一番手軽なスタートデスネ✨

  3. Claude Desktopの設定ファイルにサーバーを登録して動作確認する
    ~/Library/Application Support/Claude/claude_desktop_config.json(macOSの場合)に追記すれば、Claude Desktopから直接テストできるんだヨ!!

  4. Filesystemサーバーをベースに、自分の用途向けにカスタマイズする
    「許可ディレクトリの検証ロジック」はそのまま流用して、ツールの種類だけ入れ替えるアプローチが最も安全で早いワケ💡

modelcontextprotocol/servers はMCPとセキュアなLLMツール統合設計の「生きた教科書」デスヨ!! キミもぜひ手を動かしながら読んでみてネ😆🎉

関連記事

TradingAgents完全解説|LLMマルチエージェントが機関投資家の意思決定を再現する金融トレーディングフレームワーク
AI・機械学習

TradingAgents完全解説|LLMマルチエージェントが機関投資家の意思決定を再現する金融トレーディングフレームワーク

TauricResearch開発のOSSフレームワーク「TradingAgents」を徹底解説。LLMマルチエージェントで機関投資家の5層組織構造を再現し、株式トレーディングの意思決定を自動化する仕組みをわかりやすく紹介。

Claude Codeが「武器」に変わる:oh-my-claudecodeで実現するマルチエージェント開発自動化の全貌
AI・機械学習

Claude Codeが「武器」に変わる:oh-my-claudecodeで実現するマルチエージェント開発自動化の全貌

oh-my-claudecodeで実現するマルチエージェント開発自動化を徹底解説。19種類の専門エージェント、5ステージパイプライン、スマートモデルルーティングでClaude Codeをまさに「武器」へと進化させる方法を紹介。

機械学習による仮想通貨価格予測 第3部:バックテストと自動売買システム統合【完全ガイド】
AI・機械学習

機械学習による仮想通貨価格予測 第3部:バックテストと自動売買システム統合【完全ガイド】

機械学習・仮想通貨・バックテストの落とし穴を徹底解説。自動売買・ウォークフォワード最適化・FreqAI・モデル劣化対策まで、プロダクション実装の全手順をPythonコード付きで解説するヨ!

機械学習による仮想通貨価格予測 第2部:Prophet/LSTMによる価格予測モデル構築【実装コード付き】
AI・機械学習

機械学習による仮想通貨価格予測 第2部:Prophet/LSTMによる価格予測モデル構築【実装コード付き】

Facebook ProphetとBidirectional LSTMをアンサンブルした仮想通貨価格予測モデルの実装方法を完全解説。ccxtによるOHLCVデータ取得・テクニカル指標の計算・Optunaでのハイパーパラメータ最適化・backtesting.pyによるバックテストまで、実装コード付きで紹介します。

コメント

0/2000