Skip to content

v1.2.0

Choose a tag to compare

@github-actions github-actions released this 27 Jun 09:52
feat: SQLite-backed durable state + refresh tokens (v1.2.0)

Durable state moves to a single SQLite database (rusqlite, bundled — still a
single binary) at /var/lib/mcp-ssh/mcp-ssh.db, in a hybrid model: SQLite holds
the low-frequency structured state, while high-frequency live job output keeps
streaming to per-job log files.

OAuth (src/oauth, src/db):
- access + refresh tokens persisted in SQLite, so logins survive a restart
  (the agent self-updates by restarting its own service — previously that
  logged every client out). Access tokens 24h, refresh tokens 1 year, rotated
  on use (RFC 6749 §10.4). grant_type=refresh_token added + advertised; the
  /token response returns a refresh_token. Many tokens coexist → multiple
  clients (desktop, mobile, CLI) stay authenticated independently.

Jobs (src/jobs):
- job metadata + a bounded output tail persisted to SQLite, so job(list) and
  poll survive restarts; live output still streams to log files under
  /var/lib/mcp-ssh/logs/jobs. poll falls back to the saved tail when the live
  log is gone. Reaper runs on startup AND hourly: drops >24h jobs (rows +
  files), trims finished logs to a tail (5000 lines <3h, 500 after), mtime-ages
  orphan files, and marks jobs stuck 'running' across a restart as failed.
- job ids/log filenames now use '-' for the time (job-23-30-07), not ':' —
  colon-free is portable everywhere (Windows/scp/globbing).
- fix: poll() self-deadlocked on a MutexGuard held to the end of an `if let`
  block (temporary-in-scrutinee); bind the lookup to a local first.

config: db_path (MCP_SSH_DB) decoupled from the job-log dir.

Built in parallel by three agents (oauth, jobs, docs) + integration here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>