Execute commands, manage files, and automate deployments on remote servers directly from Claude Desktop or your agent. Six MCP tools with a built-in safety tier system, auto-backup, and one-step rollback.
Requirements: SSH access to your server, private key stored in cloak_passport under a named key (e.g. my-server). No password auth — key-based only.
Every SSH command is automatically classified into one of three tiers before execution. Read-only commands run instantly. Write or destructive commands require explicit approval via cloak_ssh_approve — this is enforced at the tool level, not by convention.
Auto-executes. No approval needed. Examples: ls, cat, ps, df, grep, curl GET
Requires approval. Auto-backs up before running. Examples: writing files, installing packages, editing configs, curl POST
Requires approval + creates rollback snapshot. Examples: rm, crontab edits, service restarts, DROP TABLE
After an approved write or destructive operation, cloak_ssh_approve returns a rollback_key. Pass this to cloak_ssh_rollback within the session to undo the entire operation.
SSH keys must be stored in cloak_passport before use. The key name you choose becomes the keyName parameter in every SSH tool call.
// Store your private key once
cloak_passport({
action: "set",
key: "my-server",
value: "-----BEGIN RSA PRIVATE KEY-----\n..."
});
// Then use keyName in all SSH calls
cloak_ssh_exec({
host: "your.server.ip",
username: "ubuntu",
keyName: "my-server", // <-- references passport
command: "uptime"
});
Never use keyPath: the keyPath parameter is not supported. Always use keyName to reference a key stored in the vault. Raw file paths are rejected.
approval_token — pass this to cloak_ssh_approve to execute.host | required | Remote hostname or IP address |
username | required | SSH username (e.g. ubuntu, root) |
command | required | Shell command to execute |
keyName | recommended | Name of key stored in cloak_passport |
port | optional | SSH port — default 22 |
timeout | optional | Command timeout in ms — default 30000 |
// Read — executes immediately
cloak_ssh_exec({ host: "1.2.3.4", username: "ubuntu", keyName: "prod", command: "df -h" });
// Write — returns approval_token, does NOT run yet
cloak_ssh_exec({ host: "1.2.3.4", username: "ubuntu", keyName: "prod",
command: "echo 'hello' > /var/www/html/index.html" });
// → { tier: "write", approval_token: "abc123", preview: {...} }
// Then approve it:
cloak_ssh_approve({ approval_token: "abc123", confirm: true });
rollback_key for one-step undo.approval_token | required | Token returned by cloak_ssh_exec or cloak_ssh_plan |
confirm | required | Must be true — explicit confirmation gate |
{
approved: true,
tier: "write",
rollback_key: "rollback_1713900000_abc", // use with cloak_ssh_rollback
results: [
{ cmd: "...", success: true, stdout: "...", exit_code: 0 }
],
health_checks: { nginx: "ok", pm2: "3 processes online" }
}
host | required | Remote hostname or IP |
username | required | SSH username |
steps | required | Array of shell command strings, executed in order |
keyName | recommended | Passport key name |
label | optional | Human-readable name for this plan (shown in preview) |
port | optional | SSH port — default 22 |
cloak_ssh_plan({
host: "1.2.3.4",
username: "ubuntu",
keyName: "prod",
label: "Deploy v2.1.0",
steps: [
"cd /var/www/myapp && git pull origin main",
"npm install --production",
"pm2 reload myapp",
"sudo nginx -t && sudo nginx -s reload"
]
});
// Returns approval_token — call cloak_ssh_approve to execute all 4 steps
.tar.gz archive with the current timestamp. Called automatically before every approved write operation — use this for manual snapshots before major changes.host | required | Remote hostname or IP |
username | required | SSH username |
keyName | recommended | Passport key name |
paths | optional | Array of absolute paths to back up. Omit to auto-detect project directories. |
// Auto-detect and backup everything
cloak_ssh_backup({ host: "1.2.3.4", username: "ubuntu", keyName: "prod" });
// Backup specific paths
cloak_ssh_backup({
host: "1.2.3.4",
username: "ubuntu",
keyName: "prod",
paths: ["/var/www/myapp", "/etc/nginx"]
});
rollback_key returned by cloak_ssh_approve. Can also target a specific backup archive path as a fallback. Restores files from the auto-backup taken before the operation ran.host | required | Remote hostname or IP |
username | required | SSH username |
keyName | recommended | Passport key name |
rollback_key | recommended | Key returned by cloak_ssh_approve — preferred method |
backup_path | fallback | Direct path to a .tar.gz backup archive on the remote server |
// After an approved operation returns rollback_key:
const { rollback_key } = await cloak_ssh_approve({ approval_token: "abc", confirm: true });
// Something went wrong — undo it:
cloak_ssh_rollback({
host: "1.2.3.4",
username: "ubuntu",
keyName: "prod",
rollback_key // restores from the auto-backup taken before the operation
});
vektor_briefing at the start of the next session.host | required | The remote host operated on this session |
summary | required | What was done, what is pending, any warnings for next session |
tags | optional | Array of tags for recall, e.g. ["deploy", "nginx", "prod"] |
cloak_ssh_session_store({
host: "1.2.3.4",
summary: `Deployed v2.1.0. Updated nginx config for new subdomain.
PENDING: SSL cert renewal due in 14 days (run certbot renew).
WARNING: pm2 process 'worker' has 200+ restarts — investigate memory leak.`,
tags: ["deploy", "nginx", "ssl", "prod"]
});
// Next session: vektor_briefing() will surface this automatically
The recommended pattern for any file edit: read first, edit with Python to avoid encoding issues, verify the change, then reload the service.
// 1. Read current file (auto-executes — read tier)
cloak_ssh_exec({ host, username, keyName,
command: "cat /etc/nginx/sites-enabled/mysite" });
// 2. Edit via Python (handles line endings + encoding correctly)
// This is write tier — returns approval_token
cloak_ssh_exec({ host, username, keyName, command: `python3 -c "
content = open('/etc/nginx/sites-enabled/mysite').read()
content = content.replace('server_name old.com', 'server_name new.com')
open('/etc/nginx/sites-enabled/mysite', 'w').write(content)
print('Done')
"` });
// 3. Approve it
cloak_ssh_approve({ approval_token: "...", confirm: true });
// 4. Test + reload (two more write ops — plan them together)
cloak_ssh_plan({ host, username, keyName, label: "Test + reload nginx",
steps: ["sudo nginx -t", "sudo nginx -s reload"] });
// 1. Check existing crons (read)
cloak_ssh_exec({ host, username, keyName, command: "crontab -l" });
// 2. Backup + add new entry (plan = single approval gate)
cloak_ssh_plan({ host, username, keyName, label: "Add cron job",
steps: [
"crontab -l > /tmp/cron.bak", // backup first
"(crontab -l; echo '0 9 * * 1 cd /app && node post.js >> /app/cron.log 2>&1') | crontab -",
"crontab -l" // verify
]
});
cloak_ssh_exec({ host, username, keyName,
command: "echo '=DISK=' && df -h && echo '=MEM=' && free -h && echo '=PM2=' && pm2 list && echo '=NGINX=' && sudo nginx -t 2>&1 && echo '=UPTIME=' && uptime" });
cloak_ssh_plan({
host, username, keyName,
label: "Full deploy — v3.0.0",
steps: [
// Backup first
"tar -czf /tmp/backup-$(date +%s).tar.gz /var/www/myapp",
// Pull latest
"cd /var/www/myapp && git pull origin main",
// Install deps
"cd /var/www/myapp && npm install --production",
// Run migrations
"cd /var/www/myapp && node migrate.js",
// Reload app
"pm2 reload myapp",
// Test + reload nginx
"sudo nginx -t && sudo nginx -s reload",
// Verify
"pm2 list && curl -s -o /dev/null -w '%{http_code}' http://localhost:3000/health"
]
});
Usually means the SSH connection itself failed before the command ran. Check: (1) Is keyName correct — does that key exist in cloak_passport? Verify with cloak_passport({ action: "get", key: "your-key-name" }). (2) Is port 22 open on the server? Try nc -zv your.host 22. (3) Is the username correct? Common mistake: using root when the server requires ubuntu.
The command ran but the process doesn't have write permission on the target path. Solutions: (1) Prefix with sudo if the user has sudo rights. (2) Check ownership: ls -la /path/to/file. (3) For nginx/system files, use sudo tee instead of direct redirects: echo 'content' | sudo tee /etc/nginx/conf.d/mysite.conf.
The command is taking too long — usually a long-running process, npm install on slow connection, or a hung process. Solutions: (1) Increase timeout: timeout: 120000. (2) For very long ops, run via nohup ... & and check the log file separately. (3) For npm installs, use npm install --prefer-offline if packages are cached.
The auto-backup runs before every approved write. If it fails (usually disk space or permission issue), the write operation still proceeds but without a rollback snapshot. Check disk space: df -h. If /tmp is full, clear it: rm -rf /tmp/*.tar.gz. The backup timeout is 90s — very large directories may need paths specified in cloak_ssh_backup to target only what matters.
By design — plans abort on first failure (on_fail: "abort"). Check the results array in the response to see which step failed and its stderr. Fix the failing command, then re-run the plan from that step. If you need steps to continue despite failures, split into separate cloak_ssh_exec calls.
Known issue: a corrupted embedding vector in the VEKTOR DB causes this after turbo_quant_compress has been run. Fix: SSH to your machine running VEKTOR and run node fix-db.js from the SDK directory. This is a local SDK issue, not a server issue — the session note is lost but the SSH tools continue working.
The rollback key is only returned when the auto-backup succeeds before the operation. If backup failed (disk space, timeout), rollback_key will be null. In this case, check /tmp/ for any .tar.gz files from around the time of the operation and pass that path as backup_path to cloak_ssh_rollback instead.
This appears in health checks after every approved operation. It is a known VPS configuration issue where nginx test runs without root privileges and cannot read SSL cert keys. It does not affect nginx actually running. Verify nginx is serving correctly with: curl -s -o /dev/null -w "%{http_code}" https://yourdomain.com. If that returns 200, nginx is fine.