Skip to main content

Drain all pages from MCP SDK paginated list methods — get every tool, resource, and prompt without cursor management

Project description

mcplisten

Drain all pages from MCP SDK paginated list methods — get every tool, resource, and prompt without cursor management.

PyPI version License: MIT Python 3.11+

Python developers using the MCP Python SDK's Client.list_tools() only receive the first page of results when a server paginates its responses. mcplisten transparently drains every page so you get the complete inventory.

Quick Start

pip install git+https://github.com/prasad-a-abhishek/mcplisten.git
from mcplisten import list_all_tools

# Async usage (with MCP SDK Client)
from mcp import Client
async with Client(server_params) as client:
    tools = await list_all_tools(client)  # drains all pages
    print(f"Got {len(tools)} tools")

# Sync usage (with SyncMCPClient from mcpsync)
from mcpsync import SyncMCPClient
from mcplisten import list_all_tools_sync

with SyncMCPClient(params) as client:
    tools = list_all_tools_sync(client)

⚡ Performance & Benchmarks

mcplisten is a thin pagination drain helper — it adds zero computational overhead beyond the network I/O of fetching additional pages. The synchronous wrapper spawns a fresh event loop per call (thread-safe for single-shot use).

python3 benchmarks/run_benchmark.py

Benchmark environment: Python 3.11.15, Linux x86_64 (kernel 6.12.67), 4 vCPU. Note: mcplisten has no direct competitor — the MCP Python SDK itself does not provide list_all_* helpers (see modelcontextprotocol/python-sdk#2556).

Test Status

The repository ships with a 131-test pytest suite covering every spec acceptance criterion (22/22), concurrent-call safety, unicode round-trip, dict-shaped and pydantic-shaped responses, CLI end-to-end against a fake paginating stdio server, and zero-dependency enforcement. Run pytest tests/ -q to reproduce (≈1 second).

Spec: see spec.md for the canonical 22-acceptance-criteria contract that drives the test suite.

Why mcplisten?

The MCP Python SDK's ClientSession.list_tools(cursor=...) accepts a cursor parameter but requires callers to manually loop across pages. MCP gateways, Claude Code, Cursor, and the Inspector CLI all shipped with this single-page limitation — silently losing tools when servers register more tools than fit in one page.

mcplisten is the fix: a zero-dependency, zero-overhead wrapper that calls list_tools(cursor=None) then follows nextCursor until the server returns null. No SDK changes required. No configuration. Drop in.

Feature mcplisten SDK default
Multi-page drain ❌ single page only
Zero dependencies
Sync + async async only
Generic list_all()
CLI included

Key Features

  • list_all_tools(client) — drain all pages from list_tools(), returns list[dict]
  • list_all_resources(client) — drain all pages from list_resources()
  • list_all_prompts(client) — drain all pages from list_prompts()
  • list_all_resource_templates(client) — drain all pages from list_resource_templates()
  • list_all(client, method, items_key) — generic drain helper
  • Sync wrapperslist_all_*_sync() variants for SyncMCPClient
  • CLImcplisten list-tools -- <server-cmd>, list-resources, list-prompts
  • Zero dependencies — pure Python stdlib, no third-party packages
  • Full type stubs — Python 3.11+ with complete type annotations

CLI Reference

# List all tools from a stdio server
mcplisten list-tools -- python -m my_mcp_server

# List all resources
mcplisten list-resources -- python -m my_mcp_server

# List all prompts
mcplisten list-prompts -- python -m my_mcp_server

# Verbose mode — includes per-server tool counts
mcplisten list-tools --verbose -- python -m my_mcp_server

# Help
mcplisten --help
mcplisten list-tools --help

API Reference

list_all_tools(client) — async

from mcplisten import list_all_tools

tools: list[dict[str, Any]] = await list_all_tools(client)

Drains all pages from client.list_tools() (works with Client, ClientSession, and ClientSessionGroup).

list_all_tools_sync(client) — sync

from mcplisten import list_all_tools_sync

tools: list[dict[str, Any]] = list_all_tools_sync(client)

Synchronous wrapper for use with SyncMCPClient (from the mcpsync extra).

list_all(client, method, items_key) — generic

from mcplisten import list_all

result: list[dict[str, Any]] = await list_all(client, "list_tools", "tools")

Generic drain helper for any paginated list method. items_key is the dict key holding the items list in each page response.

CLI

mcplisten [--help]
  list-tools [--verbose] [--] <server-cmd>...
  list-resources [--] <server-cmd>...
  list-prompts [--] <server-cmd>...
  list-resource-templates [--] <server-cmd>...

Exits 0 on success (print JSON to stdout), non-zero on error (print message to stderr).

Limitations

  • Cursor timing: if a server adds a tool between page 1 and page 2 of a drain, the caller may see duplicates. This is consistent with the MCP SDK's at-most-once semantics.
  • No streaming variant: memory-constrained streaming (async generator) is a separate future feature.
  • SDK version sensitivity: if the MCP SDK changes its pagination API (method signature or cursor field location), this library will break. Tests pin against a known SDK version.
  • No parallelization: ClientSessionGroup drains each session sequentially, not in parallel.

Non-Goals

  • Changing the underlying MCP SDK's pagination mechanism
  • Server-side pagination implementation
  • Authentication (passes through to the underlying client)
  • Tool/result caching

License

MIT License — © 2026 Prasad Abhishek

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcplisten-0.1.0.tar.gz (142.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcplisten-0.1.0-py3-none-any.whl (14.2 kB view details)

Uploaded Python 3

File details

Details for the file mcplisten-0.1.0.tar.gz.

File metadata

  • Download URL: mcplisten-0.1.0.tar.gz
  • Upload date:
  • Size: 142.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for mcplisten-0.1.0.tar.gz
Algorithm Hash digest
SHA256 57e2780b5c62a768e6e3860246b3450f881eb9b6ac65478a5ab6981d05b1b017
MD5 c5128d26f63eefe500739a103c55ff92
BLAKE2b-256 0a33e648f98f767368cfe5f751ff320b8236687e0a8047cc82d36bf797dcb130

See more details on using hashes here.

File details

Details for the file mcplisten-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: mcplisten-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for mcplisten-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f82e1e4e20e68c0deb391271698220142b0f50f3b7da4fb4332822ed651ee5cd
MD5 b41ef2cf1b97101d2785c67113712af7
BLAKE2b-256 5a7eca22f37c6560005d85c9dacc6ef8118fb6f8b7ee59bb9dd2db1d05f74637

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page