Secure Local Memory MCP Server avatar

Secure Local Memory MCP Server

Pricing

Pay per usage

Go to Apify Store
Secure Local Memory MCP Server

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

CQ

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

16 hours ago

Last modified

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:

  1. Platform / batch mode (default on Apify): you pass a list of commands (or a single query) in the actor input. Each command is executed, the encrypted vault is persisted, and one result row per command is pushed to the dataset.
  2. 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 is base64(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

ToolArgumentsDescription
store_secretkey (string), value (string)Encrypts and stores the value under key.
retrieve_secretkey (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.

FieldTypeRequiredDescription
passphrasestring (secret)Required to run commandsMaster 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.
commandsarray of objectsNoBatch 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.
querystringNoA 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:

FieldTypeDescription
toolstringThe tool that ran (store_secret, retrieve_secret, list_keys).
keystringThe affected key (when applicable).
valuestringThe decrypted value (for a successful retrieve_secret), the key list (for list_keys), or NOT_FOUND. Absent for store_secret.
statusstringsuccess or error.
messagestringHuman-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 (or SLM_PASSPHRASE), which never leaves the actor.
  • Encryption uses Node's built-in crypto module — 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.