siyuan-note/siyuan · error
tools/list exceeded pages
Error message
tools/list exceeded %d pages
What it means
listAllMCPTools caps pagination at maxMCPToolListPages pages as a safety valve. If after that many tools/list round-trips the server still returns a NextCursor, the client gives up with this error instead of paging unboundedly. It usually means the tool list is genuinely huge or the server keeps issuing new cursors indefinitely.
Solutions
- Increase maxMCPToolListPages if the tool count legitimately exceeds the cap
- Fix or upgrade the MCP server so it terminates pagination (empty NextCursor on the final page)
- Reduce the number of tools exposed by the server or increase its page size
- Check server logs to confirm cursors are actually advancing rather than being freshly minted each page
Example fix
// before: const maxMCPToolListPages = 10 // too small // after: const maxMCPToolListPages = 100 // accommodate large tool registries
Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
conn, err := listAllMCPTools(ctx, listPage)
if err != nil {
if strings.Contains(err.Error(), "exceeded") {
logging.LogWarnf("mcp: pagination cap hit: %v", err)
return
}
return err
} Prevention
- Keep per-server tool counts reasonable; disable unneeded tools server-side
- Set page sizes generously on the server so few pages are needed
- Size maxMCPToolListPages relative to the largest registry you legitimately serve
When it happens
Trigger: connectOneServer calls listAllMCPTools; the server returns a valid distinct NextCursor on every page for maxMCPToolListPages consecutive requests.
Common situations: A server exposing thousands of tools with small page sizes, a server generating fresh (never-terminating) cursors each call, or a malicious/buggy server forcing endless pagination.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- tools/list repeated cursor
- tools/list returned an empty response
- connect
- attr must be a string or null (got %T)
- command is required for stdio server
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/bf2c68a7bee28084.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/client/mcp.go:368
for page := 0; page < maxMCPToolListPages; page++ {
result, err := listPage(ctx, params)
if err != nil {
return nil, err
}
if result == nil {
return nil, fmt.Errorf("tools/list returned an empty response")
}
allTools = append(allTools, result.Tools...)
if result.NextCursor == "" {
return allTools, nil
}
if _, exists := seenCursors[result.NextCursor]; exists {
return nil, fmt.Errorf("tools/list repeated cursor %q", result.NextCursor)
}
seenCursors[result.NextCursor] = struct{}{}
params = &mcp.ListToolsParams{Cursor: result.NextCursor}
}
return nil, fmt.Errorf("tools/list exceeded %d pages", maxMCPToolListPages)
}
func sanitizedServerNameCollision(server conf.MCPServer) bool {
mcpMu.Lock()
defer mcpMu.Unlock()
sanitizedName := sanitize(server.Name)
for _, configured := range mcpServers {
if configured.ID != server.ID && sanitize(configured.Name) == sanitizedName {
return true
}
}
return false
}
func mcpToolName(server conf.MCPServer, toolName string, collision bool) string {
name := "mcp_" + sanitize(server.Name) + "_" + sanitize(toolName)
if !collision && len(name) <= maxMCPToolNameLen {
return nameView on GitHub (pinned to 9f775e8a12)