tappy-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tappy_mcp-0.1.0/.github/workflows/ci.yml +24 -0
- tappy_mcp-0.1.0/.gitignore +25 -0
- tappy_mcp-0.1.0/CHANGELOG.md +38 -0
- tappy_mcp-0.1.0/GUIDE.md +380 -0
- tappy_mcp-0.1.0/LICENSE +21 -0
- tappy_mcp-0.1.0/PKG-INFO +355 -0
- tappy_mcp-0.1.0/README.md +321 -0
- tappy_mcp-0.1.0/pyproject.toml +81 -0
- tappy_mcp-0.1.0/tappy/__init__.py +3 -0
- tappy_mcp-0.1.0/tappy/__main__.py +20 -0
- tappy_mcp-0.1.0/tappy/cli.py +888 -0
- tappy_mcp-0.1.0/tappy/core/__init__.py +1 -0
- tappy_mcp-0.1.0/tappy/core/adapters/__init__.py +28 -0
- tappy_mcp-0.1.0/tappy/core/adapters/base.py +115 -0
- tappy_mcp-0.1.0/tappy/core/adapters/claude_code.py +26 -0
- tappy_mcp-0.1.0/tappy/core/adapters/claude_desktop.py +31 -0
- tappy_mcp-0.1.0/tappy/core/adapters/cursor.py +26 -0
- tappy_mcp-0.1.0/tappy/core/adapters/generic.py +18 -0
- tappy_mcp-0.1.0/tappy/core/config_store.py +217 -0
- tappy_mcp-0.1.0/tappy/core/mcp_probe.py +240 -0
- tappy_mcp-0.1.0/tappy/core/models.py +124 -0
- tappy_mcp-0.1.0/tappy/core/registry.py +116 -0
- tappy_mcp-0.1.0/tappy/core/resolve.py +130 -0
- tappy_mcp-0.1.0/tappy/core/security.py +67 -0
- tappy_mcp-0.1.0/tappy/output.py +543 -0
- tappy_mcp-0.1.0/tests/__init__.py +0 -0
- tappy_mcp-0.1.0/tests/test_adapters.py +65 -0
- tappy_mcp-0.1.0/tests/test_cli.py +330 -0
- tappy_mcp-0.1.0/tests/test_config_store.py +112 -0
- tappy_mcp-0.1.0/tests/test_integration.py +44 -0
- tappy_mcp-0.1.0/tests/test_registry.py +138 -0
- tappy_mcp-0.1.0/tests/test_security.py +39 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: ${{ matrix.python-version }}
|
|
19
|
+
- name: Install
|
|
20
|
+
run: pip install -e ".[dev]"
|
|
21
|
+
- name: Lint
|
|
22
|
+
run: ruff check .
|
|
23
|
+
- name: Test
|
|
24
|
+
run: pytest -q
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
|
|
9
|
+
# Virtual envs
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
env/
|
|
13
|
+
|
|
14
|
+
# Tooling caches
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
|
|
19
|
+
# Editor / OS
|
|
20
|
+
.DS_Store
|
|
21
|
+
.idea/
|
|
22
|
+
.vscode/
|
|
23
|
+
|
|
24
|
+
# Local agent config
|
|
25
|
+
.claude/
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/), and the project aims to follow
|
|
5
|
+
[Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- Inspector primitives `tappy read <server> <uri>` (resource contents) and
|
|
11
|
+
`tappy prompt <server> <name>` (render a prompt) — all three MCP primitives are now
|
|
12
|
+
exercisable from the CLI.
|
|
13
|
+
- `tappy restore <client>` rolls a client config back to its latest backup (itself backed
|
|
14
|
+
up first); `tappy restore --list` shows available backups.
|
|
15
|
+
- `tappy add --dry-run` previews the change as a unified diff without writing.
|
|
16
|
+
- `--version` / `-V`.
|
|
17
|
+
- `--path` selector to disambiguate servers that exist in several configs of the same
|
|
18
|
+
client (e.g. Claude Code's project `./.mcp.json` vs. user `~/.claude.json`).
|
|
19
|
+
- `TAPPY_CONFIG` environment variable: point Tappy at extra config files (standard
|
|
20
|
+
`mcpServers` shape) it doesn't know natively.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- Renamed the monitoring commands: `ps` → `status`, `stats` → `watch`. Output and framing
|
|
24
|
+
no longer lean on Docker.
|
|
25
|
+
- `registry --init --from-client` now templates secret `env`/`header` values as `${KEY}`
|
|
26
|
+
placeholders instead of writing real secrets into the (git-committed) registry file.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- A config file that fails to parse is now flagged (`parse error`) and writes to it are
|
|
30
|
+
refused, instead of silently appearing empty and having a sentinel written back into it.
|
|
31
|
+
- `add` no longer mangles arguments that contain spaces (args are kept as a list).
|
|
32
|
+
- `disable` warns when the target client may not honor a `disabled` flag.
|
|
33
|
+
- Inspector/tool errors surface the real MCP cause instead of a TaskGroup wrapper message.
|
|
34
|
+
- Fingerprint store writes are now atomic.
|
|
35
|
+
|
|
36
|
+
## [0.1.0]
|
|
37
|
+
- Initial release: discovery, safe edits, MCP inspection, monitoring, tool-definition
|
|
38
|
+
pinning, and the team registry.
|
tappy_mcp-0.1.0/GUIDE.md
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
# Tappy — User Guide
|
|
2
|
+
|
|
3
|
+
A practical, task-oriented guide to using Tappy: the CLI that discovers, configures,
|
|
4
|
+
inspects, monitors, and standardizes **MCP (Model Context Protocol)** servers across your
|
|
5
|
+
AI clients (Claude Desktop, Claude Code, Cursor, and more).
|
|
6
|
+
|
|
7
|
+
If you just want the elevator pitch and install steps, see the [README](README.md). This
|
|
8
|
+
document is the hands-on manual.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Contents
|
|
13
|
+
|
|
14
|
+
1. [Install](#install)
|
|
15
|
+
2. [Core concepts](#core-concepts)
|
|
16
|
+
3. [Quick start](#quick-start)
|
|
17
|
+
4. [How you name a server (targeting)](#how-you-name-a-server-targeting)
|
|
18
|
+
5. [Command reference](#command-reference)
|
|
19
|
+
- [Manage](#manage)
|
|
20
|
+
- [Monitor](#monitor)
|
|
21
|
+
- [Inspect](#inspect)
|
|
22
|
+
- [Secure](#secure)
|
|
23
|
+
- [Team](#team)
|
|
24
|
+
6. [Common workflows](#common-workflows)
|
|
25
|
+
7. [Scripting & CI (JSON + exit codes)](#scripting--ci-json--exit-codes)
|
|
26
|
+
8. [Files, environment & configuration](#files-environment--configuration)
|
|
27
|
+
9. [Safety guarantees](#safety-guarantees)
|
|
28
|
+
10. [Troubleshooting](#troubleshooting)
|
|
29
|
+
11. [Security notes](#security-notes)
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
Requires Python 3.11+. The PyPI package is **`tappy-mcp`**; it installs the **`tappy`**
|
|
36
|
+
command.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install tappy-mcp
|
|
40
|
+
# or, isolated (recommended for CLI tools):
|
|
41
|
+
pipx install tappy-mcp
|
|
42
|
+
# or run without installing (the npx equivalent):
|
|
43
|
+
uvx tappy-mcp status
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Verify:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
tappy --version
|
|
50
|
+
tappy help # grouped overview of every command
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Core concepts
|
|
56
|
+
|
|
57
|
+
| Term | What it means in Tappy |
|
|
58
|
+
|------|------------------------|
|
|
59
|
+
| **Client** | An AI app that runs MCP servers (Claude Desktop, Claude Code, Cursor). Each stores servers in its own JSON config file. |
|
|
60
|
+
| **Server** | A single MCP server entry — either a local **stdio** process (`command` + `args`) or a remote **HTTP/SSE** endpoint (`url`). |
|
|
61
|
+
| **Transport** | How Tappy talks to a server: `stdio`, `http` (streamable), or `sse`. |
|
|
62
|
+
| **Health** | A server's *live* status, obtained by actually connecting and running the MCP handshake — never guessed from config. `running` / `error` / `disabled`. |
|
|
63
|
+
| **Pin / fingerprint** | A recorded hash of a server's tool definitions. Lets Tappy detect when a server changes its tools *after* you trusted it (a "rug-pull"). |
|
|
64
|
+
| **Registry** | A shared `tappy.team.json` listing the servers a team has approved, so everyone can converge on the same set. |
|
|
65
|
+
|
|
66
|
+
Tappy reads every client's config into **one normalized view**, so the same commands work
|
|
67
|
+
no matter which client a server lives in.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Quick start
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
tappy list # every server across every client
|
|
75
|
+
tappy status # ...with live health, latency, and tool counts
|
|
76
|
+
tappy inspect <name> # full report for one server: status + tools + resources + prompts
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Every data command supports `--json` and returns exit code **0** on success / **1** on
|
|
80
|
+
error, so it drops straight into scripts and CI.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## How you name a server (targeting)
|
|
85
|
+
|
|
86
|
+
Most commands take a **target**. There are two ways to specify one:
|
|
87
|
+
|
|
88
|
+
**1. By name** — a server already in some client's config:
|
|
89
|
+
```bash
|
|
90
|
+
tappy inspect github
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**2. Ad-hoc** — a server that isn't installed anywhere yet, described inline:
|
|
94
|
+
```bash
|
|
95
|
+
tappy inspect --command npx --args "-y @modelcontextprotocol/server-everything"
|
|
96
|
+
tappy inspect --url https://example.com/mcp
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Narrowing helpers (for named targets):
|
|
100
|
+
|
|
101
|
+
- `--client <id>` — restrict to one client (`claude_desktop`, `claude_code`, `cursor`, …).
|
|
102
|
+
- `--path <substring>` — restrict to configs whose file path contains a string. Use this
|
|
103
|
+
when the **same** client has the server in two places (e.g. Claude Code's project
|
|
104
|
+
`./.mcp.json` vs. user `~/.claude.json`):
|
|
105
|
+
```bash
|
|
106
|
+
tappy disable github --path .mcp.json # the project one, not the user one
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Auto-pick:** the read-only inspector commands (`inspect`, `tools`, `resources`,
|
|
110
|
+
`prompts`, `read`, `prompt`, `probe`, `pin`, `verify`, `call`) will use the sole configured
|
|
111
|
+
server automatically if you don't name one. Destructive commands (`remove`, `disable`,
|
|
112
|
+
`sync`) never auto-pick.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Command reference
|
|
117
|
+
|
|
118
|
+
Run `tappy <command> -h` for the exact flags of any command.
|
|
119
|
+
|
|
120
|
+
### Manage
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
tappy list # all servers across every client (alias: ls)
|
|
124
|
+
tappy list --client cursor # only one client
|
|
125
|
+
tappy clients # the discovered config files themselves
|
|
126
|
+
|
|
127
|
+
# add a stdio server (put the command after `--` so args like -y aren't seen as flags)
|
|
128
|
+
tappy add fs -- npx -y @modelcontextprotocol/server-filesystem .
|
|
129
|
+
|
|
130
|
+
# add a remote server
|
|
131
|
+
tappy add api --url https://example.com/mcp
|
|
132
|
+
tappy add api --url https://example.com/sse --transport sse --header "Authorization=Bearer XYZ"
|
|
133
|
+
|
|
134
|
+
# preview a change as a diff without writing anything
|
|
135
|
+
tappy add fs --dry-run -- npx -y @scope/server .
|
|
136
|
+
|
|
137
|
+
tappy enable fs # / tappy disable fs
|
|
138
|
+
tappy remove fs # (alias: rm)
|
|
139
|
+
|
|
140
|
+
# roll a client's config back to its most recent backup
|
|
141
|
+
tappy restore --list # show available backups
|
|
142
|
+
tappy restore claude_desktop # restore the latest backup for that client
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Notes:
|
|
146
|
+
- `add` writes to the **first discovered client** if you don't pass `--client`; it prints
|
|
147
|
+
which one it chose.
|
|
148
|
+
- Secret `env`/`header` values are **masked** in all output.
|
|
149
|
+
- A config file that fails to parse is flagged as `parse error`, and Tappy **refuses to
|
|
150
|
+
write to it** until you fix the JSON by hand.
|
|
151
|
+
|
|
152
|
+
### Monitor
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
tappy status # health snapshot of every server
|
|
156
|
+
tappy status -a # include disabled servers
|
|
157
|
+
tappy status --client cursor # restrict to one client
|
|
158
|
+
tappy status --fail-on-down # exit non-zero if any enabled server is unreachable (CI)
|
|
159
|
+
tappy status --json # machine-readable
|
|
160
|
+
|
|
161
|
+
tappy watch # live, auto-refreshing monitor (Ctrl-C to quit)
|
|
162
|
+
tappy watch --interval 2 # refresh faster
|
|
163
|
+
tappy watch --no-stream # print one snapshot and exit
|
|
164
|
+
|
|
165
|
+
tappy probe github # one-line health + latency for a single server
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`status`/`watch`/`probe` connect over the **real MCP protocol** — `STATUS` reflects an
|
|
169
|
+
actual handshake, not just whether the config exists. `status` also prints a footer
|
|
170
|
+
warning if any pinned server's tools have drifted.
|
|
171
|
+
|
|
172
|
+
### Inspect
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
tappy inspect github # status + tools + resources + prompts + pin status
|
|
176
|
+
tappy tools github # just the tools, with input schemas
|
|
177
|
+
tappy tools github --json
|
|
178
|
+
tappy resources github # list resource URIs
|
|
179
|
+
tappy prompts github # list prompt names
|
|
180
|
+
|
|
181
|
+
# exercise each of the three MCP primitives:
|
|
182
|
+
tappy call github create_issue -a title="Bug" -a body="..." # invoke a tool (key=value args)
|
|
183
|
+
tappy call github create_issue --input '{"title":"Bug"}' # ...or JSON args
|
|
184
|
+
tappy read github "file:///etc/hosts" # read a resource's contents
|
|
185
|
+
tappy prompt github review -a lang=python # render a prompt's messages
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
All of these work against installed servers **and** ad-hoc `--command`/`--url` targets.
|
|
189
|
+
|
|
190
|
+
### Secure
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
tappy pin github # trust the current tools (record a fingerprint)
|
|
194
|
+
tappy verify github # re-check; exit 1 if the tools changed (CI gate)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The first time you `pin`, Tappy stores a hash of the server's tool definitions. `verify`
|
|
198
|
+
compares against it later. A change means the server altered the tools it advertises after
|
|
199
|
+
you trusted it — a potential rug-pull. `inspect` shows pin status inline; `status` warns
|
|
200
|
+
about drift automatically.
|
|
201
|
+
|
|
202
|
+
### Team
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# create a shared registry, optionally seeded from a client you already have set up
|
|
206
|
+
tappy registry --init --from-client claude_desktop
|
|
207
|
+
tappy registry # show the approved server set (alias: team)
|
|
208
|
+
|
|
209
|
+
tappy apply --dry-run # preview provisioning into local clients
|
|
210
|
+
tappy apply # write them (each change backed up)
|
|
211
|
+
tappy apply --client cursor # only one client
|
|
212
|
+
|
|
213
|
+
tappy lint # report drift; exit 1 on unapproved servers (CI gate)
|
|
214
|
+
|
|
215
|
+
tappy sync github --from claude_desktop --to cursor # copy a server between clients
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Seeding from a client **never writes real secrets** into the registry: `env`/`header`
|
|
219
|
+
values are templated as `${KEY}` placeholders that each developer fills in locally after
|
|
220
|
+
`apply`. Commit `tappy.team.json`; teammates run `tappy apply`.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Common workflows
|
|
225
|
+
|
|
226
|
+
**"Is everything I rely on actually working right now?"**
|
|
227
|
+
```bash
|
|
228
|
+
tappy status
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**"A server is failing — what's wrong?"**
|
|
232
|
+
```bash
|
|
233
|
+
tappy probe <name> # confirm it's down and see the error
|
|
234
|
+
tappy inspect <name> # more detail if it connects at all
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**"I want to try a server before installing it anywhere."**
|
|
238
|
+
```bash
|
|
239
|
+
tappy inspect --command npx --args "-y @some/mcp-server"
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**"Copy a working server from one client to another."**
|
|
243
|
+
```bash
|
|
244
|
+
tappy sync <name> --from claude_desktop --to cursor
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**"Lock down a server so I get warned if it changes its tools."**
|
|
248
|
+
```bash
|
|
249
|
+
tappy pin <name>
|
|
250
|
+
# later, or in CI:
|
|
251
|
+
tappy verify <name> # exits 1 if the tools changed
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**"Undo a change I just made."**
|
|
255
|
+
```bash
|
|
256
|
+
tappy restore <client> # rolls back to the latest backup
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**"Standardize a team on the same servers."**
|
|
260
|
+
```bash
|
|
261
|
+
tappy registry --init --from-client claude_desktop # once, by a maintainer
|
|
262
|
+
git add tappy.team.json && git commit -m "Approved MCP servers"
|
|
263
|
+
# each teammate:
|
|
264
|
+
tappy apply
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Scripting & CI (JSON + exit codes)
|
|
270
|
+
|
|
271
|
+
Every data command accepts `--json` and emits pretty JSON to stdout. Secret values are
|
|
272
|
+
always masked.
|
|
273
|
+
|
|
274
|
+
**Exit codes:**
|
|
275
|
+
|
|
276
|
+
| Code | Meaning |
|
|
277
|
+
|------|---------|
|
|
278
|
+
| `0` | success |
|
|
279
|
+
| `1` | error — not found, unreachable, drift detected, or invalid input |
|
|
280
|
+
| `2` | bad command-line usage (argparse) |
|
|
281
|
+
| `130` | interrupted with Ctrl-C |
|
|
282
|
+
|
|
283
|
+
**CI gate examples:**
|
|
284
|
+
```bash
|
|
285
|
+
tappy status --fail-on-down # fail the build if any server is down
|
|
286
|
+
tappy verify weather # fail if a pinned server's tools changed
|
|
287
|
+
tappy lint # fail if any client has an unapproved server
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Parse output with `jq`:**
|
|
291
|
+
```bash
|
|
292
|
+
tappy status --json | jq '.[] | select(.health != "running") | .name'
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Files, environment & configuration
|
|
298
|
+
|
|
299
|
+
**Files Tappy owns** (all under `~/.tappy/`):
|
|
300
|
+
|
|
301
|
+
| Path | Purpose |
|
|
302
|
+
|------|---------|
|
|
303
|
+
| `~/.tappy/backups/` | Timestamped backups written before every config change. |
|
|
304
|
+
| `~/.tappy/fingerprints.json` | Pinned tool fingerprints for rug-pull detection. |
|
|
305
|
+
| `~/.tappy/tappy.team.json` | Default location for the team registry (user scope). |
|
|
306
|
+
|
|
307
|
+
**Client config files Tappy reads/writes** (discovered automatically):
|
|
308
|
+
|
|
309
|
+
- Claude Desktop — `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
310
|
+
(macOS), `%APPDATA%\Claude\…` (Windows), `~/.config/Claude/…` (Linux)
|
|
311
|
+
- Claude Code — `./.mcp.json` (project) and `~/.claude.json` (user)
|
|
312
|
+
- Cursor — `./.cursor/mcp.json` (project) and `~/.cursor/mcp.json` (user)
|
|
313
|
+
|
|
314
|
+
**Environment variables:**
|
|
315
|
+
|
|
316
|
+
| Variable | Effect |
|
|
317
|
+
|----------|--------|
|
|
318
|
+
| `TAPPY_CONFIG` | OS-path-separated list of extra config files (standard `mcpServers` shape) to manage — point Tappy at a client it doesn't know natively. |
|
|
319
|
+
| `TAPPY_REGISTRY` | Path to the team registry, overriding the default lookup. |
|
|
320
|
+
|
|
321
|
+
Registry path resolves from `--registry` → `$TAPPY_REGISTRY` → `./tappy.team.json` →
|
|
322
|
+
`~/.tappy/tappy.team.json`.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## Safety guarantees
|
|
327
|
+
|
|
328
|
+
When Tappy edits a config file, it guarantees:
|
|
329
|
+
|
|
330
|
+
- **Non-destructive** — only the `mcpServers` section is touched; every other key in the
|
|
331
|
+
file is preserved exactly.
|
|
332
|
+
- **Backup-first** — a timestamped copy is written to `~/.tappy/backups/` before any
|
|
333
|
+
change, so every edit is reversible with `tappy restore`.
|
|
334
|
+
- **Atomic** — writes go to a temp file and are then atomically renamed into place, so a
|
|
335
|
+
crash can never leave a half-written config.
|
|
336
|
+
- **Refuses broken files** — if a config can't be parsed, Tappy won't write to it (it would
|
|
337
|
+
otherwise clobber content it couldn't read).
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Troubleshooting
|
|
342
|
+
|
|
343
|
+
**`error: unknown command: X`** — run `tappy help` for the command list. Note the
|
|
344
|
+
monitoring commands are `status` and `watch` (not `ps`/`stats`).
|
|
345
|
+
|
|
346
|
+
**A server shows `error` in `status`/`probe`.** Tappy actually tried to connect. Common
|
|
347
|
+
causes: the `command` isn't on your `PATH`, a required runtime (`node`/`npx`/`uvx`) is
|
|
348
|
+
missing, a file path in `args` is wrong, or a remote `url` is unreachable. Run
|
|
349
|
+
`tappy probe <name>` to see the underlying error message.
|
|
350
|
+
|
|
351
|
+
**`... could not be parsed (…); fix its JSON by hand first`.** The client's config file has
|
|
352
|
+
invalid JSON. Fix the JSON, then retry. Tappy deliberately refuses to overwrite a file it
|
|
353
|
+
couldn't read.
|
|
354
|
+
|
|
355
|
+
**`server '<name>' exists in multiple configs`.** The name is defined in more than one
|
|
356
|
+
config. Disambiguate with `--client` and/or `--path` (the error lists each location).
|
|
357
|
+
|
|
358
|
+
**`no team registry found`.** Create one with `tappy registry --init`, or point at an
|
|
359
|
+
existing one with `--registry` / `$TAPPY_REGISTRY`.
|
|
360
|
+
|
|
361
|
+
**A remote server needs auth.** Pass headers when adding it:
|
|
362
|
+
`tappy add api --url … --header "Authorization=Bearer <token>"`. Header values are masked
|
|
363
|
+
in output.
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Security notes
|
|
368
|
+
|
|
369
|
+
- **Secrets in output are masked.** `env` and `header` values show as `***` in tables and
|
|
370
|
+
`--json`. The real values remain only in the client config files themselves.
|
|
371
|
+
- **The registry never carries real secrets.** Seeding writes `${KEY}` placeholders, not
|
|
372
|
+
your actual tokens — safe to commit to git.
|
|
373
|
+
- **Rug-pull detection.** Pin the servers you trust (`tappy pin`), then `tappy verify` (or
|
|
374
|
+
watch the `status` drift footer) to catch a server that changes its advertised tools
|
|
375
|
+
after approval. Re-pin intentionally when a change is expected.
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
*For the project overview, architecture, and contribution notes, see the
|
|
380
|
+
[README](README.md) and [CHANGELOG](CHANGELOG.md).*
|
tappy_mcp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 aadhil96
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|