[BUG] Custom fileSuggestion command: .map() passes the array index as each file's score, so MCP resources outrank every file except the first
Preflight Checklist
- [x] I have searched existing issues — the symptom was reported in #30747 (auto-closed as a duplicate of the unrelated #22737), #22021, #17681 and #36329, but the root cause below has never been identified and no open issue tracks it
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code (2.1.199)
What's Wrong?
When fileSuggestion is set to a custom command, the @ picker ranks every fuzzy-matching MCP resource and agent above every file the command returns, except the first one. With a resource-heavy MCP server connected (e.g. Figma, which publishes ~100 resources: docs, skills, skill references), a query like @author renders:
app/models/author.rb ← file #1 from the custom command
figma:skill://figma/figma-use/SKILL.md ← MCP resource
figma:file://figma/docs/… ← MCP resource
figma:skill://figma/figma-generate-… ← MCP resource
app/models/author_follow.rb ← file #2, buried
app/helpers/authors_helper.rb ← file #3
…
The custom command's output is correct and correctly ordered (verified by running it directly). The built-in file picker does not exhibit this — it's specific to fileSuggestion: { "type": "command" }.
Root cause (verified against the 2.1.199 binary)
The suggestion object builder takes an optional score:
function har(e, t) {
return { id: `file-${e}`, displayText: e, metadata: t !== void 0 ? { score: t } : void 0 }
}
The built-in index path calls it correctly with a real fuzzy score:
e.search(t, V4o).map((r) => har(r.path, r.score))
But the custom-command path passes the function reference straight to .map():
if (type === "command") { ... return (await J4o(s)).slice(0, V4o).map(har) }
Array.prototype.map invokes the callback as (element, index, array), so t receives the array index: file #1 gets score: 0, file #2 gets score: 1, file #3 gets score: 2, … (the classic ['1','10','11'].map(parseInt) footgun).
Those scores then enter the unified @ mention merge, which sorts ascending on a 0–1 scale:
for (let f of l) p.push({ source: f, score: f.score ?? 0.5 }); // files
// MCP resources / agents matched with Fuse.js:
new Bee(d, { includeScore: true, threshold: 0.6, keys: [...] }).search(t, { limit: msn });
let h = g.item.type === "mcp_resource" ? 0.15 : 0; // resource penalty
p.push({ source: g.item, score: (g.score ?? 0.5) + h });
p.sort((f, m) => f.score - m.score);
Fuse scores are 0–0.6 (threshold), +0.15 resource penalty → the worst possible resource scores 0.75, while the custom command's second-best file scores 1. So command files 2–15 lose to every resource/agent that scrapes past the (permissive) 0.6 threshold. With ~100 Figma resources with long descriptions, almost any query matches something.
Two details confirm this is unintended:
- The merge has an explicit provision for score-less command results —
f.score ?? 0.5— andharguardst !== void 0. Both are dead code, because.map(har)always supplies the index. - The 2.1.89 changelog fix ("Improved @-mention typeahead to rank source files above MCP resources with similar names" — the +0.15 penalty) works for the built-in path but is mathematically irrelevant against integer index scores, so custom-command users never got that fix.
Steps to Reproduce
settings.json:
``json``
{ "fileSuggestion": { "type": "command", "command": "bash ~/.claude/my-finder.sh" } }
where the script prints, say, 20 relevant paths for the query (any correct finder reproduces it).
- Connect an MCP server that publishes resources, e.g. Figma:
claude mcp add --transport http figma https://mcp.figma.com/mcp - Type
@+ any query that matches multiple project files.
Expected Behavior
Files returned by the custom command rank according to the command's ordering, competing with MCP resources on comparable score scales — at minimum, an exact filename hit should not rank below a loose fuzzy match on an MCP resource description.
Actual Behavior
Only the command's first result ranks at the top; results 2–15 rank below every matching MCP resource and agent.
Suggested Fix
Minimal: .map(har) → .map((p) => har(p)), so command results get the intended score-less treatment (?? 0.5).
Better: preserve the command's ordering on the 0–1 scale, e.g. .map((p, i, arr) => har(p, i / arr.length * 0.1)) — command results keep their relative order, outrank loose resource matches, and a strong resource match can still surface.
Environment
- Claude Code 2.1.199 (native installer), macOS (Darwin 24.6, x86_64)
- Reproduced in CLI interactive mode
Related
- #30747 — same symptom, auto-closed as duplicate of #22737 (which is a different bug: command not invoked / query not passed, since fixed)
- #22021 / #17681 — requests to hide MCP resources from the picker (no such setting exists as of 2.1.199)
- #36329 — resource flooding variant
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗