Skip to main content
Jobs are typed, executable units of work with strict input/output schemas, automatic retries, timeouts, permission checks, and background execution support. They are designed for operations that need reliability guarantees beyond what a simple tool call provides.
Jobs extend the FrontMCP execution model with persistent state tracking, retry logic, and DAG-based composition via Workflows.
Nx users: Scaffold with nx g @frontmcp/nx:job my-job --project my-app. See Job Generator.

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 the jobs 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().
To enable the jobs system on your server, configure the top-level jobs option:
Auto-enabled by @App({ jobs }) (issue #408). Declaring any @App({ jobs: [...] }) (or workflows: [...]) brings the jobs subsystem up with in-memory stores by default — no @FrontMcp({ jobs: { enabled: true } }) required. The SDK registers four MCP tools for job management: list_jobs, execute_job, get_job_status, and remove_job (plus parallel *_workflow tools). register_job / register_workflow are added only when jobs.allowDynamicRegistration is true. Hyphen aliases (list-jobs, execute-job, …) keep working with a deprecation log line for one release. Set @FrontMcp({ jobs }) explicitly to configure persistent storage or to opt out via jobs: { enabled: false }.

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.
Security (GHSA-58v2-gpcc-jmqv, fixed in 1.7.2) — before 1.7.2 permissions was validated and stored but never evaluated, so any caller who could reach execute_job could run every job regardless of its declared rules. Servers on 1.7.1 or earlier should treat every job as reachable by every caller.

Background Execution

Jobs can run in background mode, returning a runId 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 the register_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:
Enabling this lets any caller who can reach the tool list author and run code on the server. Leave it off unless an agent is genuinely meant to write jobs, and gate the surrounding surface with permissions when you do.
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
Don’t:
  • Use jobs for simple, synchronous operations (use tools instead)
  • Set maxAttempts too high for non-idempotent operations
  • Skip output schemas — they enable validation and type safety
  • Forget to handle the retry attempt number in your logic

Next Steps

Workflows

Compose jobs into multi-step pipelines

JobContext

Context class API reference

@Job

Decorator reference

JobRegistry

Registry API reference