Durable, lease-based asynchronous task execution MCP server.
AsyncGate is a standalone MCP server providing durable, lease-based asynchronous execution for agents. It solves: "delegate work without blocking, and reliably recover results later."
AsyncGate does not plan, reason, schedule, or orchestrate strategy. It stores work, leases it, and records outcomes.
- Agent (TASKER): Creates tasks, fetches status/results
- AsyncGate Server: Source of truth for task state, leases, results, audit trail
- Worker Services (TASKEEs): External services that claim and execute tasks
- Tasks: Units of work with type, payload, requirements, and lifecycle state
- Leases: Time-bounded exclusive claims on tasks by workers
- Receipts: Immutable contract records for audit and coordination
principal_aiis required on task creation and defines the obligation owner for receipt routing.payload_pointeris preferred for non-trivial payloads;payloadis legacy inline data.
- Python 3.11+
- PostgreSQL 15+
- Docker (for deployment)
# Install dependencies
pip install -e ".[dev]"
# Set up environment
export ASYNCGATE_DATABASE_URL="postgresql+asyncpg://asyncgate:asyncgate@localhost:5432/asyncgate"
# Run migrations
alembic upgrade head
# Start server
asyncgate./run_local.sh
# Windows PowerShell: .\run_local.ps1# Build image
docker build -t asyncgate .
# Run container
docker run -p 8080:8080 \
-e ASYNCGATE_DATABASE_URL="postgresql+asyncpg://..." \
asyncgateAsyncGate supports three deployment methods:
./deploy-fly.shSee Fly Operations Guide for details.
# Create secrets
kubectl create secret generic asyncgate-secrets \
--from-literal=ASYNCGATE_API_KEY=your-key \
--from-literal=ASYNCGATE_DATABASE_URL=postgresql://... \
-n asyncgate
# Deploy
kubectl apply -k k8s/overlays/prodSee k8s/README.md for details.
docker-compose up --buildpython scripts/golden_path.pypytest tests/ -vAsyncGate exposes MCP over HTTP at /mcp with JSON-RPC methods tools/list and tools/call.
TASKER tools:
asyncgate.bootstrapasyncgate.create_taskasyncgate.get_taskasyncgate.list_tasksasyncgate.cancel_taskasyncgate.list_receiptsasyncgate.list_receipts_ledgerasyncgate.ack_receipt
TASKEE tools:
asyncgate.lease_nextasyncgate.renew_leaseasyncgate.report_progressasyncgate.completeasyncgate.fail
System:
asyncgate.get_configasyncgate.health
Environment variables (prefix ASYNCGATE_):
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
postgresql+asyncpg://... | PostgreSQL connection URL |
REDIS_URL |
- | Redis URL for rate limiting |
ENV |
development | Environment (development/staging/production) |
INSTANCE_ID |
asyncgate-1 | Instance identifier |
LOG_LEVEL |
INFO | Logging level |
DEBUG |
false | Debug mode |
DEFAULT_LEASE_TTL_SECONDS |
120 | Default lease TTL |
MAX_LEASE_TTL_SECONDS |
1800 | Maximum lease TTL (30 min) |
MAX_LEASE_RENEWALS |
10 | Maximum lease renewals before forced release |
MAX_LEASE_LIFETIME_SECONDS |
7200 | Absolute max lease lifetime (2 hours) |
DEFAULT_MAX_ATTEMPTS |
2 | Default max retry attempts |
DEFAULT_RETRY_BACKOFF_SECONDS |
15 | Default retry backoff |
RECEIPT_MODE |
standalone | Receipt storage mode (standalone/receiptgate_integrated) |
RECEIPTGATE_ENDPOINT |
- | ReceiptGate MCP endpoint URL (accepts RECEIPTGATE_URL alias) |
RECEIPTGATE_AUTH_TOKEN |
- | ReceiptGate auth token/API key (accepts RECEIPTGATE_API_KEY alias) |
RECEIPTGATE_TENANT_ID |
- | Tenant ID to stamp in ReceiptGate receipts |
RECEIPTGATE_EMISSION_TIMEOUT_MS |
500 | ReceiptGate request timeout (ms) |
RECEIPTGATE_EMISSION_MAX_RETRIES |
10 | ReceiptGate retry count |
RECEIPTGATE_CIRCUIT_BREAKER_ENABLED |
true | Enable circuit breaker |
ESCALATION_ENABLED |
false | Emit escalation receipts |
ESCALATION_TARGETS |
- | JSON array of escalation targets |
ESCALATION_LEASE_EXPIRY_CLASS |
1 | Escalation class for lease expiry |
API_KEY |
- | API key for authentication |
ALLOW_INSECURE_DEV |
false | Allow unauthenticated in dev mode |
RATE_LIMIT_ENABLED |
true | Enable rate limiting |
RATE_LIMIT_BACKEND |
memory | Rate limit backend (memory/redis) |
RATE_LIMIT_DEFAULT_CALLS |
100 | Default calls per window |
RATE_LIMIT_DEFAULT_WINDOW_SECONDS |
60 | Rate limit window size |
States: queued, running, leased, succeeded, failed, canceled
queued -> running -> leased -> succeeded
\-> failed -> queued (retry)
\-> canceled
queued -> running: Worker picks up taskrunning -> leased: Task claimed with leaseleased -> succeeded: Task completes successfullyleased -> failed: Task fails (may retry)queued/leased -> canceled: Task canceledfailed -> queued: Retry with backoff (if attempts remaining)leased -> queued: Lease expires (system-driven)
Terminal states: succeeded, failed, canceled
- At most one active lease per task
- Lease enforcement: mutations require matching lease_id + worker_id
- Lease expiry: expired leases allow task to be reclaimed
- Idempotent creation: same idempotency_key returns same task_id
- Terminal states are immutable
- State machine is authoritative; receipts are proofs
Receipt types are enumerated in src/asyncgate/models/enums.py (ReceiptType).
Termination rules and TERMINAL_RECEIPT_TYPES live in
src/asyncgate/models/termination.py.
Terminal receipt types for task obligations:
task.completedtask.failedtask.canceled
Terminator detection is type-gated: only terminal receipt types close obligations.
MIT