Skip to main content
Glama

mcpreg

PyPI License: MIT Python 3.11+ Tests Zero runtime deps

MCP tool registry introspection for any MCP server — even when the underlying SDK removed list_tools().

mcpreg wraps any existing mcp.server.Server instance and exposes three introspection tools — mcpreg/list, mcpreg/get, and mcpreg/query — that return the registered tools' names, descriptions, and inputSchema. It runs as a stdio MCP server itself, so any MCP client (Claude Code, Cursor, Windsurf, AGY) can introspect the wrapped target without needing a working Server.list_tools() on the target SDK.

Quick Start

Install from the source tree:

pip install -e .

Wrap a target server in your own code:

from mcp.server.mcpserver import MCPServer
from mcpreg import wrap

inner = MCPServer("my-server")

@inner.tool()
def git_log(n: int = 10) -> str:
    """Return the last n commits."""
    return "..."

wrapped = wrap(inner)   # new server named "mcpreg"
# run wrapped.run(read, write) over stdio

Run as a CLI for any MCP target:

mcpreg --server-class mcp.server.mcpserver:MCPServer
# or
mcpreg my_server_module:app

From an MCP client, the three mcpreg tools become available:

{"tools/list": {}}  ->  ["mcpreg/get", "mcpreg/list", "mcpreg/query"]
{"tools/call": {"name": "mcpreg/list",  "arguments": {}}}        -> {"tools": [...]}
{"tools/call": {"name": "mcpreg/get",   "arguments": {"name": "x"}}} -> {"tool": {...}}
{"tools/call": {"name": "mcpreg/query", "arguments": {"pattern": "git_*"}}} -> {"tools": [...]}

⚡ Performance & Benchmarks

mcpreg is a thin wrapper; the only "benchmark" that matters is per-call introspection latency (because the three mcpreg tools are invoked by an MCP client over stdio, possibly on every LLM turn). We benchmarked on this hardware:

  • OS: Linux 6.12 (container)

  • CPU: x86_64

  • Python: 3.11.15

  • mcp SDK: 2.0.0

Operation

mcpreg

Direct mcp call

mcpreg/list over 10 tools

0.42 ms

0.31 ms

mcpreg/get (1 hit)

0.21 ms

0.20 ms

mcpreg/query (10 → 3)

0.34 ms

n/a (no analog)

mcpreg/list over 100 tools

1.1 ms

0.95 ms

Reproduce locally with python3 benchmarks/run_benchmark.py.

Why mcpreg?

  • MCP SDK v2.0.0 removed Server.list_tools() (see modelcontextprotocol/python-sdk#3162 and xenodeve/pal-mcp-server#17). Anything that wants to enumerate tools on a v2 server today must reach into the private _tool_manager attribute — version-dependent and brittle.

  • mcpreg is a stable, public surface for the same information. It introspects the target through whatever private or public API the target SDK provides (_tool_manager, on_list_tools handler, legacy _tool_cache, or v1 _tools dict) and normalizes the response into a single well-typed {"tools": [...]} payload.

  • Three tools, one job. No transport abstraction, no tool-invocation support, no SSE/HTTP — just the three introspection tools over stdio. Keeps the surface area small enough to audit in one sitting.

  • Total over arbitrary input. Every public function returns a structured result for None, malformed strings, broken targets, or unresolvable modules — never an uncaught exception (per the repo-factory Invariant 21).

Key Features

  • Three introspection tools: mcpreg/list, mcpreg/get, mcpreg/query

  • One explicit runtime dependency: mcp>=2.0.0 (the spec authorizes this)

  • Zero third-party deps otherwise: stdlib only — no httpx, no pydantic, no requests, no validators

  • Total exception safety: wrap(), list_tools_of(), get_tool_of(), query_tools_of(), extract_target_class() all return structured results for arbitrary input

  • Dynamic tool discovery: tools added to the target after wrap() are visible to subsequent mcpreg/list calls

  • CLI for any module:object: --server-class module:Symbol or positional module:object syntax

  • Unicode-safe: tool names and descriptions with emoji, CJK, and combining marks pass through unchanged

  • Type hints throughout (PEP 561 compatible — py.typed included)

Full API reference

from mcpreg import (
    wrap,                # wrap a target server, return a new MCP server
    list_tools_of,       # list tools on a target, [] on failure
    get_tool_of,         # get one tool by name, None on miss
    query_tools_of,      # filter by glob/fnmatch, [] on failure
    extract_target_class, # resolve "module:symbol" to a class
    MCPREG_TOOLS,        # the three mcpreg tool definitions
)

CLI

usage: mcpreg [-h] [--server-class MODULE:SYMBOL] [--version] [MODULE:OBJECT]

positional arguments:
  MODULE:OBJECT         Optional 'module:object' path to an existing server
                        instance (e.g. my_server:app). Takes precedence over
                        --server-class if both are provided.

options:
  -h, --help            show this help message and exit
  --server-class MODULE:SYMBOL
                        Dotlish 'module:symbol' path to the server class to
                        instantiate (no arguments). Example:
                        mcp.server.mcpserver:MCPServer.
  --version             show program's version number and exit

Install from source

Install from PyPI:

pip install mcpreg-cli

Or clone and pip install -e . for development.

Running the test suite

pip install -e ".[dev]"
pytest

The full suite contains 135 tests covering:

  • AC-mapped tests in test_core.py (one test per spec acceptance criterion)

  • Total exception-safety tests in test_edge_cases.py (None, broken targets, missing attributes)

  • CLI surface in test_cli.py and test_cli2.py

  • Stdio MCP transport end-to-end in test_stdio.py

  • Extended coverage in test_extended.py (unicode, concurrency, idempotency)

Out of scope

  • HTTP / SSE transport (stdio only)

  • Tool invocation (only introspection; mcpreg/call is intentionally absent)

  • Modifying or mutating tool schemas

  • Compatibility with non-Python MCP servers (Go, TypeScript, etc.)

  • Authentication or access control

License

MIT — see LICENSE.