fix: bound the salvage walks and mark the scan's refused response (#1909)
Copilot round 6. Bound both fallback walks with LIST_MAX_PAGES, which is now also passed to the SDK client as `listMaxPages` so the strict aggregate and its fallback share one value by construction. A server emitting endlessly UNIQUE cursors never trips the repeated-cursor guard, so the salvage re-walk and the SEP-2243 exclusion scan would page and accumulate without bound. Hitting the cap aborts rather than returning a truncated list as a complete one. Mark the exclusion scan's refused response on every fallback-failure path. `salvageList` can rethrow bare because ManagedListState marks from the error it receives; the scan has no such backstop — listAllTools catches and logs a failing scan by design — so an unmarked rethrow left a response the client demonstrably refused rendering as a clean exchange. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RDXCSrnSBV7vZfxycG5Z6E Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
23fe62ec5c
commit
67972adc4e
1 changed files with 245 additions and 44 deletions
|
|
@ -2,8 +2,10 @@ import { describe, it, expect } from "vitest";
|
|||
import { z } from "zod/v4";
|
||||
import { SdkError, SdkErrorCode } from "@modelcontextprotocol/client";
|
||||
import {
|
||||
LIST_MAX_PAGES,
|
||||
ModernResultEnvelopeSchema,
|
||||
describeIssues,
|
||||
listPaginationExceeded,
|
||||
isClientDecodeRejection,
|
||||
isSalvageableRejection,
|
||||
labelForRawItem,
|
||||
|
|
@ -317,4 +319,21 @@ describe("summarizeMalformed", () => {
|
|||
expect(summary).toContain("index 0");
|
||||
expect(summary).toContain("(+1 more)");
|
||||
});
|
||||
|
||||
describe("the page bound", () => {
|
||||
it("matches the cap the SDK client is configured with", () => {
|
||||
// The value is passed to the SDK as `listMaxPages`, so the strict
|
||||
// aggregate and the fallback walks are bounded by the same number.
|
||||
expect(LIST_MAX_PAGES).toBe(64);
|
||||
});
|
||||
|
||||
it("names the method and the cap it hit", () => {
|
||||
// The walk's failure is logged rather than surfaced (the original
|
||||
// validation error is what the caller sees), so the message is the only
|
||||
// record of why salvage gave up.
|
||||
const error = listPaginationExceeded("resources/templates/list");
|
||||
expect(error.message).toContain("resources/templates/list");
|
||||
expect(error.message).toContain("64 pages");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue