MCP management + inspector + monitoring CLI: discover, configure, run, inspect and monitor MCP servers across AI clients.
Project description
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.
Install · Quick start · CLI reference · User Guide · Changelog
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 listshows every server across every client;tappy add/remove/enable/disableedit them without hand-touching JSON.
Safe operations
- Non-destructive writes — only the
mcpServerssection 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 / ⚠ errorwith handshake latency. - Capability listing — a server's actual tools, resources and prompts (with input schemas).
- Tool runner — invoke any tool with JSON/
key=valueargs 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 arunning / totalsummary. 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/headervalues are masked in all output.
Team registry
- A single git-tracked
tappy.team.jsonas the source of truth for approved servers. tappy applyprovisions it into everyone's local clients.tappy lintreports drift and exits non-zero on unapproved servers — a ready-made CI gate.tappy synccopies a server from one client to another.
Install
Requires Python 3.11+. The PyPI package is tappy-mcp; it installs the tappy
command.
pip install tappy-mcp
Or, to keep it isolated in its own environment (recommended for CLI tools):
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) — the Python world's npx:
uvx tappy-mcp ps # downloads + runs in a throwaway env, nothing to install
uvx tappy-mcp inspect <name>
Verify a normal install with:
tappy --version
tappy help
Install from source (for development)
git clone https://github.com/aadhil96/tappy.git
cd tappy
uv venv && uv pip install -e ".[dev]" # or: pip install -e ".[dev]"
Quick start
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 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
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-yaren'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:
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:
export TAPPY_CONFIG=~/.config/some-client/mcp.json
Monitor
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.
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)
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
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 SDK ·
Rich.
Development
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.
Publishing (maintainers)
The distribution name on PyPI is tappy-mcp; the import package and CLI command are both
tappy.
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
watchhistory / sparklines (latency trend over time)- Secrets → OS keychain
- Log tailing (stderr + client log files)
- Marketplace / registry install of popular servers
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tappy_mcp-0.1.0.tar.gz.
File metadata
- Download URL: tappy_mcp-0.1.0.tar.gz
- Upload date:
- Size: 44.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f62622e147c14932e80fdebb0fe84360c390373d4b835033c7236362fae015f
|
|
| MD5 |
0057a495708fe15d72de9b2ff2505eb4
|
|
| BLAKE2b-256 |
167a82546d58c3e3cecd6635b390aa30ede8818e16355a0e93d7333f0971b341
|
File details
Details for the file tappy_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: tappy_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 40.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b3123f1b1039b39ab857270285d66bf3ba27ae5afae38d90d535c8557448aacc
|
|
| MD5 |
31c144715863d6411039c09579f4d6a3
|
|
| BLAKE2b-256 |
88f7fb87bf366ae474dd39c94fe580d1a7a263b4e204a4fce25d6f15671207d9
|