mcp-trove 0.2.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.
- mcp_trove-0.2.0/.gitignore +22 -0
- mcp_trove-0.2.0/CHANGELOG.md +73 -0
- mcp_trove-0.2.0/LICENSE +21 -0
- mcp_trove-0.2.0/PKG-INFO +333 -0
- mcp_trove-0.2.0/README.md +299 -0
- mcp_trove-0.2.0/pyproject.toml +66 -0
- mcp_trove-0.2.0/spec.md +142 -0
- mcp_trove-0.2.0/src/mcp_trove/__init__.py +3 -0
- mcp_trove-0.2.0/src/mcp_trove/cli.py +214 -0
- mcp_trove-0.2.0/src/mcp_trove/config.py +111 -0
- mcp_trove-0.2.0/src/mcp_trove/crypto.py +92 -0
- mcp_trove-0.2.0/src/mcp_trove/i18n.py +81 -0
- mcp_trove-0.2.0/src/mcp_trove/index.py +91 -0
- mcp_trove-0.2.0/src/mcp_trove/server.py +299 -0
- mcp_trove-0.2.0/src/mcp_trove/tools/__init__.py +1 -0
- mcp_trove-0.2.0/src/mcp_trove/tools/add_secret.py +92 -0
- mcp_trove-0.2.0/src/mcp_trove/tools/add_snippet.py +80 -0
- mcp_trove-0.2.0/src/mcp_trove/tools/doctor.py +175 -0
- mcp_trove-0.2.0/src/mcp_trove/tools/get_secret.py +54 -0
- mcp_trove-0.2.0/src/mcp_trove/tools/init_vault.py +219 -0
- mcp_trove-0.2.0/src/mcp_trove/tools/listing.py +22 -0
- mcp_trove-0.2.0/src/mcp_trove/tools/remove.py +70 -0
- mcp_trove-0.2.0/src/mcp_trove/tools/search.py +98 -0
- mcp_trove-0.2.0/src/mcp_trove/tools/update_secret.py +110 -0
- mcp_trove-0.2.0/src/mcp_trove/vault.py +149 -0
- mcp_trove-0.2.0/tests/conftest.py +24 -0
- mcp_trove-0.2.0/tests/test_cli.py +111 -0
- mcp_trove-0.2.0/tests/test_crypto.py +42 -0
- mcp_trove-0.2.0/tests/test_tools.py +178 -0
- mcp_trove-0.2.0/tests/test_vault.py +39 -0
- mcp_trove-0.2.0/uv.lock +1153 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
.eggs/
|
|
8
|
+
|
|
9
|
+
# Virtual envs
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
|
|
13
|
+
# Tooling caches
|
|
14
|
+
.pytest_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
|
|
18
|
+
# OS
|
|
19
|
+
.DS_Store
|
|
20
|
+
|
|
21
|
+
# Local environment
|
|
22
|
+
.env
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to mcp-trove are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.2.0] - 2026-06-29
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `trove_update_secret` tool: partially update an existing secret (set/remove
|
|
15
|
+
fields, change notes or tags) and re-encrypt, without re-supplying the whole
|
|
16
|
+
payload. Preserves the `created` date; decryption needs the private key,
|
|
17
|
+
re-encryption needs recipients.
|
|
18
|
+
- `trove` CLI bundled with the package (`[project.scripts]`): read and browse the
|
|
19
|
+
vault from a terminal without a running MCP client and without an external
|
|
20
|
+
`age` binary (decryption via the bundled `pyrage`). Subcommands `get`
|
|
21
|
+
(`--field`, `--clip`, `--json`), `list`, `search` (`--tags`, `--kind`). `--clip`
|
|
22
|
+
copies to the system clipboard (`pbcopy`/`wl-copy`/`xclip`/`xsel`/`clip`),
|
|
23
|
+
keeping the value off the terminal. Reuses the existing `get_secret`,
|
|
24
|
+
`list_entries` and `search` functions — no new crypto. Exit codes: 0 ok,
|
|
25
|
+
1 application error, 2 if `TROVE_PATH` is unset.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- Frontmatter is now read and written through PyYAML instead of a hand-rolled
|
|
30
|
+
parser, so values with colons, hashes, commas or unicode round-trip safely.
|
|
31
|
+
Backward compatible: legacy inline `[a, b]` lists still parse. Adds a `pyyaml`
|
|
32
|
+
dependency.
|
|
33
|
+
- `trove_init` auto-enables the pre-commit hook (`git config core.hooksPath
|
|
34
|
+
.githooks`) when the vault is a git repo, instead of only printing a hint; if a
|
|
35
|
+
different hooks path is already set it is left untouched with a warning.
|
|
36
|
+
- `trove_doctor` adds a `git_remote_present` reminder (cleartext metadata gets
|
|
37
|
+
pushed; keep the remote private) and no longer flags OS noise (`.DS_Store`,
|
|
38
|
+
`Thumbs.db`) under `secrets/` as a cleartext-secret critical.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- `trove_get_secret` (and the `trove get` CLI) no longer silently return the
|
|
43
|
+
first match when a slug exists in multiple categories: it now errors and lists
|
|
44
|
+
the candidate categories so the caller can disambiguate.
|
|
45
|
+
|
|
46
|
+
### Documentation
|
|
47
|
+
|
|
48
|
+
- README: add a "Key management" section (EN + IT) covering key lookup order
|
|
49
|
+
(`TROVE_KEY_PATH` / `trove.toml` `key_path` / default `~/.config/trove/key`),
|
|
50
|
+
file format, backup, and step-by-step restore on another machine.
|
|
51
|
+
- README: add a "Reading secrets without the MCP" section (EN + IT) — leads with
|
|
52
|
+
the `trove` CLI, with the `age`/`rage` CLI as a low-level fallback, and explains
|
|
53
|
+
why the `secrets/` folder looks empty in Markdown readers (Obsidian lists only
|
|
54
|
+
`.md`, not `.age`/`.meta.yaml`).
|
|
55
|
+
|
|
56
|
+
## [0.1.0] - 2026-06-29
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- Initial release. MCP server managing a git-backed vault of plaintext snippets
|
|
61
|
+
and encrypted secrets, with i18n (English default, Italian shipped).
|
|
62
|
+
- Encryption via `age` (through the `pyrage` binding); secrets are stored
|
|
63
|
+
ASCII-armored so they live well in git. The private key lives outside the repo;
|
|
64
|
+
the public recipient is committed in `trove.toml`.
|
|
65
|
+
- Tools: `trove_init`, `trove_add_snippet`, `trove_add_secret`,
|
|
66
|
+
`trove_get_secret`, `trove_search`, `trove_list`, `trove_index`,
|
|
67
|
+
`trove_remove`, `trove_doctor`.
|
|
68
|
+
- Secrets are split into an encrypted payload (`.age`) and a cleartext metadata
|
|
69
|
+
sidecar (`.meta.yaml`) holding only non-sensitive fields, so the index and
|
|
70
|
+
search never expose a secret value.
|
|
71
|
+
- `trove_doctor` read-only audit: missing key, no recipients, cleartext under
|
|
72
|
+
`secrets/`, orphan payload/metadata, broken frontmatter, a private key in the
|
|
73
|
+
tree, missing pre-commit hook.
|
mcp_trove-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Maurizio Mocci
|
|
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.
|
mcp_trove-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mcp-trove
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: MCP server for a git-backed vault of plaintext snippets and encrypted secrets, with i18n support
|
|
5
|
+
Project-URL: Homepage, https://github.com/mauriziomocci/mcp-trove
|
|
6
|
+
Project-URL: Repository, https://github.com/mauriziomocci/mcp-trove
|
|
7
|
+
Project-URL: Issues, https://github.com/mauriziomocci/mcp-trove/issues
|
|
8
|
+
Author-email: Maurizio Mocci <mauriziomocci@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: age,encryption,markdown,mcp,secrets,snippets,trove,vault
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Natural Language :: English
|
|
16
|
+
Classifier: Natural Language :: Italian
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Security :: Cryptography
|
|
23
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: mcp>=1.0.0
|
|
26
|
+
Requires-Dist: pyrage>=1.1.0
|
|
27
|
+
Requires-Dist: pyyaml>=6.0
|
|
28
|
+
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# mcp-trove
|
|
36
|
+
|
|
37
|
+
An MCP server that manages a **trove**: a git-backed vault holding two kinds of
|
|
38
|
+
entry — plaintext **snippets** (searchable Markdown, with images and diagrams)
|
|
39
|
+
and **secrets** stored **encrypted at rest**, so the whole vault can be pushed to
|
|
40
|
+
a private remote without exposing them. A trove holds both treasures (secrets)
|
|
41
|
+
and finds (snippets).
|
|
42
|
+
|
|
43
|
+
The server is the deterministic writer over the vault: the calling model composes
|
|
44
|
+
and cleans content, the server guarantees placement, slug, frontmatter,
|
|
45
|
+
encryption and index — always the same, no drift.
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install mcp-trove # or: uv add mcp-trove
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`pip install` is self-contained — encryption uses the `age` algorithm through the
|
|
54
|
+
`pyrage` binding, so no external binary is required.
|
|
55
|
+
|
|
56
|
+
## Configure
|
|
57
|
+
|
|
58
|
+
The vault root comes from the `TROVE_PATH` environment variable. Register the
|
|
59
|
+
server with your MCP client (Claude Code shown):
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
"trove": {
|
|
63
|
+
"type": "stdio",
|
|
64
|
+
"command": "uv",
|
|
65
|
+
"args": ["--directory", "/path/to/mcp-trove", "run", "mcp-trove"],
|
|
66
|
+
"env": { "TROVE_PATH": "/path/to/your/trove" }
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Then call `trove_init` once to scaffold the vault and generate the age keypair.
|
|
71
|
+
The private key is written outside the repo (default `~/.config/trove/key`); the
|
|
72
|
+
public recipient is committed in `trove.toml`.
|
|
73
|
+
|
|
74
|
+
> **Back up your private key off-machine** (e.g. a password manager). Without it
|
|
75
|
+
> the encrypted secrets are unrecoverable, even for you. On a new machine you
|
|
76
|
+
> clone the git vault and restore the key separately — cloning alone cannot
|
|
77
|
+
> decrypt, by design.
|
|
78
|
+
|
|
79
|
+
## Key management
|
|
80
|
+
|
|
81
|
+
There are two keys, and only one is secret.
|
|
82
|
+
|
|
83
|
+
- **Public recipient** (`age1...`) — committed in `trove.toml` under
|
|
84
|
+
`recipients`. Secrets are *encrypted to* it. Safe to share.
|
|
85
|
+
- **Private key** (`AGE-SECRET-KEY-1...`) — *decrypts* secrets. Never commit it.
|
|
86
|
+
|
|
87
|
+
**Where it lives.** Trove looks for the private key in this order:
|
|
88
|
+
|
|
89
|
+
1. `TROVE_KEY_PATH` environment variable, if set.
|
|
90
|
+
2. `key_path` under `[trove]` in `trove.toml`, if set.
|
|
91
|
+
3. Default: `~/.config/trove/key`.
|
|
92
|
+
|
|
93
|
+
**File format.** A plain text file containing a single `AGE-SECRET-KEY-1...`
|
|
94
|
+
line (lines starting with `#` are ignored). Keep it `chmod 600`.
|
|
95
|
+
|
|
96
|
+
**Creating it.** `trove_init` generates the keypair on first run: it writes the
|
|
97
|
+
private key to the resolved path (mode 600) and records the public recipient in
|
|
98
|
+
`trove.toml`. You don't create it by hand.
|
|
99
|
+
|
|
100
|
+
**Backing it up.** Copy that single file somewhere off this machine — your
|
|
101
|
+
password manager is ideal. This is the only thing that cannot be regenerated.
|
|
102
|
+
|
|
103
|
+
**Restoring on another machine.**
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
mkdir -p ~/.config/trove
|
|
107
|
+
# paste your backed-up key into the file, one AGE-SECRET-KEY-1... line:
|
|
108
|
+
$EDITOR ~/.config/trove/key
|
|
109
|
+
chmod 600 ~/.config/trove/key
|
|
110
|
+
git clone <your-private-vault-repo> /path/to/your/trove # the snippets + encrypted secrets
|
|
111
|
+
export TROVE_PATH=/path/to/your/trove
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The git clone brings the vault (snippets and encrypted secrets); the key file
|
|
115
|
+
brings the ability to decrypt. With both in place, `trove_get_secret` works.
|
|
116
|
+
|
|
117
|
+
## Reading secrets without the MCP
|
|
118
|
+
|
|
119
|
+
The MCP is a convenience, not a lock-in. The package ships a `trove` command
|
|
120
|
+
alongside the server, so you can read and browse the vault straight from a
|
|
121
|
+
terminal — no MCP client running, and no external `age` binary (decryption goes
|
|
122
|
+
through the bundled `pyrage`). It reads the same `TROVE_PATH` and private key the
|
|
123
|
+
server uses.
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
trove get jira # decrypt and print all fields
|
|
127
|
+
trove get jira --field password # print one raw value (pipe-friendly)
|
|
128
|
+
trove get jira --field password --clip # copy to clipboard, keep it off-screen
|
|
129
|
+
trove get jira --json # machine-readable dump
|
|
130
|
+
trove list # list every entry
|
|
131
|
+
trove search grafana --kind secret # search (metadata only for secrets)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`--clip` shells out to the platform clipboard tool (`pbcopy`, `wl-copy`, `xclip`,
|
|
135
|
+
`xsel`, or `clip`); if none is present it errors instead of printing.
|
|
136
|
+
|
|
137
|
+
As a low-level fallback, secrets are plain `age` files (ASCII-armored,
|
|
138
|
+
`-----BEGIN AGE ENCRYPTED FILE-----`), so the standard `age` CLI decrypts them
|
|
139
|
+
too:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
age -d -i ~/.config/trove/key <trove>/secrets/<category>/<slug>.age
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`rage` (the Rust implementation) works the same way. Security lives entirely in
|
|
146
|
+
the private key, not in the server: whoever holds `~/.config/trove/key` can read
|
|
147
|
+
every secret, with or without the MCP.
|
|
148
|
+
|
|
149
|
+
Note on Markdown readers (Obsidian, etc.): the `secrets/` folder looks **empty**
|
|
150
|
+
because those tools list only `.md` files, and secrets are `.age` payloads plus
|
|
151
|
+
`.meta.yaml` sidecars. The files are there — enable "Detect all file extensions"
|
|
152
|
+
to see them. The `.age` stays unreadable (encrypted) and the `.meta.yaml` shows
|
|
153
|
+
only title and tags, never values. Use Markdown readers for `snippets/`; manage
|
|
154
|
+
secrets through the MCP tools or the `age` CLI.
|
|
155
|
+
|
|
156
|
+
## Tools
|
|
157
|
+
|
|
158
|
+
| Tool | Purpose |
|
|
159
|
+
|---|---|
|
|
160
|
+
| `trove_init` | Scaffold the vault, generate/register the keypair, write config, hooks |
|
|
161
|
+
| `trove_add_snippet` | Save a plaintext snippet (Markdown + frontmatter) |
|
|
162
|
+
| `trove_add_secret` | Save an encrypted secret + cleartext metadata sidecar |
|
|
163
|
+
| `trove_get_secret` | Decrypt a secret on the fly (needs the private key) |
|
|
164
|
+
| `trove_update_secret` | Partially update a secret (set/remove fields, notes, tags) and re-encrypt |
|
|
165
|
+
| `trove_search` | Full-text over snippets; metadata-only over secrets |
|
|
166
|
+
| `trove_list` / `trove_index` | List entries / regenerate `INDEX.md` |
|
|
167
|
+
| `trove_remove` | Delete an entry and rebuild the index |
|
|
168
|
+
| `trove_doctor` | Read-only health & safety audit |
|
|
169
|
+
|
|
170
|
+
## Layout
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
<trove>/
|
|
174
|
+
snippets/<domain>/<sub>/<slug>.md plaintext markdown + frontmatter
|
|
175
|
+
secrets/<category>/<slug>.age encrypted payload (armored age)
|
|
176
|
+
secrets/<category>/<slug>.meta.yaml cleartext metadata, never values
|
|
177
|
+
_assets/ images, diagrams
|
|
178
|
+
INDEX.md generated
|
|
179
|
+
trove.toml vault config (recipients, language)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Snippets render in any Markdown reader (Obsidian, VS Code, GitHub). The index and
|
|
183
|
+
search read only cleartext metadata for secrets, so they can never leak a value.
|
|
184
|
+
|
|
185
|
+
## Security model
|
|
186
|
+
|
|
187
|
+
- Encryption is delegated to vetted code (`age`/`pyrage`); none is written here.
|
|
188
|
+
- The private key lives outside the repo and is git-ignored.
|
|
189
|
+
- `trove_add_secret` encrypts in memory; plaintext never touches disk.
|
|
190
|
+
- `trove_init` installs a pre-commit hook that blocks committing a private key,
|
|
191
|
+
and enables it automatically (`core.hooksPath`) when the vault is a git repo.
|
|
192
|
+
- `trove_doctor` flags any cleartext under `secrets/` or a key in the tree, and
|
|
193
|
+
reminds you when a git remote is configured.
|
|
194
|
+
|
|
195
|
+
**Cleartext metadata caveat.** Secret *values* are encrypted, but the
|
|
196
|
+
`.meta.yaml` sidecars — titles, tags, category names — are cleartext and get
|
|
197
|
+
pushed with the vault. Keep the remote **private** and avoid putting sensitive
|
|
198
|
+
details in secret titles (prefer "Prod DB" over "Prod DB root password h***").
|
|
199
|
+
|
|
200
|
+
## Development
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
uv sync --extra dev
|
|
204
|
+
uv run pytest
|
|
205
|
+
uv run ruff check src tests
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
# mcp-trove (Italiano)
|
|
211
|
+
|
|
212
|
+
Server MCP che gestisce un **trove**: un vault versionato con git che contiene due
|
|
213
|
+
tipi di voce — **snippet** in chiaro (Markdown cercabile, con immagini e schemi) e
|
|
214
|
+
**segreti** salvati **cifrati a riposo**, così l'intero vault si pubblica su un
|
|
215
|
+
remote privato senza esporli. Un trove custodisce sia i tesori (i segreti) sia i
|
|
216
|
+
ritrovamenti (gli snippet).
|
|
217
|
+
|
|
218
|
+
Il server è lo scrittore deterministico del vault: il modello compone e ripulisce
|
|
219
|
+
il contenuto, il server garantisce collocazione, slug, frontmatter, cifratura e
|
|
220
|
+
indice — sempre uguali, senza deriva.
|
|
221
|
+
|
|
222
|
+
## Installazione
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
pip install mcp-trove
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
L'installazione è autosufficiente: la cifratura usa l'algoritmo `age` tramite il
|
|
229
|
+
binding `pyrage`, nessun binario esterno richiesto.
|
|
230
|
+
|
|
231
|
+
## Configurazione
|
|
232
|
+
|
|
233
|
+
La radice del vault arriva dalla variabile d'ambiente `TROVE_PATH`. Registra il
|
|
234
|
+
server nel tuo client MCP (esempio Claude Code) come mostrato sopra, poi chiama
|
|
235
|
+
`trove_init` una volta per creare il vault e generare la coppia di chiavi age.
|
|
236
|
+
|
|
237
|
+
> **Fai un backup della chiave privata fuori dalla macchina** (es. password
|
|
238
|
+
> manager). Senza, i segreti cifrati sono irrecuperabili, anche per te. Su un PC
|
|
239
|
+
> nuovo cloni il vault git e ripristini la chiave a parte: clonare e basta non
|
|
240
|
+
> decifra, per scelta.
|
|
241
|
+
|
|
242
|
+
## Gestione della chiave
|
|
243
|
+
|
|
244
|
+
Le chiavi sono due, e solo una è segreta.
|
|
245
|
+
|
|
246
|
+
- **Recipient pubblico** (`age1...`) — committato in `trove.toml` sotto
|
|
247
|
+
`recipients`. I segreti vengono *cifrati verso* di lui. Si può condividere.
|
|
248
|
+
- **Chiave privata** (`AGE-SECRET-KEY-1...`) — *decifra* i segreti. Mai committarla.
|
|
249
|
+
|
|
250
|
+
**Dove vive.** Trove cerca la chiave privata in quest'ordine:
|
|
251
|
+
|
|
252
|
+
1. variabile d'ambiente `TROVE_KEY_PATH`, se impostata;
|
|
253
|
+
2. `key_path` sotto `[trove]` in `trove.toml`, se impostato;
|
|
254
|
+
3. default: `~/.config/trove/key`.
|
|
255
|
+
|
|
256
|
+
**Formato del file.** Un file di testo con una sola riga `AGE-SECRET-KEY-1...`
|
|
257
|
+
(le righe che iniziano con `#` sono ignorate). Tienilo a `chmod 600`.
|
|
258
|
+
|
|
259
|
+
**Creazione.** `trove_init` genera la coppia al primo avvio: scrive la chiave
|
|
260
|
+
privata nel path risolto (permessi 600) e registra il recipient pubblico in
|
|
261
|
+
`trove.toml`. Non la crei a mano.
|
|
262
|
+
|
|
263
|
+
**Backup.** Copia quel singolo file fuori da questa macchina — il password
|
|
264
|
+
manager è il posto ideale. È l'unica cosa che non si può rigenerare.
|
|
265
|
+
|
|
266
|
+
**Ripristino su un'altra macchina.**
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
mkdir -p ~/.config/trove
|
|
270
|
+
# incolla la chiave salvata nel file, una riga AGE-SECRET-KEY-1...:
|
|
271
|
+
$EDITOR ~/.config/trove/key
|
|
272
|
+
chmod 600 ~/.config/trove/key
|
|
273
|
+
git clone <repo-privato-del-vault> /path/to/your/trove # snippet + segreti cifrati
|
|
274
|
+
export TROVE_PATH=/path/to/your/trove
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Il clone git porta il vault (snippet e segreti cifrati); il file chiave porta la
|
|
278
|
+
capacità di decifrare. Con entrambi a posto, `trove_get_secret` funziona.
|
|
279
|
+
|
|
280
|
+
## Leggere i segreti senza l'MCP
|
|
281
|
+
|
|
282
|
+
L'MCP è una comodità, non un vincolo. Il package installa un comando `trove`
|
|
283
|
+
accanto al server, così leggi e navighi il vault direttamente da terminale —
|
|
284
|
+
senza client MCP attivo e senza binario `age` esterno (la decifratura passa per
|
|
285
|
+
`pyrage` già incluso). Usa lo stesso `TROVE_PATH` e la stessa chiave privata del
|
|
286
|
+
server.
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
trove get jira # decifra e stampa tutti i campi
|
|
290
|
+
trove get jira --field password # stampa un solo valore grezzo (per pipe)
|
|
291
|
+
trove get jira --field password --clip # copia negli appunti, fuori dallo schermo
|
|
292
|
+
trove get jira --json # output leggibile dalle macchine
|
|
293
|
+
trove list # elenca ogni voce
|
|
294
|
+
trove search grafana --kind secret # cerca (solo metadata per i segreti)
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
`--clip` invoca il tool clipboard di sistema (`pbcopy`, `wl-copy`, `xclip`,
|
|
298
|
+
`xsel` o `clip`); se non ce n'è nessuno dà errore invece di stampare.
|
|
299
|
+
|
|
300
|
+
Come fallback di basso livello, i segreti sono normali file `age` (in armor
|
|
301
|
+
ASCII, `-----BEGIN AGE ENCRYPTED FILE-----`), quindi anche la CLI standard `age`
|
|
302
|
+
li decifra:
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
age -d -i ~/.config/trove/key <trove>/secrets/<categoria>/<slug>.age
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Anche `rage` (l'implementazione Rust) funziona allo stesso modo. La sicurezza sta
|
|
309
|
+
tutta nella chiave privata, non nel server: chi possiede `~/.config/trove/key`
|
|
310
|
+
legge ogni segreto, con o senza l'MCP.
|
|
311
|
+
|
|
312
|
+
Nota sui lettori Markdown (Obsidian, ecc.): la cartella `secrets/` appare
|
|
313
|
+
**vuota** perché quegli strumenti elencano solo i file `.md`, mentre i segreti
|
|
314
|
+
sono payload `.age` più sidecar `.meta.yaml`. I file ci sono — attiva "Detect all
|
|
315
|
+
file extensions" per vederli. Il `.age` resta illeggibile (cifrato) e il
|
|
316
|
+
`.meta.yaml` mostra solo titolo e tag, mai i valori. Usa i lettori Markdown per
|
|
317
|
+
gli `snippets/`; i segreti gestiscili con gli strumenti MCP o con la CLI `age`.
|
|
318
|
+
|
|
319
|
+
## Modello di sicurezza
|
|
320
|
+
|
|
321
|
+
- La cifratura è delegata a codice collaudato (`age`/`pyrage`), nessuna scritta
|
|
322
|
+
qui.
|
|
323
|
+
- La chiave privata vive fuori dal repo ed è esclusa da git.
|
|
324
|
+
- `trove_add_secret` cifra in memoria; il testo in chiaro non tocca mai il disco.
|
|
325
|
+
- `trove_init` installa un hook pre-commit che blocca il commit di una chiave
|
|
326
|
+
privata e lo abilita da solo (`core.hooksPath`) quando il vault è un repo git.
|
|
327
|
+
- `trove_doctor` segnala qualsiasi file in chiaro sotto `secrets/` o una chiave
|
|
328
|
+
nell'albero, e ti avvisa quando è configurato un remote git.
|
|
329
|
+
|
|
330
|
+
**Caveat metadati in chiaro.** I *valori* dei segreti sono cifrati, ma i sidecar
|
|
331
|
+
`.meta.yaml` — titoli, tag, nomi di categoria — sono in chiaro e vengono pushati
|
|
332
|
+
col vault. Tieni il remote **privato** ed evita dettagli sensibili nei titoli
|
|
333
|
+
(meglio "Prod DB" che "Prod DB password di root h***").
|