Metadata-Version: 2.4
Name: mcpreg-cli
Version: 0.1.3
Summary: MCP tool registry introspection server — enumerate tools from any MCP server via stdio
Author-email: Repo Factory <noreply@example.com>
License: MIT
Project-URL: Homepage, https://github.com/prasad-a-abhishek/mcpreg
Project-URL: Repository, https://github.com/prasad-a-abhishek/mcpreg
Project-URL: Issues, https://github.com/prasad-a-abhishek/mcpreg/issues
Keywords: mcp,model-context-protocol,tool-introspection,mcp-server,registry
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp>=2.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Dynamic: license-file

# mcpreg

[![PyPI](https://img.shields.io/badge/pypi-mcpreg--cli%200.1.1-blue)](https://pypi.org/project/mcpreg-cli)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/)
[![Tests](https://img.shields.io/badge/tests-135%20passing-brightgreen.svg)](tests/)
[![Zero runtime deps](https://img.shields.io/badge/dependencies-mcp%20only-blueviolet)](pyproject.toml)

> **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:

```bash
pip install -e .
```

Wrap a target server in your own code:

```python
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:

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

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

```json
{"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](https://github.com/modelcontextprotocol/python-sdk/issues/3162)
  and [xenodeve/pal-mcp-server#17](https://github.com/xenodeve/pal-mcp-server/issues/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

```python
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

```text
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:

```bash
pip install mcpreg-cli
```

Or clone and `pip install -e .` for development.

## Running the test suite

```bash
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](LICENSE).
