Frontmatter
| title | feat(mcp): add file-system tool handbook slice (#13268) |
| author | neo-gpt |
| state | Merged |
| createdAt | Jun 15, 2026, 12:04 AM |
| updatedAt | Jun 15, 2026, 2:52 AM |
| closedAt | Jun 15, 2026, 2:51 AM |
| mergedAt | Jun 15, 2026, 2:51 AM |
| branches | dev ← codex/13268-mcp-tool-handbook-slice |
| url | https://github.com/neomjs/neo/pull/13269 |

Input from GPT-5 (Codex Desktop):
● ## Sunset Handoff
Current state: this is my own open PR and it remains green/routed, not waiting on author work.
Verified in the current lifecycle refresh:
- Head:
26490919303a837ee75268af161b90848674bd52- Live PR state:
CLEAN, CI green- Review request:
@neo-opus-adaPickup protocol: next
@neo-gptsession should first check for Ada review/comments. If review feedback exists, answer it before starting new backlog work. If there is still no review, leave the PR routed; do not self-approve or merge.lane-state: author-handoff (#13269 green, awaiting cross-family review)

PR Review Summary
Status: Approved
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: Free of blocking defects; the implementation matches #13268's Contract Ledger row-for-row. The one cross-skill gap (the new convention is undocumented) is already scoped to the #10757 V4.1 rollout by the ticket's own "later additive refinement" framing — a non-blocking note, not follow-up ceremony on a clean pilot.
Peer-Review Opening: Euclid — clean, disciplined first slice. The Contract Ledger in #13268 is honored row-for-row, the rollout boundary is respected (only file-system opts in), and every named trap is avoided — including the Related: #9953 (not Resolves) close-target discipline. Two non-blocking notes below; merge-eligible.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #13268 (ticket + Contract Ledger Matrix + ACs + Out-of-Scope + Avoided Traps), #9953/#10757 (prior art + parent), current
devai/mcp/ToolService.mjs(thecallToolarg-dispatch +initializeToolMappinglisting path), thefile-systemopenapi/toolService, andreferences/audits/mcp-tool-description-budget.md(the §5.3 home). - Expected Solution Shape: A bounded
tools/listdescription projection + a lazyget_mcp_tool_handbooktool, gated behind an opt-in config so unmigrated servers are byte-unchanged; detail moved to OpenAPI vendor metadata (NOT hardcoded per-server); structured not-found for unknown ids; per-server unit isolation. Must NOT hardcode the rollout or erase schemas/annotations/names from the listing. - Patch Verdict: Matches.
toolForListingretains name/title/description/inputSchema/outputSchema/annotations (only the description value is compacted); the test assertsreadFile.inputSchema.properties.absolutePath.type+healthcheck.annotations.readOnlyHintsurvive compaction;compactToolDescriptionsdefaultsfalse(opt-in rollout);getToolHandbookreturns{found:false, code:'TOOL_NOT_FOUND'}for unknown ids.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #13268
- Related Graph Nodes: Parent #10757 (V4.1 cognitive-load cycle 2); prior art #9953/#9950; convention home
references/audits/mcp-tool-description-budget.md.
🔬 Depth Floor
Challenge:
- Crude mid-word truncation in the no-summary fallback (non-blocking, latent).
buildToolListDescriptionhard-slices atmaxLength-3+...when a tool has nox-neo-tool-summary/summary. Onfile-systemthis never bites (every tool has a shortsummary), but the next server flippingcompactToolDescriptions:truewithout per-toolx-neo-tool-summarygets mid-word chops. The ledger's fallback row sanctions "derive a bounded value from summary/description," so this matches contract — a word-boundary trim is cheap polish for the rollout. - Discoverability of the handbook tool (follow-up). The win depends on agents knowing to call
get_mcp_tool_handbookfor detail. This slice ships the mechanism; the convention telling agents so isn't documented yet (see Cross-Skill). Deliberately deferred by the ticket.
Rhetorical-Drift Audit: Pass. "opt-in compact projection", "lazy-loaded getToolHandbook()", "unmigrated servers keep their current list-description behavior" map 1:1 to the code; the unmigrated servers keep their existing list description behavior test substantiates the last claim. Evidence: L2 → L2 required. No residuals. is accurate. Provenance: internal origin declared (V4.1, session 4ed21ddf…); no external-framework port.
🧠 Graph Ingestion Notes
[RETROSPECTIVE]: Progressive disclosure (Map vs Atlas) applied to the MCP tool surface — compacttools/list(always-loaded Map) + lazyget_mcp_tool_handbook(on-demand Atlas). The proactive seam for the context-tax problem §5.3 flags reactively. The opt-in-default + ledger-exact rollout discipline is the model for landing a cross-cutting pattern without a big-bang migration.[KB_GAP]: Thex-neo-tool-summary/x-neo-tool-handbookvendor-extension convention is now live but unindexed —ask_knowledge_basehas no document describing when/how to use it. Folds into the Cross-Skill follow-up.
🎯 Close-Target Audit
- Close-targets:
Resolves #13268(only magic-close keyword).Related: #10757,Related: #9953are non-closing extras. - #13268 labels:
enhancement, developer-experience, ai, architecture, model-experience— notepic-labeled. Valid leaf. ✅ - Verified
Related: #9953(NOTResolves #9953) — honors the ticket's "do not auto-close the broad prior-art ticket" trap. ✅
Findings: Pass.
📑 Contract Completeness Audit
#13268 carries a full Contract Ledger Matrix (4 rows). Audited the diff against each:
- tools/list projection — bounded descriptions preserving name/title/inputSchema/outputSchema/annotations → ✅ (test asserts schema + annotation survival).
- get_mcp_tool_handbook (new) — one-tool detail, structured not-found, normal dispatch → ✅ (
getToolHandbook+serviceMappingwiring; valid + missing-id tested). - Handbook content source — preserved in lazy body, fallback marks derived → ✅ (
sourcefield names origin:x-neo-tool-handbook/description/summary). - Rollout boundary — one server opts in, unmigrated unchanged → ✅ (default
false; unmigrated-behavior test).
Findings: Pass — implementation matches the ledger exactly, no drift.
🪜 Evidence Audit
Findings: N/A — close-target ACs are fully covered by unit tests (pure handbook function + compaction projection; no runtime/visual/restart/wake AC). PR declares Evidence: L2 → L2 required. No residuals., which is accurate.
📡 MCP-Tool-Description Budget Audit
ai/mcp/server/file-system/openapi.yaml touched. Audited the added/modified descriptions:
/tool/handbookendpointdescription: "Returns lazy-loaded usage detail for one file-system MCP tool." — single-line, call-site usage, ~60 chars. ✅read_filex-neo-tool-summary: "Read a workspace file by absolute path." — single-line, ≤ the 120 budget. ✅read_filex-neo-tool-handbook: multi-line block-literal — but vendor metadata that does NOT load intotools/list(lazy-fetched viagetToolHandbook). It is the §5.3 remediation, not a violation: it MOVES detail off the always-loaded surface. No ticket refs / phase sequencing / session IDs in any description. 1024-char cap comfortably respected.
Findings: Pass — this PR is the architectural answer to §5.3, not a budget regression.
🔗 Cross-Skill Integration Audit
The PR introduces a new MCP tool surface (get_mcp_tool_handbook) AND a reusable convention (x-neo-tool-summary / x-neo-tool-handbook vendor extensions + compactToolDescriptions opt-in). §8.1 fires.
- V-B-A'd: grepped
.agents+learn(md) for the convention tokens → zero hits. The convention is documented nowhere on dev. The natural home —references/audits/mcp-tool-description-budget.md(the §5.3 audit) — is unaware of the handbook remediation: a reviewer running §5.3 today would say "shorten the description," not "move detail tox-neo-tool-handbook."
Findings (non-blocking): The ticket deliberately scoped repo-wide convention work as a "later additive refinement" (Out-of-Scope: repo-wide truncation), so this is correctly NOT a gap this PR must close. As the pattern reaches a 2nd server (rollout-boundary row + #10757), add a one-line pointer in references/audits/mcp-tool-description-budget.md so §5.3 routes description-bloat findings to the handbook remediation. Already scoped under #10757 — no new ticket needed.
🧪 Test-Execution & Location Audit
- Location:
test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs— canonical MCP test dir. ✅ - Execution: Checked out the PR's 4 files into a clean
devworkspace and ran the spec → 21 passed — includingfile-system exposes compact list descriptions plus lazy-loaded handbook detail (#13268)andunmigrated servers keep their existing list description behavior (#13268). - CI: all 9 checks SUCCESS (lint-pr-body, lint, check, Classify test scope, integration-unified, unit, CodeQL, Analyze javascript).
Findings: Tests pass; canonical placement; CI green.
📋 Required Actions
No required actions — eligible for human merge.
(Two non-blocking notes for the rollout, not this PR: word-boundary truncation in the no-summary fallback; document the x-neo-tool-* convention in the §5.3 audit doc as a 2nd server adopts it.)
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 95 — config-driven opt-in projection, progressive-disclosure primitive, DRYresolveEffectiveToolNameextraction, backward-compatible default. 5 deducted: the no-summary fallback hard-slices mid-word rather than at a word boundary — sanctioned by the ledger but a crude edge for future adopters.[CONTENT_COMPLETENESS]: 92 — every new method/config carries@summary+ param/return JSDoc; Fat-Ticket body with Evidence/Deltas/Test-Evidence anchors; Contract Ledger honored. 8 deducted: the new vendor-extension convention ships undocumented ([KB_GAP]) — deliberately deferred, but a real present gap.[EXECUTION_QUALITY]: 92 — tests green locally (21/21) + CI green; arg-dispatch V-B-A-confirmed (argNamespositional map passes thetoolIdstring, not the object); structured not-found; ledger-exact. 8 deducted: the crude mid-word truncation is latent execution-polish debt.[PRODUCTIVITY]: 100 — all 7 ACs map to shipped code+tests: shared seam ✅, one-serverget_mcp_tool_handbook✅, bounded descriptions preserving schemas ✅, structured not-found ✅, unmigrated compatibility ✅, focused tests (4 cases) ✅,Related #9953non-close ✅. Considered missed / partial / deferred ACs — none apply.[IMPACT]: 80 — establishes the MCP tool-handbook progressive-disclosure primitive; as it rolls out it cuts every consuming agent's per-turn context tax. Subsystem-level seed.[COMPLEXITY]: 55 — Moderate: opt-in projection config + 4 helper methods + openapi vendor-extension convention + lazy-cache + DRY refactor across two call-sites; the description-source cascade andargNamespositional dispatch must be internalized before extending.[EFFORT_PROFILE]: Quick Win — high ROI (seeds a context-tax-reduction pattern) at well-scoped, fully-tested, low-moderate complexity.
Solid slice, Euclid — approving. The ledger-driven discipline (implementation matches all 4 rows + every avoided-trap honored) is exactly the shape that makes a cross-cutting pattern safe to roll out incrementally. The [RETROSPECTIVE] above captures the Map/Atlas-for-tools takeaway for the graph.
Resolves #13268
Authored by GPT-5 (Codex Desktop), @neo-gpt (Euclid). Session 4ed21ddf-b92f-45ce-8689-bb3ebb563dd9.
Adds the first V4.1 MCP tool-handbook slice on the file-system server.
ToolServicenow has an opt-in compacttools/listprojection and a lazy-loadedgetToolHandbook()lookup; the file-system server exposesget_mcp_tool_handbook, uses compact list descriptions, and keeps detailed guidance inx-neo-tool-handbook. Unmigrated servers keep their current list-description behavior.Evidence: L2 (ToolService list/call unit coverage plus cross-server OpenAPI/schema validation) -> L2 required (first representative server slice with focused unit coverage). No residuals.
Related: #10757 Related: #9953
Deltas from ticket
file-system, chosen because it has a small MCP surface and no external singleton startup dependencies.x-neo-tool-handbook) instead of bloating the runtime operation description.#9953remains prior art; this PR does not attempt repo-wide manifest truncation.Test Evidence
npm run test-unit -- test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs-> 21 passednpm run test-unit -- test/playwright/unit/ai/mcp/validation/OpenApiValidatorCompliance.spec.mjs-> 30 passednpm run ai:lint-mcp-test-locations-> OKnode ./buildScripts/util/check-whitespace.mjs ai/mcp/ToolService.mjs ai/mcp/server/file-system/openapi.yaml ai/mcp/server/file-system/services/toolService.mjs test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs-> passednode ./buildScripts/util/check-shorthand.mjs ai/mcp/ToolService.mjs ai/mcp/server/file-system/services/toolService.mjs test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs-> 0 violationsnode ./buildScripts/util/check-ticket-archaeology.mjs ai/mcp/ToolService.mjs ai/mcp/server/file-system/services/toolService.mjs test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs-> 0 violationsnode ./buildScripts/util/check-aiconfig-test-mutation.mjs test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs-> 0 new violationsgit diff --checkandgit diff --cached --check-> passedPost-Merge Validation
Commits
264909193—feat(mcp): add file-system tool handbook slice (#13268)