Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

filesystem: search_files does not expand non-wildcard excludePatterns like directory_tree does

オープン 初心者向け
#5,216 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
72/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
node.js, typescript
領域
backend, testing

調査の方向性

src/filesystem/lib.ts の searchFilesWithValidation と src/filesystem/server.ts の buildTree を読み、excludePatterns の照合方法を比較してください。トップレベルとネストされたディレクトリで、パスを含まない除外指定を扱うテストを src/filesystem/__tests__/lib.test.ts と src/filesystem/__tests__/server-tools.test.ts に追加してください。search_files が一致するディレクトリのサブツリーをスキップし、directory_tree と同じ動作をすれば完了です。

索引モデルが issue の本文から書いたものです。

説明

Summary

While auditing src/filesystem on v2.0.0 (origin/main) following the #4857 spec refactor, I found a behavioral mismatch in how excludePatterns is evaluated between directory_tree (src/filesystem/server.ts) and search_files (src/filesystem/lib.ts).

When an LLM or user passes a bare directory or file name in excludePatterns (for example, ["node_modules", ".git"]), directory_tree excludes both the directory and its entire subtree, whereas search_files still traverses into the excluded directory and returns all files inside it.

Server & Environment

  • Server: filesystem (@modelcontextprotocol/server-filesystem v2.0.0 / origin/main)
  • Files: src/filesystem/server.ts (buildTree) vs. src/filesystem/lib.ts (searchFilesWithValidation)
  • Protocol era / transport: Both 2026-07-28 and 2025-era over stdio / in-memory client transport

Reproduction / Root Cause in v2/main

  1. In directory_tree (src/filesystem/server.ts, lines 515–529), buildTree checks whether an exclusion pattern contains *. If it does not, it automatically expands the pattern to match nested paths and subtrees (**/${pattern} and **/${pattern}/**), and skips recursing into the excluded directory:
const shouldExclude = excludePatterns.some((pattern) => {
  if (pattern.includes("*")) {
    return minimatch(relativePath, pattern, { dot: true });
  }
  // For files: match exact name or as part of path
  // For directories: match as directory path
  return (
    minimatch(relativePath, pattern, { dot: true }) ||
    minimatch(relativePath, `**/${pattern}`, { dot: true }) ||
    minimatch(relativePath, `**/${pattern}/**`, { dot: true })
  );
});
if (shouldExclude) continue;
  1. In search_files (src/filesystem/lib.ts, lines 397–413), searchFilesWithValidation evaluates minimatch(relativePath, excludePattern, { dot: true }) directly without the non-wildcard expansion:
const relativePath = path.relative(rootPath, fullPath);
const shouldExclude = excludePatterns.some((excludePattern) =>
  minimatch(relativePath, excludePattern, { dot: true }),
);

if (shouldExclude) continue;
What happens when a caller passes excludePatterns: ["node_modules"] or ["sub"]:
  • At node_modules (top-level): relativePath is "node_modules". minimatch("node_modules", "node_modules") is true, so if (shouldExclude) continue skips recursing into top-level node_modules!
  • At packages/app/node_modules (nested directory): relativePath is "packages/app/node_modules". minimatch("packages/app/node_modules", "node_modules") is false! search_files enters packages/app/node_modules and traverses every file inside it.
  • When excludePatterns: ["node_modules/*"] or ["**/node_modules"] (without trailing /**) is passed: Even if a pattern matches files inside a directory, search_files still wastes I/O recursing unless the directory entry itself matches shouldExclude.

Expected vs. Actual Behavior

  • Expected: Passing excludePatterns: ["node_modules", ".git"] (or a bare filename/directory name without *) to search_files should behave identically to directory_tree: any nested directory or file matching pattern, **/${pattern}, or **/${pattern}/** is excluded and its directory subtree is not traversed.
  • Actual: directory_tree excludes nested packages/app/node_modules, while search_files traverses into packages/app/node_modules and returns matches from inside it unless the caller explicitly writes **/node_modules/**.

Prompt to Reproduce Fix in the Agentic Workflow

Per CONTRIBUTING.md, here is the exact prompt to fix and test this in the factory workflow:

Unify `excludePatterns` matching between `directory_tree` (`src/filesystem/server.ts`) and `search_files` (`src/filesystem/lib.ts`):

1. Extract a shared helper (or update `searchFilesWithValidation` in `src/filesystem/lib.ts` to match `buildTree` in `src/filesystem/server.ts`) so that when an entry in `excludePatterns` does not contain `*`, it matches `minimatch(relativePath, pattern, { dot: true }) || minimatch(relativePath, `**/${pattern}`, { dot: true }) || minimatch(relativePath, `**/${pattern}/**`, { dot: true })`.
2. Add a protocol-level test in `src/filesystem/__tests__/server-tools.test.ts` (and unit test in `src/filesystem/__tests__/lib.test.ts`) verifying that `search_files` with a bare name in `excludePatterns` (e.g. `excludePatterns: ["ignored_dir"]`) excludes both top-level `ignored_dir/file.txt` and nested `nested/ignored_dir/file.txt`, matching `directory_tree`'s behavior.
3. Run `npm run format` and `npm run local:gate`.
主要言語
TypeScript
スター
91.4k
フォーク
11.8k
平均マージ
7時間 36分
マージ済み PR(30日)
126

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

modelcontextprotocol/servers のほかの issue

modelcontextprotocol/servers の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。