Skip to content

Agent-native (MCP)

SchedStack ships a first-class Model Context Protocol server so an agent can schedule durable HTTP deliveries directly — no glue code, no hand-written API client. It speaks MCP over stdio, exposes ten scheduling tools, and is scoped to exactly one (project, mode) by the API key you give it.

Two things make it agent-native rather than a thin API wrapper:

  • A forgiving when parser — agents pass natural timing strings ("24h", "in 2h", "2026-07-01 09:00", "0 9 * * *") and the server resolves them, including DST-correct wall-clock and recurring schedules.
  • Self-correcting errors — a bad input comes back as a plain-language hint the agent can act on ("that time is in the past — give a future time, or a duration like \"24h\""), not an opaque protocol failure.

Run the sched mcp subcommand. The MCP server needs direct database access, not just an API key — it connects to SchedStack’s database rather than calling api.schedstack.com — so it requires both your API key and a database URL, and serves over stdio:

Terminal window
SCHED_API_KEY=sk_live_… SCHED_DATABASE_URL=postgres://… sched mcp

Both env vars are required in every deployment — the command exits with SCHED_DATABASE_URL is required (or SCHED_API_KEY is required) if either is missing. Use an sk_test_… key to drive the test mode sandbox, or an sk_live_… key for production. Every tool call is bound to that key’s project and mode — the agent can only see and act on schedules in that scope.

Most clients launch the server as a child process and pass env through. Register sched as a stdio server with args: ["mcp"] and both env vars set:

In claude_desktop_config.json:

{
"mcpServers": {
"schedstack": {
"command": "sched",
"args": ["mcp"],
"env": {
"SCHED_API_KEY": "sk_live_…",
"SCHED_DATABASE_URL": "postgres://…"
}
}
}
}

The server announces itself as sched / SchedStack. Once connected, the ten tools below are available to the agent.

Every timing input — preview_schedule’s and create_schedule’s when — runs through one parser. It accepts four forms and picks the kind (one_shot vs recurring) for you:

Form Examples Resolves to
Relative duration "24h", "in 2h", "90s", "1h30m" one-shot, now + duration
RFC3339 instant "2026-07-01T09:00:00Z", "2026-07-01T05:00:00-04:00" one-shot, that exact instant
Offset-less wall-clock "2026-07-01 09:00", "2026-07-01T09:00:00" one-shot, that local time in timezone (DST-correct)
5-field cron "0 9 * * *", "*/15 * * * *" recurring, in timezone (default UTC)

How it decides: five or more space-separated fields is treated as cron; an "in " prefix is stripped and the rest parsed as a Go duration; otherwise it tries the timestamp layouts. An offset-less timestamp is interpreted in the timezone you pass (not UTC), so "2026-07-01 09:00" with timezone: "America/New_York" means 9am New York — mapped across daylight-saving transitions the same way recurring schedules fire. An RFC3339 string carries its own offset and is taken as-is.

What it deliberately does not accept:

  • ISO8601 durations like "PT2H" — use "2h" instead.
  • Seconds-precision cron — only standard 5-field cron (minute hour day-of-month month day-of-week).
  • Sub-second delays — the minimum is ~1s ("500ms" is rejected). SchedStack is a durable scheduler, not a sub-second timer.
  • Times in the past — both relative and absolute inputs must be in the future.

Bad inputs return guidance, e.g. "couldn't parse \"PT2H\" — try a duration (\"24h\", \"in 2h\"), an ISO8601 time, or a cron (\"0 9 * * *\")".

The agent sees exactly these tools — no more. There is intentionally no update, reschedule, or endpoint-management tool over MCP (to change timing, cancel and create again; endpoint profiles are managed via the HTTP API).

Resolve a timing input and return the next fire times without creating a schedule.

Arg Required Notes
when yes duration, RFC3339, offset-less wall-clock, or 5-field cron
timezone no IANA name (e.g. America/New_York); applies to cron and offset-less times. Default UTC

Returns kind (one_shot or recurring) and next_runs (up to 5 RFC3339 instants).

Create a durable schedule. Delivery is at-least-once and retried until it lands — see Retries & dead-letter.

Arg Required Notes
endpoint yes the https URL to deliver to
when yes same forms as preview_schedule
method no HTTP method (default POST)
body no request body; sent as application/json
timezone no IANA name for cron / wall-clock times (default UTC)
ttl no deliver-by deadline as a duration, e.g. "1h"
metadata no string→string labels

New schedules use the default retry policy (8 attempts, exponential backoff from 5s to 1h, jittered). The response is a schedule summary including id, state, kind, next_fire_at, and the resolved next_runs.

Retrieve a schedule by id. Arg: id (required).

List schedules in this scope, cursor-paginated.

Arg Required Notes
state no active | paused | canceled
kind no one_shot | recurring
cursor no opaque pagination cursor from a prior call
limit no page size (default 20, max 100). An out-of-range value (<= 0 or > 100) falls back to 20 — it is not clamped to 100

Returns schedules, plus next_cursor and has_more for paging.

Pause a schedule (reversible — future occurrences stop until resumed). Arg: id (required).

Resume a paused schedule. Arg: id (required).

Cancel a schedule (terminal — stops all future occurrences). Arg: id (required).

A delivery is one occurrence of a schedule. See Dead-letter & replay for the lifecycle.

List deliveries (occurrences), cursor-paginated.

Arg Required Notes
status no e.g. scheduled | succeeded | dead_letter | expired
schedule_id no restrict to one schedule
cursor no opaque pagination cursor
limit no page size

Returns deliveries, plus next_cursor and has_more.

Retrieve a delivery by id. Arg: id (required). The summary includes status, scheduled_for, attempt_count, and replay_of (set when this delivery is a replay).

Replay a terminal delivery (dead-lettered, expired, or succeeded) as a new occurrence. Arg: id (required). The new delivery records replay_of pointing at the original.

The MCP server is a control surface, not a replacement for the delivery contract. Tell your agent — or your receiver — that:

  • Delivery is at-least-once. A schedule can fire more than once. Your endpoint must verify the Sched-Signature and dedupe on the Idempotency-Key header. See Verify webhook signatures and Idempotency.
  • The SLO covers dispatch initiation, not delivery completion — see the timing guarantee in Quickstart.
  • There is no edit-in-place. Changing a schedule’s timing is cancel-then-create; the HTTP API (not MCP) owns endpoint profiles and richer retry policies.