Skip to content

Fix listRoots() pagination on an empty nextCursor - #1275

Open
subhashpolisetti wants to merge 1 commit into
modelcontextprotocol:mainfrom
subhashpolisetti:fix/list-roots-empty-cursor
Open

subhashpolisetti wants to merge 1 commit into
modelcontextprotocol:mainfrom
subhashpolisetti:fix/list-roots-empty-cursor

Conversation

@subhashpolisetti

Copy link
Copy Markdown

Fixes #1274

Motivation and Context

McpAsyncServerExchange#listRoots() follows nextCursor until it is null. When a client answers roots/list with "nextCursor": "", the server requests the next page with "cursor": "", and a client that keeps answering that way makes listRoots() never complete. McpSyncServerExchange#listRoots() blocks on the same Mono, so it hangs the calling thread.

#954 fixed this on the client for listTools, listResources, listResourceTemplates and listPrompts. This change applies the same guard, line for line, to listRoots(), the last aggregate list method in mcp-core without it:

.expand(result -> {
	String next = result.nextCursor();
	return (next != null && !next.isEmpty()) ? this.listRoots(next) : Mono.empty();
})

McpSyncServerExchange#listRoots() delegates to this method, so it needs no change.

How Has This Been Tested?

Added testListRootsStopsOnEmptyNextCursor to McpAsyncServerExchangeTests: the first page returns nextCursor: "", and the test checks that only that page is returned and that roots/list is sent once. It fails on main (a second request goes out with an empty cursor) and passes with this change.

./mvnw -pl mcp-core test -Dtest=McpAsyncServerExchangeTests,McpSyncServerExchangeTests
./mvnw clean verify
./mvnw -pl mcp-test -am -Pjackson2 test
  • McpAsyncServerExchangeTests 38/38, McpSyncServerExchangeTests 27/27
  • clean verify: BUILD SUCCESS (mcp-core 506, mcp-json-jackson3 45, mcp-json-jackson2 45, mcp-test 1357; 1 existing assumeTrue skip in StdioMcpAsyncClientTests)
  • -Pjackson2: BUILD SUCCESS, same counts

Breaking Changes

None. A non-empty nextCursor is still followed; an empty one now ends pagination, as it does on the client.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

McpAsyncServerExchange#listRoots() kept following nextCursor when a client
returned "" instead of omitting it, sending roots/list again with an empty
cursor. Apply the same guard the client list methods already use.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

McpAsyncServerExchange#listRoots() keeps paginating when nextCursor is an empty string

1 participant