Skip to content

Conversation

Hellobaka
Copy link

Replace while (cursor is not null) with while (!string.IsNullOrEmpty(cursor)) to prevent potential infinite loops if the cursor is an empty string.

Motivation and Context

When integrating with Alibaba Bailian's MCP service, I encountered an issue where the pagination API returns an empty string ("") instead of null for NextCursor when there is no more data. The previous loop condition failed to terminate in this case, resulting in infinite requests. This PR updates the loop condition to improve SDK compatibility with this scenario.

image

How Has This Been Tested?

Yes, I verified the change by testing the compiled code and confirmed that the modified logic works as expected and resolves the infinite request issue.

Breaking Changes

No.

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

This change ensures more robust pagination handling and prevents potential infinite loops caused by empty cursor values.

cursor = toolResults.NextCursor;
}
while (cursor is not null);
while (!string.IsNullOrEmpty(cursor));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to add an integration test that recreates the conditions of the infinite loop?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very familiar with xUnit or the project's test structure, so I'm not able to write a new integration test at this time.
If you'd like to reproduce the issue, you can do so by performing a paginated operation for tools, and on the last page, set the NextCursor property to an empty string ("") instead of null. This should help simulate the scenario in question.

@mikekistler
Copy link
Contributor

mikekistler commented Sep 16, 2025

What happens (or what should happen) when a subsequent request is made with cusror set to an empty string? Shouldn't that fail? If it did, then there would be no infinite loop.

@alvin-su
Copy link

When should this pull request be merged?

@halter73
Copy link
Contributor

If we do make this change, we should probably copy the pattern for prompts, resources and templated resources, and add tests.

What happens (or what should happen) when a subsequent request is made with cusror set to an empty string? Shouldn't that fail? If it did, then there would be no infinite loop.

Looking at the screenshot, Alibaba Bailian's MCP service continues to return the same tool listing with an empty cursor whether or not it should. I think that stopping iteration given an empty string as a nextCursor makes more sense than using it. We could also treat an empty nextCursor as an error, but I don't think that's helpful.

Looking at the TypeScript and Python SDK, neither automatically enumerates cursors the way we do. I cannot even find a sample in the TypeScript SDK repo that iterates over paginated results. Here's the list tools sample code:

https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/examples/client/simpleStreamableHttp.ts#L530-L539

The Python SDK repo has a sample of iterating over paginated resources that checks if result.nextCursor: where the empty string evaluates as false, so it would stop iterating in this case.

https://github.com/modelcontextprotocol/python-sdk/blob/71889d7387f070cd872cab7c9aa3d1ff1fa5a5d2/examples/snippets/clients/pagination_client.py#L31-L35

In the meantime, people can use the lower level await client.SendRequestAsync(RequestMethods.ToolsList, ... method to get the raw ListToolsResult and deal with the NextCursor themselves.

@alvin-su
Copy link

I've also encountered this problem. When connecting to Alibaba's MCP service, the cursor returns an empty string instead of null. Please approve this PR as soon as possible.

@mikekistler
Copy link
Contributor

IMHO this is a bug in Alibaba's MCP Server. According to the spec:

The cursor is an opaque string token

Opaque means the client should not be inspecting its value for meaning. The client should only use the presence or absence of the token to determine when it can issue a subsequent request.

After receiving a cursor, the client can continue paginating by issuing a request including that cursor

Another possible workaround is a custom deserializer for ListToolsResult that omits the cursor if it is empty. This might be a cleaner alternative to dropping down to the lower level API.

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.

5 participants