-
Notifications
You must be signed in to change notification settings - Fork 3
Description
Problem
The list_tags tool currently returns all tags from a repository in a single response with no pagination or limits. This can cause:
- Memory issues for repositories with thousands of tags
- Poor performance with large result sets
- Poor user experience - no way to incrementally fetch results or get the most relevant tags first
MCP Best Practices
According to the MCP specification, while the built-in list operations (resources/list, prompts/list, tools/list) use cursor-based pagination, custom tools should implement their own pagination strategy appropriate for their use case.
For list operations in tools, best practices recommend:
- Setting reasonable defaults to avoid overwhelming responses
- Providing cursor or page-based navigation for large result sets
- Being transparent about pagination behavior in tool descriptions
Proposed Solution
Add pagination support to the list_tags tool with the following parameters:
New Parameters
-
limit(integer, optional)- Default:
100 - Maximum number of tags to return per request
- Should align with registry API capabilities
- Default:
-
cursor(string, optional)- Opaque pagination cursor for fetching the next page of results
- Returned in the response as
nextCursorwhen more results are available - Should be treated as an opaque token by clients (following MCP best practices)
-
sort(string, optional, enum)- Default:
name(alphabetical) - Options:
name: Alphabetical order (A-Z)name_desc: Reverse alphabetical order (Z-A)created: Oldest first (if registry supports it)created_desc: Newest first (if registry supports it)
- Allows users to get most relevant results faster
- Default:
Response Format
The tool should return:
{
"tags": ["tag1", "tag2", "..."],
"nextCursor": "opaque-cursor-string-or-null",
"total": 1234 // optional: if registry provides it
}Implementation Notes
The go-containerregistry library already supports pagination through:
-
Low-level pagination via
fetcher.listPage()inpkg/v1/remote/list.go:- Supports
pageSizeparameter (nquery param in registry API) - Returns
Nextlink for subsequent pages via Link header - The
Listertype providesHasNext()andNext(ctx)methods
- Supports
-
Current implementation via
remote.List():- Returns all tags by automatically handling pagination internally
- We need to expose the underlying pagination capabilities to the tool
Implementation Strategy
- Use the
fetcher.listPage()method or create a similar paginated approach - Store the pagination state (next URL) in an opaque cursor
- For sorting:
namesorting is default (registry provides alphabetical order)- For
createdsorting, we may need to fetch tag metadata unless registry provides it - Client-side sorting fallback if registry doesn't support the requested order
Backward Compatibility
- All new parameters are optional with sensible defaults
- Existing tool calls without pagination parameters will continue to work
- Default
limitof 100 prevents accidentally fetching thousands of tags
Example Usage
// Initial request
{
"tool": "list_tags",
"arguments": {
"repository": "docker.io/library/alpine",
"limit": 50,
"sort": "name"
}
}
// Response
{
"tags": ["2.6", "2.7", ..., "3.19"],
"nextCursor": "eyJuZXh0IjoiaHR0cHM6Ly9yZWdpc3RyeS0xLmRvY2tlci5pby92Mi9saWJyYXJ5L2FscGluZS90YWdzL2xpc3Q/bj01MCZsYXN0PTMuMTkifQ=="
}
// Fetch next page
{
"tool": "list_tags",
"arguments": {
"repository": "docker.io/library/alpine",
"cursor": "eyJuZXh0IjoiaHR0cHM6Ly9yZWdpc3RyeS0xLmRvY2tlci5pby92Mi9saWJyYXJ5L2FscGluZS90YWdzL2xpc3Q/bj01MCZsYXN0PTMuMTkifQ=="
}
}Additional Considerations
- Update tool description to document pagination behavior
- Consider adding integration tests with repositories that have many tags
- Document the cursor format in code comments (even though it's opaque to clients)
- Handle registry-specific pagination differences gracefully