Skip to main content

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 wrappers — list_all_*_sync() variants for SyncMCPClient
  • 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: 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

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)

Source distribution for mcplisten 0.1.0
File Size Uploaded
mcplisten-0.1.0.tar.gz 142.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mcplisten 0.1.0
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page