mcplisten
Drain all pages from MCP SDK paginated list methods — get every tool, resource, and prompt without cursor management.
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 fromlist_tools(), returnslist[dict]list_all_resources(client)— drain all pages fromlist_resources()list_all_prompts(client)— drain all pages fromlist_prompts()list_all_resource_templates(client)— drain all pages fromlist_resource_templates()list_all(client, method, items_key)— generic drain helper- Sync wrappers —
list_all_*_sync()variants forSyncMCPClient - CLI —
mcplisten 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:
ClientSessionGroupdrains 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
Metadata
Release files for mcplisten 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mcplisten-0.1.0.tar.gz | 142.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcplisten-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 157.0 kB
Release files / mcplisten-0.1.0.tar.gz
| Download URL | mcplisten-0.1.0.tar.gz |
|---|---|
| Size | 142.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
57e2780b5c62a768e6e3860246b3450f881eb9b6ac65478a5ab6981d05b1b017
|
|
BLAKE2b-256 checksum How to use checksums |
0a33e648f98f767368cfe5f751ff320b8236687e0a8047cc82d36bf797dcb130
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / mcplisten-0.1.0-py3-none-any.whl
| Download URL | mcplisten-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f82e1e4e20e68c0deb391271698220142b0f50f3b7da4fb4332822ed651ee5cd
|
|
BLAKE2b-256 checksum How to use checksums |
5a7eca22f37c6560005d85c9dacc6ef8118fb6f8b7ee59bb9dd2db1d05f74637
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|