Metadata-Version: 2.4
Name: tappy-mcp
Version: 0.1.0
Summary: MCP management + inspector + monitoring CLI: discover, configure, run, inspect and monitor MCP servers across AI clients.
Project-URL: Homepage, https://github.com/aadhil96/tappy
Project-URL: Repository, https://github.com/aadhil96/tappy
Project-URL: Issues, https://github.com/aadhil96/tappy/issues
Author: aadhil96
License-Expression: MIT
License-File: LICENSE
Keywords: ai,claude,cli,cursor,inspector,llm,mcp,model-context-protocol,monitoring
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Terminals
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Requires-Dist: mcp>=1.2
Requires-Dist: rich>=13
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Requires-Dist: twine>=5; extra == 'dev'
Description-Content-Type: text/markdown

<div align="center">

# Tappy

**One CLI to manage, inspect and monitor every MCP server you run.**

Works across Claude Desktop, Claude Code, Cursor — and any client with an `mcpServers` config.

[![CI](https://github.com/aadhil96/tappy/actions/workflows/ci.yml/badge.svg)](https://github.com/aadhil96/tappy/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/tappy-mcp.svg)](https://pypi.org/project/tappy-mcp/)
[![Python](https://img.shields.io/pypi/pyversions/tappy-mcp.svg)](https://pypi.org/project/tappy-mcp/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

[Install](#install) · [Quick start](#quick-start) · [CLI reference](#cli-reference) · [User Guide](GUIDE.md) · [Changelog](CHANGELOG.md)

</div>

---

## What is Tappy?

MCP servers are the plugins that give AI tools their real-world powers — filesystem
access, GitHub, databases, web search, custom APIs. But each AI client stores its servers
in its **own** JSON config file, in its own place, with no way to see whether a server
actually works or what it exposes.

**Tappy is the control panel for all of it** — a fast, scriptable CLI that reads every
client's config into one view and lets you:

- **see** every server across every client at a glance,
- **edit** them safely (with backups and validation, never raw JSON),
- **inspect** them over the real MCP protocol — list their tools/resources/prompts and
  even call a tool to test it,
- **monitor** their health and latency live (`tappy status`, `tappy watch`),
- **standardize** a server set across a whole team.

Everything is a command, so it drops straight into scripts, dotfiles and CI — every data
command supports `--json` and meaningful exit codes.

## Why Tappy exists

Managing MCP servers today means:

- **Scattered config** — `claude_desktop_config.json`, `~/.claude.json`,
  `.cursor/mcp.json`… all different, all edited by hand.
- **No visibility** — you can't tell which servers start, which are healthy, or what
  tools they expose without launching a client and hoping.
- **Risky edits** — one stray comma silently breaks a server.
- **No team story** — everyone configures their own servers slightly differently.
- **Security blind spots** — a server can quietly change the tools it offers *after*
  you've trusted it ("rug-pull").

Tappy fixes each of these with one tool that speaks the MCP protocol and treats your
config files with care.

## Features

### Configuration & discovery
- **Auto-discovers** servers across Claude Desktop, Claude Code (user + project) and
  Cursor — plus any custom config path.
- **Normalized model** — stdio, HTTP and SSE servers presented the same way.
- **One unified view** — `tappy list` shows every server across every client; `tappy add`
  / `remove` / `enable` / `disable` edit them without hand-touching JSON.

### Safe operations
- **Non-destructive writes** — only the `mcpServers` section is touched; everything else
  in the file is preserved.
- **Atomic + backed up** — every change is written atomically and a timestamped backup is
  saved to `~/.tappy/backups/` first.
- **Diff preview** before anything is written (`--dry-run`).
- **One-command rollback** — `tappy restore <client>` puts back the latest backup.
- **Enable / disable** a server in place without deleting it.

### Inspection & debugging (a terminal MCP Inspector)
- **Live status** over the real MCP protocol: `● running / ○ stopped / ⚠ error` with
  handshake latency.
- **Capability listing** — a server's actual **tools, resources and prompts** (with input
  schemas).
- **Tool runner** — invoke any tool with JSON/`key=value` args and see the raw response.
- **Ad-hoc inspection** — point Tappy at a server that isn't installed anywhere yet via
  `--command` / `--url`.

### Monitoring
- **`tappy status`** — a one-shot health snapshot of every server:
  `NAME / CLIENT / TRANSPORT / STATUS / LATENCY / TOOLS`, with a `running / total`
  summary. Servers are probed concurrently.
- **`tappy watch`** — a **live, auto-refreshing** monitor: the same table, re-probed on
  an interval, updating in place until you press Ctrl-C. Newly added/removed servers
  appear as you change configs.
- **`tappy probe`** — a single server's health + latency in one line, for healthchecks.

### Security
- **Tool-definition pinning** — Tappy fingerprints each server's tools the first time it
  trusts them and **warns you if they change later**, catching post-approval tool
  mutation ("rug-pull" / tool poisoning).
- Secret `env`/`header` **values are masked** in all output.

### Team registry
- A single git-tracked **`tappy.team.json`** as the source of truth for approved servers.
- **`tappy apply`** provisions it into everyone's local clients.
- **`tappy lint`** reports drift and exits non-zero on unapproved servers — a ready-made
  **CI gate**.
- **`tappy sync`** copies a server from one client to another.

## Install

Requires Python 3.11+. The PyPI package is **`tappy-mcp`**; it installs the **`tappy`**
command.

```bash
pip install tappy-mcp
```

Or, to keep it isolated in its own environment (recommended for CLI tools):

```bash
pipx install tappy-mcp        # or: uv tool install tappy-mcp
```

### Run without installing (the `npx` equivalent)

Tappy is a Python tool, so its "run-it-instantly" command is **`uvx`** (from
[uv](https://docs.astral.sh/uv/)) — the Python world's `npx`:

```bash
uvx tappy-mcp ps              # downloads + runs in a throwaway env, nothing to install
uvx tappy-mcp inspect <name>
```

Verify a normal install with:

```bash
tappy --version
tappy help
```

<details>
<summary>Install from source (for development)</summary>

```bash
git clone https://github.com/aadhil96/tappy.git
cd tappy
uv venv && uv pip install -e ".[dev]"   # or: pip install -e ".[dev]"
```
</details>

## Quick start

```bash
tappy list            # every server across every client
tappy status          # ...with live health, latency and tool counts
tappy inspect <name>  # full report for one server
tappy help            # grouped overview of every command
```

If you only have **one** server configured, the inspector commands don't need a name at
all — `tappy inspect`, `tappy tools`, `tappy probe` etc. just use it.

> New to Tappy? The [User Guide](GUIDE.md) is a hands-on manual covering every command,
> common workflows, scripting, and troubleshooting.

## CLI reference

Every data command supports `--json` (machine-readable) and uses meaningful exit codes,
so it drops straight into scripts and CI:

| Exit code | Meaning |
|-----------|---------|
| `0` | success |
| `1` | error — target not found, server unreachable, or a failed check (`verify` on changed tools, `lint` on unapproved servers, `status --fail-on-down`) |
| `2` | usage error (unknown command / bad flags) |

All probing commands accept `--timeout SECONDS` (default 20) for slow-starting servers.

### Manage
```bash
tappy list                         # all servers across every client
tappy clients                      # discovered client config files
tappy add fs -- npx -y @modelcontextprotocol/server-filesystem .   # add a stdio server
tappy add api --url https://example.com/mcp                        # add a remote server
tappy enable fs        # / tappy disable fs
tappy remove fs
tappy add fs --dry-run -- npx -y @scope/server .   # preview the change as a diff, write nothing
tappy restore --list   # show backups; restore a client's latest with: tappy restore claude_desktop
```
> Tip: put the stdio command after `--` so args like `-y` aren't mistaken for flags.

Every write is backed up to `~/.tappy/backups/` first, so any change is reversible with
`tappy restore <client>`.

When a server name lives in more than one config of the *same* client (e.g. Claude Code's
project `./.mcp.json` and user `~/.claude.json`), narrow it with `--path`:
```bash
tappy disable github --path .mcp.json     # the project one, not the user one
```
Point Tappy at a config it doesn't know natively by listing it in `$TAPPY_CONFIG`
(OS-path-separated), and it shows up everywhere `list`/`status` do:
```bash
export TAPPY_CONFIG=~/.config/some-client/mcp.json
```

### Monitor
```bash
tappy status                       # health snapshot of every server
tappy status -a                    # include disabled servers
tappy status --json                # machine-readable, for dashboards/CI
tappy status --fail-on-down        # exit non-zero if any server is unreachable (CI healthcheck)
tappy watch                        # live monitor, refreshes every 5s
tappy watch --interval 2           # refresh faster
tappy watch --no-stream            # one snapshot and exit
```
`status`/`watch` probe servers concurrently over the real MCP protocol — `STATUS` reflects
an actual handshake, not just whether the config exists. (Familiar if you've used
`docker ps`, but it talks MCP, not containers.)

### Secure (catch tool "rug-pulls")
A server can quietly change the tools it advertises *after* you've trusted it. Pin the
tools you approve, then verify later — `tappy status` also flags drift automatically.
```bash
tappy pin weather                  # record a fingerprint of the current tools
tappy verify weather               # re-check; exit 1 if the tools changed (CI gate)
```
`inspect` shows the pin status inline, and `status` prints a footer warning if any pinned
server's tools have drifted.

### Inspect (the MCP Inspector part)
```bash
tappy inspect fs                   # status + tools + resources + prompts + fingerprint
tappy inspect                      # name optional when exactly one server is configured
tappy tools fs --json              # tools with their input schemas
tappy resources fs                 # list resources
tappy prompts fs                   # list prompts
tappy probe fs                     # one-line health + latency
tappy call fs read_file -a path=README.md          # invoke a tool
tappy call fs read_file --input '{"path":"x"}'     # ...or pass JSON args
tappy read fs file:///etc/hosts                    # read a resource's actual contents
tappy prompt fs review -a lang=python              # render a prompt's messages

# inspect something not installed anywhere yet:
tappy inspect --command npx --args "-y @modelcontextprotocol/server-everything"
```
`tappy` speaks the full inspector surface: `tools`/`resources`/`prompts` list what a
server exposes, and `call`/`read`/`prompt` exercise each of the three MCP primitives.

### Team workflow
```bash
tappy registry --init --from-client claude_desktop   # create tappy.team.json, seeded
tappy registry                                        # show the approved server set
tappy apply --dry-run                                 # preview changes
tappy apply                                           # provision into local clients (backed up)
tappy lint                                            # report drift (exit 1 = CI gate)
tappy sync github --from claude_desktop --to cursor   # copy a server between clients
```
Registry path resolves from `--registry` → `$TAPPY_REGISTRY` → `./tappy.team.json` →
`~/.tappy/tappy.team.json`. Commit `tappy.team.json`; teammates run `tappy apply`.

Because the registry is meant to be committed, seeding from a client **never writes real
secrets**: `env`/`header` values are templated as `${KEY}` placeholders, which each
developer fills in locally after `apply`.

## Architecture

Every command is a thin shell over one shared core, so management, inspection and
monitoring all see the same data the same way.

```
tappy/
├── __main__.py       # console entry point
├── cli.py            # argparse CLI: management + inspector + monitoring
├── output.py         # rich tables (incl. status/watch monitor) + --json renderers
└── core/             # the shared engine
    ├── models.py         # normalized ServerDef / HealthStatus
    ├── config_store.py   # discovery + safe (atomic, backed-up) writes
    ├── adapters/         # one per client: claude_desktop, claude_code, cursor, generic
    ├── mcp_probe.py      # speaks MCP: initialize, list, call_tool, read_resource, get_prompt, probe_many, fingerprint
    ├── resolve.py        # resolve a target by name or ad-hoc flags
    ├── registry.py       # team registry: load / apply / lint / sync
    └── security.py       # tool-definition pinning store
```

**Built with:** Python · the official [`mcp`](https://modelcontextprotocol.io/) SDK ·
[Rich](https://rich.readthedocs.io/).

## Development

```bash
pytest                # run the test suite
ruff check .          # lint
python -m tappy ...   # equivalent to the `tappy` command

# opt in to the (slow, network) integration tests against a real MCP server:
TAPPY_INTEGRATION=1 pytest -m integration
```

CI (GitHub Actions) runs `ruff` and the test suite on Python 3.11–3.13 for every push
and pull request. Release history lives in the [changelog](CHANGELOG.md).

## Publishing (maintainers)

The distribution name on PyPI is `tappy-mcp`; the import package and CLI command are both
`tappy`.

```bash
pip install -e ".[dev]"          # includes build + twine
python -m build                  # creates dist/*.whl and dist/*.tar.gz
twine check dist/*               # validate metadata + README rendering
twine upload dist/*              # publish to PyPI (use TestPyPI first if unsure)
```

Bump `version` in `pyproject.toml` before each release and tag it (`git tag v0.1.0`).

## Roadmap

- `watch` history / sparklines (latency trend over time)
- Secrets → OS keychain
- Log tailing (stderr + client log files)
- Marketplace / registry install of popular servers

## License

MIT
