Repository navigation
[Bug][mcp-resources][0.2.1-alpha.2] list_mcp_resources never returns nextCursor and fails on servers with more than 64 pages #9374
Replies: 1 comment
|
分叉点、SDK 行为、64 页上限我都从 npm tarball 逐行核过了,都成立。但你的 Summary 把两件事并列成两个 bug,其中一件严格来说不是 bug —— 这条会被 maintainer 挑,建议先改准。 1. 分叉点确实在
|
Uh oh!
There was an error while loading. Please reload this page.
Summary
The shared model tools
list_mcp_resourcesandlist_mcp_resource_templatescannot page through an MCP server's resources:cursor(the only way the model can start), the tool returns the SDK's merged listing of every page withnextCursorremoved. The model therefore never receives a cursor, and the documentedcursorargument has nothing to continue from.resources/list: exceeded listMaxPages (64); server pagination did not terminate, even though the server's pagination did terminate. The model has no cursor to resume from, so the listing is unreachable.This contradicts the package contract: mcp-resources README L38 says "An explicit
cursorrequests that page; pass a returnednextCursorunchanged", and L104 says "continuation cursors remain visible".Environment
d743267388(currentmaster)@modelcontextprotocol/client2.0.0 (the pinned SDK)resources/listorresources/templates/list.Reproduction
Add this case to
packages/mcp/mcp-client/tests/protocol.spec.ts(it reuses that file'sconnect()helper, which wires a realMcpServerto the connection supervisor and mountsdsh-mcp-resources):pnpm exec vitest run packages/mcp/mcp-client/tests/protocol.spec.tsOn
d743267388the call fails with:With
pages = 3the call succeeds, but returns all 30 resources merged with nonextCursor; the server sees cursors[undefined, '2', '3']from a single tool call.Root cause
connection.tsL371-L379 forwards a cursor-less request toClient.listResources(undefined)/Client.listResourceTemplates(undefined):In
@modelcontextprotocol/client2.0.0, alist*()call withoutcursoris the auto-aggregate path (Client._listAllPages): it requests every page, appends them into page 1, executesdelete acc.nextCursor, and throwsSdkErrorCode.ListPaginationExceededonce it has fetchedlistMaxPagespages (DEFAULT_LIST_MAX_PAGES = 64). Only an explicit{ cursor }takes the SDK's single-page path. That aggregation is right for tool discovery, which needs the complete list (the 64-page cap is the #5905 guard), but the model-facing resource tools need one page plus its cursor.Fix
Branch:
heaven999b/deepseek-harness@fix/mcp-resources-pagination(compare with master) (one commit,fix(mcp): list one resource page per model call).packages/mcp/mcp-client/src/connection.ts: both listing methods send exactly oneresources/listorresources/templates/listrequest throughClient.request(), forwarding the caller's cursor, and return the server's page unchanged, includingnextCursor. A server that does not advertise theresourcescapability still gets{ resources: [] }/{ resourceTemplates: [] }, matching the SDK list methods. That keeps the existing "resource tools stay available for a tools-only server" behavior.resources/readand tool discovery are unchanged.packages/mcp/mcp-client/tests/protocol.spec.ts: a regression test against a real SDK server with 65 pages for both tools. The first call issues one request and returns page 1 withnextCursor: '2'; following each cursor reaches the last page.packages/mcp/mcp-resources/README.md/README.zh.md(+ i18n record): document one page per call, and drop the "pagination follows the MCP SDK" wording.Verification
d743267388withresources/list: exceeded listMaxPages (64); server pagination did not terminateand passes with the fix.vitest run packages/mcp/mcp-client/tests packages/mcp/mcp-resources/tests --coverage --coverage.include='packages/mcp/mcp-client/src/**/*.ts' --coverage.include='packages/mcp/mcp-resources/src/**/*.ts': 10 files, 147 tests passed; everysrcfile at 100% statements/branches/functions/lines.tsc -b packages/mcp/mcp-client/tsconfig.jsonandtsc -b tsconfig.host.json(includes the specs): clean.verify-md-wrappasses.mcp-resourcessnapshot fixture server returns a single page, so its recorded tool results are byte-identical under both code paths. A keyless replay was not run locally because it needs builtlib/artifacts.Related
listMaxPagescap for tool discovery. That path is unchanged.All reactions