Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.agentfront.dev/llms.txt

Use this file to discover all available pages before exploring further.

Basic Usage

import { Job, JobContext } from '@frontmcp/sdk';
import { z } from '@frontmcp/sdk';

@Job({
  name: 'send-email',
  description: 'Send an email to a recipient',
  inputSchema: {
    to: z.string().email().describe('Recipient email'),
    subject: z.string().describe('Email subject'),
    body: z.string().describe('Email body'),
  },
  outputSchema: {
    messageId: z.string(),
    sent: z.boolean(),
  },
})
class SendEmailJob extends JobContext {
  async execute(input: { to: string; subject: string; body: string }) {
    const mailer = this.get(MailerToken);
    const result = await mailer.send(input);
    return { messageId: result.id, sent: true };
  }
}

Signature

function Job<I extends ZodRawShape, O extends OutputSchema>(
  opts: JobMetadata<I, O> & { outputSchema: O }
): TypedClassDecorator

Type Safety

The @Job decorator enforces at compile time:
  • The decorated class must extend JobContext
  • The execute() parameter must exactly match the inputSchema type
  • The execute() return type must match the outputSchema type
  • Both inputSchema and outputSchema are required for Jobs

Configuration Options

Required Properties

PropertyTypeDescription
namestringUnique job identifier
inputSchemaZodShapeZod object shape for input validation
outputSchemaZodShapeZod object shape for output validation

Optional Properties

PropertyTypeDefaultDescription
descriptionstringJob description
idstringnameStable identifier for tracking
timeoutnumber300000Max execution time in ms (5 min)
retryJobRetryConfigRetry configuration
tagsstring[]Categorization tags
labelsRecord<string, string>Key-value labels
hideFromDiscoverybooleanfalseHide from list-jobs
permissionsJobPermission[]RBAC permission rules

RetryConfig

PropertyTypeDefaultDescription
maxAttemptsnumber3Maximum retry attempts
backoffMsnumber1000Initial backoff delay in ms
backoffMultipliernumber2Backoff multiplier per attempt
maxBackoffMsnumber60000Maximum backoff delay in ms

Permission

PropertyTypeDescription
action'create' | 'read' | 'update' | 'delete' | 'execute' | 'list'Permission action
rolesstring[]Required roles (at least one must match)
scopesstring[]Required OAuth scopes
custom(authInfo) => boolean | Promise<boolean>Custom guard function

Examples

Simple Job

@Job({
  name: 'greet',
  inputSchema: { name: z.string() },
  outputSchema: { message: z.string() },
})
class GreetJob extends JobContext {
  async execute(input: { name: string }) {
    return { message: `Hello, ${input.name}!` };
  }
}

Job with Retry

@Job({
  name: 'fetch-api',
  description: 'Fetch data from external API with retries',
  inputSchema: { endpoint: z.string().url() },
  outputSchema: { data: z.unknown(), statusCode: z.number() },
  retry: {
    maxAttempts: 5,
    backoffMs: 2000,
    backoffMultiplier: 2,
    maxBackoffMs: 30000,
  },
  timeout: 60000,
})
class FetchApiJob extends JobContext {
  async execute(input: { endpoint: string }) {
    this.log(`Attempt ${this.attempt}: fetching ${input.endpoint}`);
    const response = await this.fetch(input.endpoint);
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return { data: await response.json(), statusCode: response.status };
  }
}

Job with Permissions

@Job({
  name: 'delete-records',
  description: 'Delete records from database',
  inputSchema: {
    table: z.string(),
    ids: z.array(z.string()),
  },
  outputSchema: {
    deletedCount: z.number(),
  },
  permissions: [
    { action: 'execute', roles: ['admin'] },
    { action: 'execute', scopes: ['data:delete'] },
  ],
  tags: ['destructive', 'admin'],
})
class DeleteRecordsJob extends JobContext {
  async execute(input: { table: string; ids: string[] }) {
    const db = this.get(DatabaseToken);
    const count = await db.deleteMany(input.table, input.ids);
    return { deletedCount: count };
  }
}

Function-Based Alternative

For simpler jobs, use the job() function:
import { job } from '@frontmcp/sdk';
import { z } from '@frontmcp/sdk';

const GreetJob = job({
  name: 'greet',
  description: 'Generate a greeting',
  inputSchema: { name: z.string() },
  outputSchema: { message: z.string() },
})((input, ctx) => {
  ctx.log(`Greeting ${input.name}`);
  return { message: `Hello, ${input.name}!` };
});

Context Methods

The JobContext base class provides:

Dependency Injection

async execute(input) {
  const service = this.get(ServiceToken);      // Required dependency
  const optional = this.tryGet(OptionalToken); // Optional dependency
}

Logging and Progress

async execute(input) {
  this.log('Starting processing');
  await this.progress(50, 100, 'Halfway done');
}

Error Handling

async execute(input) {
  // Fail with an error when validation fails
  if (!input.data) {
    this.fail(new Error('Missing required data'));
  }

  // Early return with a previously computed output
  const cachedResult = this.tryGet(CacheToken)?.get(input.data);
  if (cachedResult) {
    this.respond(cachedResult); // Ends execution
  }
}

JobContext

Context class details

JobRegistry

Job registry API

Jobs Guide

Jobs documentation

@Workflow

Define workflows