Skip to content

Commit 555c16a

Browse files
committed
feat: add pagination support for listRoots operation
- Add nextCursor field to ListRootsResult for cursor-based pagination - Implement automatic pagination in McpAsyncServerExchange.listRoots() - Update tests to verify pagination functionality - Automatically fetches and combines all pages into single result Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
1 parent ba5bc94 commit 555c16a

File tree

3 files changed

+23
-4
lines changed

3 files changed

+23
-4
lines changed

mcp/src/main/java/io/modelcontextprotocol/server/McpAsyncServerExchange.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package io.modelcontextprotocol.server;
66

7+
import java.util.ArrayList;
8+
79
import com.fasterxml.jackson.core.type.TypeReference;
810
import io.modelcontextprotocol.spec.McpError;
911
import io.modelcontextprotocol.spec.McpSchema;
@@ -126,7 +128,16 @@ public Mono<McpSchema.ElicitResult> createElicitation(McpSchema.ElicitRequest el
126128
* @return A Mono that emits the list of roots result.
127129
*/
128130
public Mono<McpSchema.ListRootsResult> listRoots() {
129-
return this.listRoots(null);
131+
132+
return this.listRoots(McpSchema.FIRST_PAGE).expand(result -> {
133+
if (result.nextCursor() != null) {
134+
return this.listRoots(result.nextCursor());
135+
}
136+
return Mono.empty();
137+
}).reduce(new McpSchema.ListRootsResult(new ArrayList<>(), null), (allRootssResult, result) -> {
138+
allRootssResult.roots().addAll(result.roots());
139+
return allRootssResult;
140+
});
130141
}
131142

132143
/**

mcp/src/main/java/io/modelcontextprotocol/spec/McpSchema.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1615,11 +1615,19 @@ public record Root( // @formatter:off
16151615
*
16161616
* @param roots An array of Root objects, each representing a root directory or file
16171617
* that the server can operate on.
1618+
* @param nextCursor An optional cursor for pagination. If present, indicates there
1619+
* are more roots available. The client can use this cursor to request the next page
1620+
* of results by sending a roots/list request with the cursor parameter set to this
16181621
*/
16191622
@JsonInclude(JsonInclude.Include.NON_ABSENT)
16201623
@JsonIgnoreProperties(ignoreUnknown = true)
16211624
public record ListRootsResult( // @formatter:off
1622-
@JsonProperty("roots") List<Root> roots) {
1625+
@JsonProperty("roots") List<Root> roots,
1626+
@JsonProperty("nextCursor") String nextCursor) {
1627+
1628+
public ListRootsResult(List<Root> roots) {
1629+
this(roots, null);
1630+
}
16231631
} // @formatter:on
16241632

16251633
}

mcp/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,7 @@ void testListRootsResult() throws Exception {
984984

985985
McpSchema.Root root2 = new McpSchema.Root("file:///path/to/root2", "Second Root");
986986

987-
McpSchema.ListRootsResult result = new McpSchema.ListRootsResult(Arrays.asList(root1, root2));
987+
McpSchema.ListRootsResult result = new McpSchema.ListRootsResult(Arrays.asList(root1, root2), "next-cursor");
988988

989989
String value = mapper.writeValueAsString(result);
990990

@@ -993,7 +993,7 @@ void testListRootsResult() throws Exception {
993993
.isObject()
994994
.isEqualTo(
995995
json("""
996-
{"roots":[{"uri":"file:///path/to/root1","name":"First Root"},{"uri":"file:///path/to/root2","name":"Second Root"}]}"""));
996+
{"roots":[{"uri":"file:///path/to/root1","name":"First Root"},{"uri":"file:///path/to/root2","name":"Second Root"}],"nextCursor":"next-cursor"}"""));
997997

998998
}
999999

0 commit comments

Comments
 (0)