vaultzero 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.
- vaultzero-0.1.0/.gitignore +69 -0
- vaultzero-0.1.0/LICENSE +21 -0
- vaultzero-0.1.0/PKG-INFO +236 -0
- vaultzero-0.1.0/README.md +202 -0
- vaultzero-0.1.0/pyproject.toml +96 -0
- vaultzero-0.1.0/tests/__init__.py +0 -0
- vaultzero-0.1.0/tests/unit/__init__.py +0 -0
- vaultzero-0.1.0/tests/unit/golden_vectors.json +24 -0
- vaultzero-0.1.0/tests/unit/test_crypto.py +165 -0
- vaultzero-0.1.0/tests/unit/test_sdk_and_mcp.py +132 -0
- vaultzero-0.1.0/vaultzero/__init__.py +4 -0
- vaultzero-0.1.0/vaultzero/client/__init__.py +1 -0
- vaultzero-0.1.0/vaultzero/client/_net.py +21 -0
- vaultzero-0.1.0/vaultzero/client/crypto.py +102 -0
- vaultzero-0.1.0/vaultzero/client/embeddings.py +182 -0
- vaultzero-0.1.0/vaultzero/client/mcp_server.py +153 -0
- vaultzero-0.1.0/vaultzero/client/sdk.py +470 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# Unit test / coverage reports
|
|
30
|
+
htmlcov/
|
|
31
|
+
.tox/
|
|
32
|
+
.nox/
|
|
33
|
+
.coverage
|
|
34
|
+
.coverage.*
|
|
35
|
+
.cache
|
|
36
|
+
nosetests.xml
|
|
37
|
+
coverage.xml
|
|
38
|
+
*.cover
|
|
39
|
+
*.py.cover
|
|
40
|
+
*.lcov
|
|
41
|
+
.hypothesis/
|
|
42
|
+
.pytest_cache/
|
|
43
|
+
cover/
|
|
44
|
+
|
|
45
|
+
# Environments
|
|
46
|
+
.env
|
|
47
|
+
.envrc
|
|
48
|
+
.venv
|
|
49
|
+
env/
|
|
50
|
+
venv/
|
|
51
|
+
ENV/
|
|
52
|
+
env.bak/
|
|
53
|
+
venv.bak/
|
|
54
|
+
|
|
55
|
+
# mypy / pyre / pytype
|
|
56
|
+
.mypy_cache/
|
|
57
|
+
.dmypy.json
|
|
58
|
+
dmypy.json
|
|
59
|
+
.pyre/
|
|
60
|
+
.pytype/
|
|
61
|
+
|
|
62
|
+
# Ruff
|
|
63
|
+
.ruff_cache/
|
|
64
|
+
|
|
65
|
+
# PyPI configuration file
|
|
66
|
+
.pypirc
|
|
67
|
+
|
|
68
|
+
# JetBrains IDE
|
|
69
|
+
.idea/
|
vaultzero-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 VaultZero contributors
|
|
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.
|
vaultzero-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: vaultzero
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server for a privacy-first agent memory vault: memories are encrypted on the client before they reach the server.
|
|
5
|
+
Project-URL: Homepage, https://vaultzero.cc
|
|
6
|
+
Project-URL: Documentation, https://github.com/xo0ps/VaultZero-Client#readme
|
|
7
|
+
Project-URL: Issues, https://github.com/xo0ps/VaultZero-Client/issues
|
|
8
|
+
Project-URL: Repository, https://github.com/xo0ps/VaultZero-Client
|
|
9
|
+
Project-URL: Source, https://github.com/xo0ps/VaultZero-Client
|
|
10
|
+
Author: VaultZero contributors
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: agent-memory,ai-agents,encryption,end-to-end-encryption,llm,long-term-memory,mcp,model-context-protocol,privacy
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Classifier: Topic :: Security :: Cryptography
|
|
20
|
+
Requires-Python: <3.14,>=3.13
|
|
21
|
+
Provides-Extra: client
|
|
22
|
+
Requires-Dist: cryptography>=43; extra == 'client'
|
|
23
|
+
Requires-Dist: httpx>=0.28; extra == 'client'
|
|
24
|
+
Requires-Dist: mcp<2,>=1.6; extra == 'client'
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest-asyncio>=0.25; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=8.3; extra == 'dev'
|
|
28
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
29
|
+
Provides-Extra: mcp
|
|
30
|
+
Requires-Dist: cryptography>=43; extra == 'mcp'
|
|
31
|
+
Requires-Dist: httpx>=0.28; extra == 'mcp'
|
|
32
|
+
Requires-Dist: mcp<2,>=1.6; extra == 'mcp'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# VaultZero Client
|
|
36
|
+
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
[](https://modelcontextprotocol.io)
|
|
39
|
+
[](https://www.python.org)
|
|
40
|
+
|
|
41
|
+
**An MCP server that gives an AI agent long-term memory it cannot read.** VaultZero is a
|
|
42
|
+
privacy-first memory vault: this package embeds and encrypts every memory on your machine
|
|
43
|
+
before it is sent, so the server stores ciphertext and vectors and never holds a key.
|
|
44
|
+
|
|
45
|
+
This repository is the trusted, customer-side client: the SDK, the crypto, the embedding
|
|
46
|
+
adapters, and the Model Context Protocol server. It is the only code that ever sees
|
|
47
|
+
plaintext or holds payload keys.
|
|
48
|
+
|
|
49
|
+
> The server stores ciphertext, vector embeddings (which can be partially inverted to text),
|
|
50
|
+
> scope labels, record sizes and timestamps. It cannot read your memories, but it is not
|
|
51
|
+
> "a server that knows nothing". See the [trust model](#trust-model) below.
|
|
52
|
+
|
|
53
|
+
## MCP server
|
|
54
|
+
|
|
55
|
+
Two tools, so an agent can remember across sessions and recall by meaning rather than by key:
|
|
56
|
+
|
|
57
|
+
| Tool | What it does |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `remember_fact` | Encrypts a fact locally and stores it under a scope you permit. |
|
|
60
|
+
| `recall_context` | Embeds the query, retrieves the nearest ciphertext envelopes, verifies each one, and decrypts locally. |
|
|
61
|
+
|
|
62
|
+
The model never chooses a tenant, a user, or a key, and cannot grant itself a scope.
|
|
63
|
+
Remembered text comes back explicitly framed as untrusted data, so a stored instruction
|
|
64
|
+
cannot become a command.
|
|
65
|
+
|
|
66
|
+
### Install
|
|
67
|
+
|
|
68
|
+
Requires Python 3.13.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install "vaultzero[mcp]" # or: uv tool install "vaultzero[mcp]"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Configure a client
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"mcpServers": {
|
|
79
|
+
"vaultzero": {
|
|
80
|
+
"command": "uvx",
|
|
81
|
+
"args": ["--from", "vaultzero[mcp]", "vaultzero-mcp"],
|
|
82
|
+
"env": {
|
|
83
|
+
"VZ_BASE_URL": "https://api.vaultzero.cc",
|
|
84
|
+
"VZ_CREDENTIAL": "<your 64-hex-character bearer credential>",
|
|
85
|
+
"VZ_KEY_STORE_PATH": "~/.vaultzero/keys.json",
|
|
86
|
+
"VZ_EMBEDDING_BASE_URL": "https://<your-embeddings-endpoint>/v1"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`VZ_BASE_URL` and `VZ_CREDENTIAL` are required. The other three are strongly recommended and
|
|
94
|
+
are described under [Configuration](#configuration).
|
|
95
|
+
|
|
96
|
+
### Docker
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
docker build -t vaultzero-mcp .
|
|
100
|
+
docker run -i --rm \
|
|
101
|
+
-e VZ_BASE_URL=https://api.vaultzero.cc \
|
|
102
|
+
-e VZ_CREDENTIAL=... \
|
|
103
|
+
-v vaultzero-keys:/keys -e VZ_KEY_STORE_PATH=/keys/keys.json \
|
|
104
|
+
vaultzero-mcp
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`-i` without `-t`: stdio transport needs a raw stdin, not a TTY. The image runs as UID 10001
|
|
108
|
+
and ships no pip.
|
|
109
|
+
|
|
110
|
+
## Configuration
|
|
111
|
+
|
|
112
|
+
| Variable | Required | Purpose |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `VZ_BASE_URL` | yes | Bare HTTPS origin of the VaultZero API. |
|
|
115
|
+
| `VZ_CREDENTIAL` | yes | Bearer credential. Secret. |
|
|
116
|
+
| `VZ_KEY_STORE_PATH` | recommended | Where payload keys persist. **Without it keys live in memory and every memory becomes unreadable when the process exits.** |
|
|
117
|
+
| `VZ_EMBEDDING_BASE_URL` | recommended | OpenAI-compatible embeddings endpoint, ideally customer-controlled. Without it a hashing test provider is used, which gives no meaningful retrieval. |
|
|
118
|
+
| `VZ_EMBEDDING_API_KEY` | no | Bearer token for the embeddings endpoint. Secret. |
|
|
119
|
+
| `VZ_EMBEDDING_SPACE`, `_MODEL`, `_REVISION`, `_PREPROCESSING` | no | Pin the embedding space. Changing any of them changes the vectors and makes existing memories unsearchable. |
|
|
120
|
+
| `VZ_PERMITTED_SCOPES` | no | Comma-separated scopes this process may use. Defaults to `preferences,work,financial,medical`. |
|
|
121
|
+
| `VZ_RETENTION_CHOICES` | no | Retention values offered to the model. Defaults to `30d,90d,365d`. Add `forever` only for a credential with a retention grant. |
|
|
122
|
+
|
|
123
|
+
## Trust model
|
|
124
|
+
|
|
125
|
+
What the server can and cannot see, stated precisely:
|
|
126
|
+
|
|
127
|
+
- **It cannot** read a memory: payloads are AES-256-GCM ciphertext, and keys exist only in
|
|
128
|
+
this process's key store.
|
|
129
|
+
- **It can** see vector embeddings, which are partially invertible to text. Treat the
|
|
130
|
+
embeddings endpoint and the API origin as part of your data path.
|
|
131
|
+
- **It can** see the shape of your data: scope labels, record sizes, timestamps, and
|
|
132
|
+
identifiers.
|
|
133
|
+
|
|
134
|
+
Memory contents are only as safe as the key store. Losing every copy of a key makes its
|
|
135
|
+
memories unrecoverable by design; production hosts should use `FileKeyStore` or a
|
|
136
|
+
KMS/keychain adapter, not the in-memory default.
|
|
137
|
+
|
|
138
|
+
## Contents
|
|
139
|
+
|
|
140
|
+
- **SDK** (`vaultzero.client.sdk`): HTTP lifecycle, retries, key lookup, and local
|
|
141
|
+
decryption.
|
|
142
|
+
- **Crypto** (`vaultzero.client.crypto`): AES-256-GCM envelope encryption with authenticated
|
|
143
|
+
associated data.
|
|
144
|
+
- **Embeddings** (`vaultzero.client.embeddings`): embedding-provider adapters with pinned
|
|
145
|
+
embedding-space configuration.
|
|
146
|
+
- **MCP host** (`vaultzero.client.mcp_server`): a Model Context Protocol server exposing
|
|
147
|
+
`remember_fact` and `recall_context` tools to an agent.
|
|
148
|
+
|
|
149
|
+
## Layout
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
vaultzero/client/ SDK, MCP adapter, crypto, embedding providers
|
|
153
|
+
tests/unit/ golden vectors and unit tests for the client
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Installing the SDK
|
|
157
|
+
|
|
158
|
+
Requires Python 3.13.
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
pip install "vaultzero[client]"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The `[client]` extra pulls `cryptography`, `httpx`, and `mcp`; it installs the
|
|
165
|
+
`vaultzero-mcp` console script and makes `vaultzero.client.sdk.VaultZeroClient` importable.
|
|
166
|
+
|
|
167
|
+
## SDK usage
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
import asyncio
|
|
171
|
+
|
|
172
|
+
from vaultzero.client.embeddings import EmbeddingSpace, OpenAICompatibleEmbeddings
|
|
173
|
+
from vaultzero.client.sdk import FileKeyStore, VaultZeroClient
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
async def main() -> None:
|
|
177
|
+
client = VaultZeroClient(
|
|
178
|
+
base_url="https://api.example.com",
|
|
179
|
+
credential="<64-hex-character bearer secret>",
|
|
180
|
+
key_store=FileKeyStore("~/.vaultzero/keys.json"),
|
|
181
|
+
embedding_provider=OpenAICompatibleEmbeddings(
|
|
182
|
+
space=EmbeddingSpace(
|
|
183
|
+
space_id="my-space-v1",
|
|
184
|
+
model="text-embedding-3-small",
|
|
185
|
+
revision="1",
|
|
186
|
+
preprocessing="nfc-strip-v1",
|
|
187
|
+
),
|
|
188
|
+
base_url="https://<customer-controlled-embeddings>",
|
|
189
|
+
api_key=None,
|
|
190
|
+
),
|
|
191
|
+
)
|
|
192
|
+
memory_id = await client.remember_fact("prefers oat milk in coffee", scope="preferences")
|
|
193
|
+
results = await client.recall_context("coffee milk", scopes=["preferences"])
|
|
194
|
+
await client.delete(memory_id)
|
|
195
|
+
await client.aclose()
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
asyncio.run(main())
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Keys: one active key per scope, resolved only from the bound subject's trusted key store and
|
|
202
|
+
reused across writes until rotated. Losing every copy of a key makes its memories
|
|
203
|
+
unrecoverable, so production hosts must use a persistent store (`FileKeyStore` or a
|
|
204
|
+
KMS/keychain adapter).
|
|
205
|
+
|
|
206
|
+
## MCP host
|
|
207
|
+
|
|
208
|
+
Run the MCP host (the trusted process that holds keys and sees plaintext):
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
VZ_BASE_URL=https://... VZ_CREDENTIAL=<secret> VZ_KEY_STORE_PATH=~/.vaultzero/keys.json \
|
|
212
|
+
VZ_EMBEDDING_BASE_URL=https://<customer-controlled-embeddings> vaultzero-mcp
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Without `VZ_KEY_STORE_PATH` keys live in memory and every memory becomes unreadable when the
|
|
216
|
+
process exits. Optional: `VZ_PERMITTED_SCOPES`, `VZ_RETENTION_CHOICES` (add `forever` only
|
|
217
|
+
for credentials with a retention grant), `VZ_SERVERLESS_TOKEN` for IAM-protected endpoints.
|
|
218
|
+
|
|
219
|
+
## Security model
|
|
220
|
+
|
|
221
|
+
- **Local encryption**: AES-256-GCM; the associated data binds every envelope to its exact
|
|
222
|
+
tenant, user, agent, subject epoch, memory id, scope, entity token, key id, embedding
|
|
223
|
+
space, and expiration.
|
|
224
|
+
- **No plaintext to the server**: the SDK embeds and encrypts before sending anything.
|
|
225
|
+
- **Integrity on recall**: every recalled envelope is re-checked against the authenticated
|
|
226
|
+
request context before decryption; tampered or mismatched envelopes raise `IntegrityError`.
|
|
227
|
+
- **No redirects**: the HTTP client never forwards credentials to a redirect target.
|
|
228
|
+
|
|
229
|
+
Golden vectors live in `tests/unit/golden_vectors.json`; any other SDK implementation must
|
|
230
|
+
reproduce them.
|
|
231
|
+
|
|
232
|
+
## Tests
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
uv run --python .venv/bin/python -m pytest
|
|
236
|
+
```
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# VaultZero Client
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](https://modelcontextprotocol.io)
|
|
5
|
+
[](https://www.python.org)
|
|
6
|
+
|
|
7
|
+
**An MCP server that gives an AI agent long-term memory it cannot read.** VaultZero is a
|
|
8
|
+
privacy-first memory vault: this package embeds and encrypts every memory on your machine
|
|
9
|
+
before it is sent, so the server stores ciphertext and vectors and never holds a key.
|
|
10
|
+
|
|
11
|
+
This repository is the trusted, customer-side client: the SDK, the crypto, the embedding
|
|
12
|
+
adapters, and the Model Context Protocol server. It is the only code that ever sees
|
|
13
|
+
plaintext or holds payload keys.
|
|
14
|
+
|
|
15
|
+
> The server stores ciphertext, vector embeddings (which can be partially inverted to text),
|
|
16
|
+
> scope labels, record sizes and timestamps. It cannot read your memories, but it is not
|
|
17
|
+
> "a server that knows nothing". See the [trust model](#trust-model) below.
|
|
18
|
+
|
|
19
|
+
## MCP server
|
|
20
|
+
|
|
21
|
+
Two tools, so an agent can remember across sessions and recall by meaning rather than by key:
|
|
22
|
+
|
|
23
|
+
| Tool | What it does |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `remember_fact` | Encrypts a fact locally and stores it under a scope you permit. |
|
|
26
|
+
| `recall_context` | Embeds the query, retrieves the nearest ciphertext envelopes, verifies each one, and decrypts locally. |
|
|
27
|
+
|
|
28
|
+
The model never chooses a tenant, a user, or a key, and cannot grant itself a scope.
|
|
29
|
+
Remembered text comes back explicitly framed as untrusted data, so a stored instruction
|
|
30
|
+
cannot become a command.
|
|
31
|
+
|
|
32
|
+
### Install
|
|
33
|
+
|
|
34
|
+
Requires Python 3.13.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install "vaultzero[mcp]" # or: uv tool install "vaultzero[mcp]"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Configure a client
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"mcpServers": {
|
|
45
|
+
"vaultzero": {
|
|
46
|
+
"command": "uvx",
|
|
47
|
+
"args": ["--from", "vaultzero[mcp]", "vaultzero-mcp"],
|
|
48
|
+
"env": {
|
|
49
|
+
"VZ_BASE_URL": "https://api.vaultzero.cc",
|
|
50
|
+
"VZ_CREDENTIAL": "<your 64-hex-character bearer credential>",
|
|
51
|
+
"VZ_KEY_STORE_PATH": "~/.vaultzero/keys.json",
|
|
52
|
+
"VZ_EMBEDDING_BASE_URL": "https://<your-embeddings-endpoint>/v1"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`VZ_BASE_URL` and `VZ_CREDENTIAL` are required. The other three are strongly recommended and
|
|
60
|
+
are described under [Configuration](#configuration).
|
|
61
|
+
|
|
62
|
+
### Docker
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
docker build -t vaultzero-mcp .
|
|
66
|
+
docker run -i --rm \
|
|
67
|
+
-e VZ_BASE_URL=https://api.vaultzero.cc \
|
|
68
|
+
-e VZ_CREDENTIAL=... \
|
|
69
|
+
-v vaultzero-keys:/keys -e VZ_KEY_STORE_PATH=/keys/keys.json \
|
|
70
|
+
vaultzero-mcp
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`-i` without `-t`: stdio transport needs a raw stdin, not a TTY. The image runs as UID 10001
|
|
74
|
+
and ships no pip.
|
|
75
|
+
|
|
76
|
+
## Configuration
|
|
77
|
+
|
|
78
|
+
| Variable | Required | Purpose |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `VZ_BASE_URL` | yes | Bare HTTPS origin of the VaultZero API. |
|
|
81
|
+
| `VZ_CREDENTIAL` | yes | Bearer credential. Secret. |
|
|
82
|
+
| `VZ_KEY_STORE_PATH` | recommended | Where payload keys persist. **Without it keys live in memory and every memory becomes unreadable when the process exits.** |
|
|
83
|
+
| `VZ_EMBEDDING_BASE_URL` | recommended | OpenAI-compatible embeddings endpoint, ideally customer-controlled. Without it a hashing test provider is used, which gives no meaningful retrieval. |
|
|
84
|
+
| `VZ_EMBEDDING_API_KEY` | no | Bearer token for the embeddings endpoint. Secret. |
|
|
85
|
+
| `VZ_EMBEDDING_SPACE`, `_MODEL`, `_REVISION`, `_PREPROCESSING` | no | Pin the embedding space. Changing any of them changes the vectors and makes existing memories unsearchable. |
|
|
86
|
+
| `VZ_PERMITTED_SCOPES` | no | Comma-separated scopes this process may use. Defaults to `preferences,work,financial,medical`. |
|
|
87
|
+
| `VZ_RETENTION_CHOICES` | no | Retention values offered to the model. Defaults to `30d,90d,365d`. Add `forever` only for a credential with a retention grant. |
|
|
88
|
+
|
|
89
|
+
## Trust model
|
|
90
|
+
|
|
91
|
+
What the server can and cannot see, stated precisely:
|
|
92
|
+
|
|
93
|
+
- **It cannot** read a memory: payloads are AES-256-GCM ciphertext, and keys exist only in
|
|
94
|
+
this process's key store.
|
|
95
|
+
- **It can** see vector embeddings, which are partially invertible to text. Treat the
|
|
96
|
+
embeddings endpoint and the API origin as part of your data path.
|
|
97
|
+
- **It can** see the shape of your data: scope labels, record sizes, timestamps, and
|
|
98
|
+
identifiers.
|
|
99
|
+
|
|
100
|
+
Memory contents are only as safe as the key store. Losing every copy of a key makes its
|
|
101
|
+
memories unrecoverable by design; production hosts should use `FileKeyStore` or a
|
|
102
|
+
KMS/keychain adapter, not the in-memory default.
|
|
103
|
+
|
|
104
|
+
## Contents
|
|
105
|
+
|
|
106
|
+
- **SDK** (`vaultzero.client.sdk`): HTTP lifecycle, retries, key lookup, and local
|
|
107
|
+
decryption.
|
|
108
|
+
- **Crypto** (`vaultzero.client.crypto`): AES-256-GCM envelope encryption with authenticated
|
|
109
|
+
associated data.
|
|
110
|
+
- **Embeddings** (`vaultzero.client.embeddings`): embedding-provider adapters with pinned
|
|
111
|
+
embedding-space configuration.
|
|
112
|
+
- **MCP host** (`vaultzero.client.mcp_server`): a Model Context Protocol server exposing
|
|
113
|
+
`remember_fact` and `recall_context` tools to an agent.
|
|
114
|
+
|
|
115
|
+
## Layout
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
vaultzero/client/ SDK, MCP adapter, crypto, embedding providers
|
|
119
|
+
tests/unit/ golden vectors and unit tests for the client
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Installing the SDK
|
|
123
|
+
|
|
124
|
+
Requires Python 3.13.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
pip install "vaultzero[client]"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The `[client]` extra pulls `cryptography`, `httpx`, and `mcp`; it installs the
|
|
131
|
+
`vaultzero-mcp` console script and makes `vaultzero.client.sdk.VaultZeroClient` importable.
|
|
132
|
+
|
|
133
|
+
## SDK usage
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
import asyncio
|
|
137
|
+
|
|
138
|
+
from vaultzero.client.embeddings import EmbeddingSpace, OpenAICompatibleEmbeddings
|
|
139
|
+
from vaultzero.client.sdk import FileKeyStore, VaultZeroClient
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
async def main() -> None:
|
|
143
|
+
client = VaultZeroClient(
|
|
144
|
+
base_url="https://api.example.com",
|
|
145
|
+
credential="<64-hex-character bearer secret>",
|
|
146
|
+
key_store=FileKeyStore("~/.vaultzero/keys.json"),
|
|
147
|
+
embedding_provider=OpenAICompatibleEmbeddings(
|
|
148
|
+
space=EmbeddingSpace(
|
|
149
|
+
space_id="my-space-v1",
|
|
150
|
+
model="text-embedding-3-small",
|
|
151
|
+
revision="1",
|
|
152
|
+
preprocessing="nfc-strip-v1",
|
|
153
|
+
),
|
|
154
|
+
base_url="https://<customer-controlled-embeddings>",
|
|
155
|
+
api_key=None,
|
|
156
|
+
),
|
|
157
|
+
)
|
|
158
|
+
memory_id = await client.remember_fact("prefers oat milk in coffee", scope="preferences")
|
|
159
|
+
results = await client.recall_context("coffee milk", scopes=["preferences"])
|
|
160
|
+
await client.delete(memory_id)
|
|
161
|
+
await client.aclose()
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
asyncio.run(main())
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Keys: one active key per scope, resolved only from the bound subject's trusted key store and
|
|
168
|
+
reused across writes until rotated. Losing every copy of a key makes its memories
|
|
169
|
+
unrecoverable, so production hosts must use a persistent store (`FileKeyStore` or a
|
|
170
|
+
KMS/keychain adapter).
|
|
171
|
+
|
|
172
|
+
## MCP host
|
|
173
|
+
|
|
174
|
+
Run the MCP host (the trusted process that holds keys and sees plaintext):
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
VZ_BASE_URL=https://... VZ_CREDENTIAL=<secret> VZ_KEY_STORE_PATH=~/.vaultzero/keys.json \
|
|
178
|
+
VZ_EMBEDDING_BASE_URL=https://<customer-controlled-embeddings> vaultzero-mcp
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Without `VZ_KEY_STORE_PATH` keys live in memory and every memory becomes unreadable when the
|
|
182
|
+
process exits. Optional: `VZ_PERMITTED_SCOPES`, `VZ_RETENTION_CHOICES` (add `forever` only
|
|
183
|
+
for credentials with a retention grant), `VZ_SERVERLESS_TOKEN` for IAM-protected endpoints.
|
|
184
|
+
|
|
185
|
+
## Security model
|
|
186
|
+
|
|
187
|
+
- **Local encryption**: AES-256-GCM; the associated data binds every envelope to its exact
|
|
188
|
+
tenant, user, agent, subject epoch, memory id, scope, entity token, key id, embedding
|
|
189
|
+
space, and expiration.
|
|
190
|
+
- **No plaintext to the server**: the SDK embeds and encrypts before sending anything.
|
|
191
|
+
- **Integrity on recall**: every recalled envelope is re-checked against the authenticated
|
|
192
|
+
request context before decryption; tampered or mismatched envelopes raise `IntegrityError`.
|
|
193
|
+
- **No redirects**: the HTTP client never forwards credentials to a redirect target.
|
|
194
|
+
|
|
195
|
+
Golden vectors live in `tests/unit/golden_vectors.json`; any other SDK implementation must
|
|
196
|
+
reproduce them.
|
|
197
|
+
|
|
198
|
+
## Tests
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
uv run --python .venv/bin/python -m pytest
|
|
202
|
+
```
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.25"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vaultzero"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
# This string is what MCP directories show next to the listing, so it names the thing a
|
|
9
|
+
# prospective user is looking for (an MCP server) before the architecture behind it.
|
|
10
|
+
description = "MCP server for a privacy-first agent memory vault: memories are encrypted on the client before they reach the server."
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
requires-python = ">=3.13,<3.14"
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
authors = [{ name = "VaultZero contributors" }]
|
|
15
|
+
keywords = [
|
|
16
|
+
"mcp",
|
|
17
|
+
"model-context-protocol",
|
|
18
|
+
"ai-agents",
|
|
19
|
+
"agent-memory",
|
|
20
|
+
"long-term-memory",
|
|
21
|
+
"privacy",
|
|
22
|
+
"encryption",
|
|
23
|
+
"end-to-end-encryption",
|
|
24
|
+
"llm",
|
|
25
|
+
]
|
|
26
|
+
classifiers = [
|
|
27
|
+
"Development Status :: 3 - Alpha",
|
|
28
|
+
"Intended Audience :: Developers",
|
|
29
|
+
"License :: OSI Approved :: MIT License",
|
|
30
|
+
"Programming Language :: Python :: 3.13",
|
|
31
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
32
|
+
"Topic :: Security :: Cryptography",
|
|
33
|
+
]
|
|
34
|
+
dependencies = []
|
|
35
|
+
|
|
36
|
+
[project.optional-dependencies]
|
|
37
|
+
# Trusted customer-side SDK and MCP host process.
|
|
38
|
+
client = [
|
|
39
|
+
"cryptography>=43",
|
|
40
|
+
"httpx>=0.28",
|
|
41
|
+
"mcp>=1.6,<2",
|
|
42
|
+
]
|
|
43
|
+
# For `pip install vaultzero[mcp]`: everything the `vaultzero-mcp` console script needs, so a
|
|
44
|
+
# directory's install snippet is a single line rather than an understanding of this repo's
|
|
45
|
+
# extra layout.
|
|
46
|
+
mcp = [
|
|
47
|
+
"vaultzero[client]",
|
|
48
|
+
]
|
|
49
|
+
dev = [
|
|
50
|
+
"pytest>=8.3",
|
|
51
|
+
"pytest-asyncio>=0.25",
|
|
52
|
+
"ruff>=0.8",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[project.scripts]
|
|
56
|
+
vaultzero-mcp = "vaultzero.client.mcp_server:main"
|
|
57
|
+
|
|
58
|
+
[project.urls]
|
|
59
|
+
Homepage = "https://vaultzero.cc"
|
|
60
|
+
Documentation = "https://github.com/xo0ps/VaultZero-Client#readme"
|
|
61
|
+
Issues = "https://github.com/xo0ps/VaultZero-Client/issues"
|
|
62
|
+
Repository = "https://github.com/xo0ps/VaultZero-Client"
|
|
63
|
+
Source = "https://github.com/xo0ps/VaultZero-Client"
|
|
64
|
+
|
|
65
|
+
[tool.uv]
|
|
66
|
+
# Resolve from public PyPI only, whatever a developer's global uv configuration points at. A
|
|
67
|
+
# corporate or private index would otherwise leak into uv.lock and make the project
|
|
68
|
+
# unresolvable for everyone else (403 on a package the lock references). The global config is
|
|
69
|
+
# untouched.
|
|
70
|
+
[[tool.uv.index]]
|
|
71
|
+
name = "pypi"
|
|
72
|
+
url = "https://pypi.org/simple"
|
|
73
|
+
default = true
|
|
74
|
+
|
|
75
|
+
[tool.hatch.build.targets.wheel]
|
|
76
|
+
packages = ["vaultzero"]
|
|
77
|
+
|
|
78
|
+
[tool.hatch.build.targets.sdist]
|
|
79
|
+
include = ["vaultzero", "tests", "README.md", "LICENSE"]
|
|
80
|
+
|
|
81
|
+
[tool.pytest.ini_options]
|
|
82
|
+
testpaths = ["tests"]
|
|
83
|
+
asyncio_mode = "auto"
|
|
84
|
+
asyncio_default_fixture_loop_scope = "session"
|
|
85
|
+
asyncio_default_test_loop_scope = "session"
|
|
86
|
+
|
|
87
|
+
[tool.ruff]
|
|
88
|
+
line-length = 100
|
|
89
|
+
target-version = "py313"
|
|
90
|
+
|
|
91
|
+
[tool.ruff.lint]
|
|
92
|
+
select = ["E", "F", "W", "I", "B", "UP", "S", "ASYNC"]
|
|
93
|
+
ignore = ["S101", "S608"]
|
|
94
|
+
|
|
95
|
+
[tool.ruff.lint.per-file-ignores]
|
|
96
|
+
"tests/**" = ["S105", "S106", "S311", "S603", "S607"]
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"vectors": [
|
|
3
|
+
{
|
|
4
|
+
"aad": "[\"vaultzero\",1,\"A256GCM\",\"00000000-0000-0000-0000-000000000001\",\"00000000-0000-0000-0000-000000000002\",\"00000000-0000-0000-0000-000000000003\",\"00000000-0000-0000-0000-000000000004\",\"00000000-0000-0000-0000-000000000005\",\"preferences\",\"00000000-0000-0000-0000-000000000006\",\"test-key-1\",\"test-hashing-v1\",1999999999]",
|
|
5
|
+
"ciphertext_b64": "IG26f6CL4m3oIuPkw8kIAeK/6UCVAyvq73WBpeT+XMeYg17P+gQ2",
|
|
6
|
+
"fields": {
|
|
7
|
+
"agent_id": "00000000-0000-0000-0000-000000000003",
|
|
8
|
+
"embedding_space": "test-hashing-v1",
|
|
9
|
+
"entity_token": "00000000-0000-0000-0000-000000000006",
|
|
10
|
+
"expires_at_epoch": 1999999999,
|
|
11
|
+
"key_id": "test-key-1",
|
|
12
|
+
"memory_id": "00000000-0000-0000-0000-000000000005",
|
|
13
|
+
"scope": "preferences",
|
|
14
|
+
"subject_epoch": "00000000-0000-0000-0000-000000000004",
|
|
15
|
+
"tenant_id": "00000000-0000-0000-0000-000000000001",
|
|
16
|
+
"user_id": "00000000-0000-0000-0000-000000000002"
|
|
17
|
+
},
|
|
18
|
+
"key_b64": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=",
|
|
19
|
+
"name": "preferences-scope-expiring",
|
|
20
|
+
"nonce_b64": "AAECAwQFBgcICQoL",
|
|
21
|
+
"plaintext_b64": "Z29sZGVuIHZlY3RvciBwbGFpbnRleHQ="
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|