MCP and HTTP

The same managed-job lifecycle is available over stdio MCP and a local HTTP server. A disconnected client does not stop the job; reconnect with its job_id.

MCP stdio

agent-exec mcp exposes run, status, tail, wait, kill, set_abandonment, and clear_abandonment.

set_abandonment(job_id, abandon_in, acknowledge_result_loss) replaces a running job's abandonment deadline and clear_abandonment(job_id) removes it. abandon_in is seconds measured from durable acceptance of the update, not from job start. Set gives up on the job and terminates it at that point and may permanently lose unfinished results, so it always requires acknowledge_result_loss: true; clear never signals the job and requires no acknowledgement. Both return the durable abandon_revision they committed, and both fail with invalid_state for a job that is not running, whose abandonment already began, or that runs under a supervisor predating this control. MCP status reports the same effective control through abandon_job_after_ms, abandon_deadline, abandon_remaining_ms, abandon_revision, and abandon_configured_by.

MCP run also accepts the optional completion sinks notify_command and notify_file, persisted before the workload launches. When a sink was persisted and the job is still running, the response adds an optional notification object with state set to armed, the generic sinks classes, and polling_required set to false: completion reaches the configured sink, so repeated wait, status, or tail polling is unnecessary. The object is omitted whenever no sink was persisted, and armed does not guarantee downstream delivery.

AGENT_EXEC="$(command -v agent-exec)"
"$AGENT_EXEC" mcp

HTTP server

agent-exec serve binds to 127.0.0.1:19263 by default. --port changes only the loopback port. A non-loopback --bind requires --insecure and a nonempty AGENT_EXEC_SERVE_TOKEN.

Bearer authentication protects only POST /exec, POST /kill/{id}, PUT /abandon/{id}, and DELETE /abandon/{id}. Read endpoints remain unprotected. Keep the default loopback bind or add a private network, firewall, or authenticating reverse proxy. Do not expose the server directly to the public internet.

--allow-origin permits one explicit CORS origin. The wildcard * is rejected. Preflight permits GET, POST, PUT, DELETE, and OPTIONS, so the abandonment routes are reachable from a browser client.

MethodEndpointEquivalent
GET/healthHealth envelope
POST/execrun
GET/status/{id}status
GET/tail/{id}tail
GET/wait/{id}wait --forever
POST/kill/{id}kill
PUT/abandon/{id}abandon set
DELETE/abandon/{id}abandon clear

Start one HTTP job

curl -X POST http://127.0.0.1:19263/exec \
  -H 'Content-Type: application/json' \
  -d '{"command":["sh","-c","echo hello"]}'

Documented handler responses use the CLI schema_version, ok, and type envelope. POST /exec requires a nonempty command array of strings. Optional fields are cwd, env, abandon_job_after, acknowledge_result_loss, wait, until, and max_bytes. Unknown fields are rejected. abandon_job_after gives up on the job, terminates it, and may permanently lose unfinished results, so it requires acknowledge_result_loss: true; use until to stop waiting without stopping the job. The removed timeout and timeout_ms fields are rejected with migration guidance and never launch a job.

PUT /abandon/{id} takes abandon_in as a nonnegative number of seconds together with acknowledge_result_loss: true; without the acknowledgement the request is rejected with HTTP 400 result_loss_not_acknowledged before any control state is read or written. DELETE /abandon/{id} takes no body. Both answer with the abandon_set / abandon_clear envelope carrying the committed abandon_revision, return HTTP 400 invalid_state for a job that is not running or has no supervisor-authored control record, and HTTP 404 job_not_found for an unknown job.