Stu Mason · Folkestone, Kent
One entryOpened issue· StuMason/coolify-mcp· TypeScript

Issue #233 opened: scheduled_tasks: add a run_once action (one-off command execution with output, safe cleanup)

Motivation (real war story, 2026-07-02)

Needed to run three one-off artisan/SQL commands inside the crunch app container (apply a missed migration). The only path today is the documented dance: create a task with frequency: "* * * * *", wait for the minute tick, read list_executions, delete the task. Sharp edges hit in practice:

  1. The task fires every minute until deleted — a non-idempotent SQL statement ran twice before the delete landed (and the "cleanup" task then also ran twice, deleting both rows it was meant to dedupe). Recovering required a third, carefully idempotent (where not exists) task.
  2. Timing the tick manually (create → wait ~60-70s → list_executions → delete) is boilerplate every caller reimplements badly.

Verified there is no upstream trigger/run-now endpoint: the bundled docs/coolify-openapi.yaml has no scheduled-task trigger (the only trigger in the spec is database backups), and src/lib/coolify-client.ts has no such method. So this must be a composite in the MCP layer.

Proposed: action: "run_once"

Params: resource, uuid, command, container, optional timeout (execution), optional wait_seconds (poll budget, default ~90).

Behaviour:

  1. Create task: generated name (oneoff-<rand>), frequency: "* * * * *", enabled.
  2. Poll list_executions (existing endpoints: coolify-client.ts:1460 app / :1637 service) every ~5s until the first execution appears with a terminal status, or wait_seconds expires.
  3. Delete the task in a finally — cleanup must happen on success, timeout, and error.
  4. Return the execution's status + message (the message field carries the command's stdout — worth also documenting on list_executions, since types/coolify.ts:1188 doesn't model it).

Tool description must carry an idempotency warning: "the underlying cron may fire more than once before cleanup completes — make the command idempotent or tolerate re-execution." (Deleting immediately after the first observed execution shrinks but does not close the window.)

Where

  • Tool shape/handler: src/lib/mcp-server.ts:1656 (scheduled_tasks).
  • Client: reuse existing create/delete/list_executions methods; no new endpoints needed.

Acceptance

  • One call runs a command in a container and returns its output, with the task gone afterwards in all paths.
  • Timeout path returns a clear message including the task UUID it cleaned up (or failed to — say so loudly).
  • Docs: site/concepts/coolify-api-gotchas.md gains the every-minute/idempotency gotcha for anyone still doing it manually.