Jobs extend the FrontMCP execution model with persistent state tracking, retry logic, and DAG-based composition via Workflows.
Why Jobs?
Jobs fill the gap between lightweight tool calls and full workflow orchestration:
Jobs are ideal for:
- Data processing — ETL pipelines, file parsing, batch operations
- External integrations — API calls that may fail and need retries
- Long-running operations — background tasks with progress reporting
- Auditable actions — operations that need execution logs and state tracking
Creating Jobs
Class Style
Use class decorators for jobs that need dependency injection, lifecycle hooks, or complex logic:Function Style
For simpler jobs, use the functional builder:Registering Jobs
Add jobs to your app via thejobs array:
Loading from npm or Remote Servers
Mix local jobs with those loaded from npm or proxied from remote servers:Job.esm() and Job.remote() load individual jobs. For loading entire apps, use App.esm() or App.remote().jobs option:
Input & Output Schemas
Jobs require both input and output schemas using Zod:Configuration
Retry Configuration
Jobs support automatic retries with exponential backoff:
The backoff schedule for defaults: 1s, 2s, 4s (capped at
maxBackoffMs).
Permissions
Jobs support RBAC-style permission checks:
When no permissions are defined, the job is accessible to all authenticated users.
Once a rule targets an action, every rule for that action must pass; within a
single rule,
roles and scopes are any-of.
Rules are enforced in JobExecutionManager, the choke point every caller path
goes through, so background runs and workflow steps are covered too. list_jobs
hides a job the caller could not run, and a denial is indistinguishable from
“not found” so the response cannot be used to enumerate restricted job names.
Roles and scopes are read from the caller’s verified token. When the server
declares authorities.claimsMapping, that mapping is authoritative; otherwise
the fallback chain is user.roles → the roles claim → the authorization’s
scopes.
Background Execution
Jobs can run in background mode, returning arunId for status polling:
Via DirectClient
Progress Reporting
Jobs can report progress and log messages during execution:Job Stores
Jobs use two stores for persistence:State Store
Tracks execution state (JobRunRecord): run ID, state, input, result, error, logs, timing.
Definition Store
Persists dynamic job definitions registered at runtime via theregister_job tool (opt-in — see Dynamic registration).
Memory (Default)
Suitable for development. Data is lost on restart.Redis
For production, configure Redis storage:MCP Tools
When jobs are enabled, the following MCP tools are automatically registered:
Hyphen aliases (
list-jobs, execute-job, …) still resolve with a deprecation log line for one release — agents and code that hardcoded the old form keep working.
Dynamic registration is opt-in
register_job and register_workflow take a raw script string and register it
as an executable job. Since 1.7.2 they are not registered at all unless you ask
for them:
get_job_status and get_workflow_status return runs started by the calling
subject only — a run record carries the job’s inputs and results, so a guessed
runId reads as “not found”.
Best Practices
Do:- Define clear input and output schemas with
.describe()on each field - Use retries for operations that call external services
- Set appropriate timeouts based on expected execution time
- Use background mode for long-running operations
- Log meaningful progress messages for debugging
- Use jobs for simple, synchronous operations (use tools instead)
- Set
maxAttemptstoo high for non-idempotent operations - Skip output schemas — they enable validation and type safety
- Forget to handle the retry
attemptnumber in your logic
Next Steps
Workflows
Compose jobs into multi-step pipelines
JobContext
Context class API reference
@Job
Decorator reference
JobRegistry
Registry API reference