Vaulted MCP Server
# @vaulted/mcp-server
[](https://www.npmjs.com/package/@vaulted/mcp-server)
[](LICENSE)
Share encrypted, self-destructing secrets directly from Claude Desktop, Cursor, Windsurf, and any MCP-compatible AI tool.
- š Zero-knowledge E2E encryption (AES-256-GCM, key never sent to server)
- š Agent-blind input: share env vars, files, and .env keys without exposing them in context
- š ļø 4 tools: `create_secret`, `view_secret`, `check_status`, `list_secrets`
- š Local history with live status tracking
- š» Works with Claude Desktop, Cursor, Windsurf, Claude Code, VS Code
## Agent-blind secret sharing
The headline feature: sensitive values are **resolved locally and never passed through the LLM**. When you ask your agent to share an environment variable or file, the MCP server reads the value directly from your machine ā the agent only ever sees the secure link, not the secret itself.
```
"Share the value of my STRIPE_SECRET_KEY env var"
ā Agent passes: env:STRIPE_SECRET_KEY (never sees the value)
ā Server resolves it locally, encrypts, returns the link
```
This means sensitive values never appear in your conversation history or the LLM's context.
## Installation
**Requires Node.js ā„ 18.**
Zero-install via npx:
```bash
npx -y @vaulted/mcp-server
```
Or install globally:
```bash
npm install -g @vaulted/mcp-server
vaulted-mcp-server
```
## Quick start
Add to your MCP host config and restart the application. Your agent will have access to all 4 Vaulted tools immediately.
```json
{
"mcpServers": {
"vaulted": {
"command": "npx",
"args": ["-y", "@vaulted/mcp-server"]
}
}
}
```
## Configuration
### Claude Desktop
File: `~/Library/Application Support/Claude/claude_desktop_config.json`
```json
{
"mcpServers": {
"vaulted": {
"command": "npx",
"args": ["-y", "@vaulted/mcp-server"]
}
}
}
```
### Cursor
File: `~/.cursor/mcp.json`
```json
{
"mcpServers": {
"vaulted": {
"command": "npx",
"args": ["-y", "@vaulted/mcp-server"]
}
}
}
```
### Windsurf
File: `~/.codeium/windsurf/mcp_config.json`
```json
{
"mcpServers": {
"vaulted": {
"command": "npx",
"args": ["-y", "@vaulted/mcp-server"]
}
}
}
```
### Claude Code
File: `.mcp.json` in your project root (or `~/.claude/.mcp.json` globally):
```json
{
"mcpServers": {
"vaulted": {
"command": "npx",
"args": ["-y", "@vaulted/mcp-server"]
}
}
}
```
### VS Code
File: `.vscode/mcp.json`
```json
{
"servers": {
"vaulted": {
"command": "npx",
"args": ["-y", "@vaulted/mcp-server"]
}
}
}
```
### Any other MCP client
Run `npx @vaulted/mcp-server` as a stdio transport. The server uses the standard MCP stdio protocol.
### Optional flags
| Flag | Default | Description |
| ---------------- | --------------------- | --------------------------------------------------------------------------------- |
| `--base-url` | `https://vaulted.fyi` | Vaulted API base URL (for self-hosted instances) |
| `--allowed-dirs` | _(none)_ | Comma-separated directories accessible for file-based input sources (extends CWD) |
Pass flags via the `args` array:
```json
{
"mcpServers": {
"vaulted": {
"command": "npx",
"args": ["-y", "@vaulted/mcp-server", "--base-url", "https://your-instance.example.com"]
}
}
}
```
Multiple allowed directories:
```json
{
"mcpServers": {
"vaulted": {
"command": "npx",
"args": ["-y", "@vaulted/mcp-server", "--allowed-dirs", "/home/user/secrets,/tmp/creds"]
}
}
}
```
## Tools reference
### `create_secret`
Encrypt and store a secret, returns a shareable self-destructing link.
| Parameter | Type | Default | Description |
| ------------ | ------------------------------------------------------------------------------------------ | -------- | ---------------------------------------------------------------------------------------------------- |
| `content` | string | required | The secret to encrypt (max 1000 chars). Supports [agent-blind prefixes](#agent-blind-input-sources). |
| `max_views` | `"1"` \| `"3"` \| `"5"` \| `"10"` | `"1"` | Views before self-destruct |
| `expiry` | `"1h"` \| `"2h"` \| `"6h"` \| `"12h"` \| `"24h"` \| `"3d"` \| `"7d"` \| `"14d"` \| `"30d"` | `"24h"` | Time until expiration |
| `passphrase` | string | _(none)_ | Optional passphrase protection |
| `label` | string | _(none)_ | Human-readable label for local history |
**Returns:** `{ success: true, data: { url, statusUrl, expiresIn, maxViews, passphraseProtected }, message }`
---
### `view_secret`
Retrieve and decrypt a secret from a Vaulted URL. Defaults to opening in the browser ā use `output_mode` to keep the decrypted value out of the conversation.
| Parameter | Type | Default | Description |
| ---------------- | ------------------------------------------------------ | ------------------ | ------------------------------------------------------------ |
| `url` | string | _(one req.)_ | Full Vaulted URL including the `#` fragment |
| `secret_id` | string | _(one req.)_ | Secret ID (alternative to `url`) |
| `encryption_key` | string | _(with secret_id)_ | Encryption key from URL fragment (required with `secret_id`) |
| `output_mode` | `"browser"` \| `"clipboard"` \| `"file"` \| `"direct"` | `"browser"` | Where to send the decrypted value |
| `file_path` | string | _(none)_ | Required when `output_mode` is `"file"` |
| `passphrase` | string | _(none)_ | Required for passphrase-protected secrets |
**Output modes:**
- `browser` ā opens the secret URL in your default browser (decryption happens in-browser, value stays out of agent context)
- `clipboard` ā copies decrypted value to clipboard, nothing returned to agent
- `file` ā writes decrypted value to `file_path`, nothing returned to agent
- `direct` ā returns decrypted value in the response (use with care ā value enters agent context)
**Returns:** Depends on `output_mode`. Browser/clipboard/file modes confirm success without returning the plaintext.
---
### `check_status`
Check how many times a secret has been viewed and whether it's still active. **Does not consume a view.**
| Parameter | Type | Default | Description |
| --------------- | ------ | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `url` | string | _(one req.)_ | Status URL (e.g., `https://vaulted.fyi/s/<id>/status?token=...`) |
| `secret_id` | string | _(one req.)_ | Secret ID (alternative to `url`) |
| `status_token` | string | _(with id)_ | Status token from secret creation (required with `secret_id`) |
| `previousViews` | number | _(none)_ | Pass the last known view count to detect new views since last check. When the count increases, the response includes "New view detected!" |
**Returns:** `{ success: true, data: { views, maxViews, status, expiresAt }, message }`
---
### `list_secrets`
Show all locally tracked secrets with their live status fetched from the API.
| Parameter | Type | Description |
| --------- | ---- | ------------- |
| _(none)_ | ā | No parameters |
**Returns:** `{ success: true, data: { entries: [...], suggestedAction? }, message }`
`suggestedAction` is included when unconsumed active secrets exist, prompting you to use `check_status` to monitor them.
---
### Response format
All tools use a consistent response shape:
```json
// Success
{ "success": true, "data": { /* tool-specific */ }, "message": "Human-readable summary" }
// Error
{ "success": false, "error": { "code": "SECRET_EXPIRED", "message": "...", "suggestion": "..." } }
```
**Error codes:** `SECRET_EXPIRED`, `SECRET_CONSUMED`, `PASSPHRASE_REQUIRED`, `ENV_VAR_NOT_FOUND`, `FILE_NOT_FOUND`, `PATH_TRAVERSAL_BLOCKED`, `DOTENV_KEY_NOT_FOUND`, `API_UNREACHABLE`, `API_ERROR`, `ENCRYPTION_FAILED`, `FILE_WRITE_ERROR`, `INVALID_INPUT`
## Examples
### Create a secret
```
"Share this API key securely: sk-abc123"
```
ā Returns a one-time link in the chat. Share it via Slack, email, or a ticket.
### Agent-blind: share an environment variable
```
"Share the value of my GITHUB_TOKEN env var securely"
```
ā Agent passes `env:GITHUB_TOKEN` to the tool. The server reads the value locally. The agent never sees the token.
### Agent-blind: share a file
```
"Share the contents of ~/.ssh/id_rsa.pub securely"
```
ā Agent passes `file:~/.ssh/id_rsa.pub`. File is read locally and encrypted before the link is returned.
### Agent-blind: share a key from a .env file
```
"Share the DATABASE_URL from my .env.local"
```
ā Agent passes `dotenv:.env.local:DATABASE_URL`. The specific key is parsed and encrypted. Other values in the file are never read.
### View a secret in the browser
```
"Open this secret: https://vaulted.fyi/s/abc123#key..."
```
ā Browser opens with the decrypted content. The value never enters the conversation.
### View a secret to clipboard
```
"Retrieve this secret to my clipboard: https://vaulted.fyi/s/abc123#key..."
```
ā Decrypted value is copied to clipboard. Nothing sensitive is returned in the chat.
### Save a secret to a file
```
"Save this secret to /tmp/creds.txt: https://vaulted.fyi/s/abc123#key..."
```
ā Decrypted value is written to `/tmp/creds.txt`. Nothing sensitive is returned in the chat.
### View a secret directly (returns value to agent)
```
"Retrieve this secret and return the value to me: https://vaulted.fyi/s/abc123#key..."
```
ā Decrypted value is returned in the response. Use only when you need the value in the conversation ā it will appear in your chat history.
### Check whether a secret has been viewed
```
"Has my secret been viewed yet?"
```
ā Returns view count, max views, and expiry. Does not consume a view.
### Poll for new views
```
"Let me know when someone views my secret ā previous view count was 0"
```
ā Pass `previousViews: 0`. When the count increases, the response includes "New view detected!"
### List recent secrets
```
"What secrets have I shared recently?"
```
ā Returns your local history with live status from the API ā view counts, remaining views, and expiry for each.
## Agent-blind input sources
The `content` parameter of `create_secret` supports prefixes that instruct the server to resolve the value locally before encrypting. **The resolved value is never passed back to the agent.**
| Prefix | Example | Resolves to |
| --------- | -------------------------------- | --------------------------------------- |
| _(none)_ | `the plain value` | Literal string |
| `env:` | `env:STRIPE_SECRET_KEY` | `process.env.STRIPE_SECRET_KEY` |
| `file:` | `file:/home/user/.ssh/id_rsa` | Contents of the file at that path |
| `dotenv:` | `dotenv:.env.local:DATABASE_URL` | Value of `DATABASE_URL` in `.env.local` |
**Path security:** File and dotenv paths are validated against `process.cwd()` and any `--allowed-dirs` you configure. Symlinks pointing outside allowed directories are rejected with `PATH_TRAVERSAL_BLOCKED`.
**Output modes that keep secrets out of context:** Use `browser`, `clipboard`, or `file` output modes for `view_secret` ā the decrypted value is delivered directly to you without entering the agent's response or conversation history.
## Security model
- **End-to-end encrypted:** AES-256-GCM encryption runs locally via [@vaulted/crypto](https://www.npmjs.com/package/@vaulted/crypto). The server never sees plaintext.
- **Key in URL fragment:** The encryption key lives only in the `#` fragment of the URL ā never sent to any server, never logged.
- **Zero-knowledge server:** vaulted.fyi stores only ciphertext. It cannot decrypt your secrets.
- **Self-destructing:** Secrets are deleted when max views are reached or TTL expires ā whichever comes first.
- **No accounts, no telemetry:** Anonymous usage. No API keys required.
- **Agent-blind by design:** Input source prefixes (`env:`, `file:`, `dotenv:`) ensure sensitive values never pass through the LLM.
Learn more at [vaulted.fyi/security](https://vaulted.fyi/security).
## Contributing
```bash
git clone https://github.com/vaulted-fyi/vaulted-mcp-server
cd vaulted-mcp-server
npm install
npm test
```
## License
MIT
TDQS
Scored across 4 tools
Each tool has a clearly distinct purpose with no overlap: check_status monitors secret usage, create_secret generates new secrets, list_secrets provides an overview of existing secrets, and view_secret retrieves and decrypts secrets. The descriptions clearly differentiate between monitoring, creation, listing, and retrieval actions.
All tools follow a consistent verb_noun pattern (check_status, create_secret, list_secrets, view_secret) with clear, descriptive names that accurately reflect their functions. There are no deviations in naming conventions across the set.
With 4 tools, this server is well-scoped for managing secure secrets, covering the essential CRUD-like operations: create, list, view, and check status. Each tool earns its place without redundancy or bloat, making it easy for agents to navigate.
The tool set provides complete coverage for the secret-sharing domain: create_secret handles creation, list_secrets and check_status cover monitoring and status, and view_secret handles retrieval. There are no obvious gaps, as all lifecycle stages (creation, viewing, monitoring, expiration) are addressed.