Secure Local Memory MCP Server
Pricing
Pay per usage
Secure Local Memory MCP Server
Model Context Protocol (MCP) server for encrypted local storage and memory vaults.
Pricing
Pay per usage
Rating
0.0
(0)
Developer
CQ
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
16 hours ago
Last modified
Categories
Share
A Model Context Protocol (MCP) server that stores key/value secrets encrypted at rest and lets an AI agent (or a batch job) store and retrieve them by key. Encryption is real AES-256-GCM with a key derived from your passphrase via scrypt — the ciphertext on disk never contains the plaintext, and the wrong passphrase fails authentication.
It runs two ways:
- Platform / batch mode (default on Apify): you pass a list of
commands(or a singlequery) in the actor input. Each command is executed, the encrypted vault is persisted, and one result row per command is pushed to the dataset. - Stdio MCP mode: when no commands are supplied and a process pipes JSON-RPC into stdin, the actor speaks MCP (JSON-RPC 2.0) over stdin/stdout so it can be wired into an MCP client as a local server.
What it does
- Encrypts each stored value with AES-256-GCM (16-byte random salt + 12-byte random
IV per value; key derived with
scrypt). The stored blob isbase64(salt | iv | tag | ciphertext). - Persists the encrypted vault in a named Apify key-value store
(
secure-local-memory-vault), which is not purged between runs, so the vault persists across runs. - Decrypts on retrieval only with the correct passphrase. A wrong passphrase is rejected by the GCM authentication tag (you get an error, never a wrong/garbage value).
MCP tools exposed
| Tool | Arguments | Description |
|---|---|---|
store_secret | key (string), value (string) | Encrypts and stores the value under key. |
retrieve_secret | key (string) | Decrypts and returns the value for key. |
list_keys | (none) | Lists the keys in the vault. Values stay encrypted. |
Input
All fields are optional, but you must provide either commands or query for the actor
to do anything in batch mode, and a passphrase (or the SLM_PASSPHRASE env var) is
required before any secret can be encrypted/decrypted.
| Field | Type | Required | Description |
|---|---|---|---|
passphrase | string (secret) | Required to run commands | Master passphrase used to derive the AES key via scrypt. The same passphrase is needed to decrypt previously stored secrets. Falls back to the SLM_PASSPHRASE environment variable if omitted. |
commands | array of objects | No | Batch of tool calls. Each item is { "tool": "store_secret", "key": "...", "value": "..." }, { "tool": "retrieve_secret", "key": "..." }, or { "tool": "list_keys" }. JSON-RPC-style items ({ "method": "tools/call", "params": { "name", "arguments" } }) are also accepted. |
query | string | No | A single command as a JSON string — either a simple object like {"tool":"store_secret","key":"k","value":"v"} or a raw JSON-RPC line. Use commands for batches. |
Example input
{"passphrase": "correct horse battery staple","commands": [{ "tool": "store_secret", "key": "api_token", "value": "sk-live-abc123" },{ "tool": "store_secret", "key": "db_pw", "value": "p@ssw0rd" },{ "tool": "list_keys" },{ "tool": "retrieve_secret", "key": "api_token" }]}
Output
For each command, one row is pushed to the default dataset with this shape:
| Field | Type | Description |
|---|---|---|
tool | string | The tool that ran (store_secret, retrieve_secret, list_keys). |
key | string | The affected key (when applicable). |
value | string | The decrypted value (for a successful retrieve_secret), the key list (for list_keys), or NOT_FOUND. Absent for store_secret. |
status | string | success or error. |
message | string | Human-readable status / error description. |
A combined { "results": [...] } object is also written to the default key-value store
under the key OUTPUT.
Example output row (retrieve):
{"tool": "retrieve_secret","key": "api_token","value": "sk-live-abc123","status": "success","message": "Decrypted secret for key: api_token"}
The encrypted vault itself is stored in the named key-value store
secure-local-memory-vault under the record ENCRYPTED_VAULT (a map of key → base64
ciphertext). Plaintext values are never written there.
Running as a local MCP server (stdio mode)
Run with no commands/query and pipe JSON-RPC requests on stdin:
$SLM_PASSPHRASE="correct horse battery staple" node src/main.js
Then send newline-delimited JSON-RPC, e.g.:
{"jsonrpc":"2.0","id":1,"method":"tools/list"}{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"store_secret","arguments":{"key":"k","value":"v"}}}{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"retrieve_secret","arguments":{"key":"k"}}}
Each request gets a JSON-RPC response on stdout.
Setup / auth
- No third-party API keys. The only credential is your
passphrase(orSLM_PASSPHRASE), which never leaves the actor. - Encryption uses Node's built-in
cryptomodule — no extra dependencies beyond the Apify SDK.
Limitations
- The vault persists in the named key-value store
secure-local-memory-vault. If you run this actor on a different account/store or that store is deleted, the data is gone. There is no external/shared database. - If you lose the passphrase, the data is unrecoverable — by design. There is no recovery mechanism or backdoor.
- The passphrase is supplied via input/env. Use Apify's secret input handling and treat the actor run logs accordingly; do not log secret values yourself.
- This is a single-vault, single-passphrase design. It is not a multi-tenant secrets manager and does not do key rotation, sharing, or access control beyond the passphrase.
- All values are strings. Binary blobs must be base64/encoded by the caller.
License
Provided as-is. See repository for details.