Features

The designer, MCP, chat, launch validation, the jobs list, metrics, the AWX API and query logging

  1. Example
  2. Variables

Change these to switch optional parts of the application on or off.


Example

Serve the MCP server for AI agents and enforce the form validation rules on every launch. In the compose project’s .env:

ENABLE_MCP=1
LAUNCH_VALIDATION=enforce

ENABLE_MCP and ENABLE_CHAT apply without a restart: they are read on every request, so you can switch them on the settings page. While one is off, its endpoint (/api/v2/mcp or /api/v2/chat) answers 404.

Run LAUNCH_VALIDATION=log for a while first: it logs what enforce would refuse without refusing it. See MCP and Log and enforce.


Variables

Every variable of this group, with its type, default and description:

Variable Choices/Defaults Comments
ENABLE_MCP
boolean
added in version 6.4.0
Default:
0

Enable the MCP server for AI agents
0, 1

Serves an MCP (Model Context Protocol) server on /api/v2/mcp, so an AI agent or an MCP client (a chat backend, an IDE) can list the forms a user may use, resolve their fields, launch jobs and follow them. Every request carries an AnsibleForms access token and runs as that user, with the same form roles and job visibility as in the browser. Users whose roles turn off allowMcp (“Allow MCP”) cannot use it. Takes effect at once, without a restart. See the MCP page of the documentation.

Scheduling follows the role options too. With allowPlannedJobs a client gets plan_job (Run later: one run of a form as the user, its run_at an ISO 8601 time with its offset or Z) and list_schedules, get_schedule and delete_schedule for the runs the user planned. With allowScheduledJobs it also gets create_schedule (a cron or one-time schedule that runs as the Schedule Service) and sees every schedule.

With allowStoredJobs a client gets the stored jobs: list_stored_jobs, get_stored_job, store_job (values saved under a name, as the Store dialog does, password fields left out) and delete_stored_job, for the user’s own (everyone’s for a settings user). resolve_field, launch_job and plan_job take a storedJob to start from its values, as Load does, with the values given laid over them.

MCP_READ_ONLY
boolean
added in version 7.0.0
Default:
0

Block launching, relaunching and planning jobs (read-only)
0, 1

With 1, the MCP server is read-only: it offers no launch_job, relaunch_job, plan_job, create_schedule, delete_schedule, store_job or delete_stored_job tool and refuses them. An AI client can list the forms, read them, resolve their fields, follow jobs and read schedules and stored jobs, but runs, plans and saves nothing. A safe way to try an agent before letting it launch playbooks. Takes effect at once, without a restart.

MCP_CHAT_FORMS_ONLY
boolean
added in version 7.0.0
Default:
0

Only allow the forms offered in the chat
0, 1

With 0 (the default) an MCP client sees every form the user’s roles may open. With 1 it sees only the forms that also set enableForChat: true - the chat assistant’s allowlist, one list for both - and a form or a job of a form left out is not found. Takes effect at once, without a restart.

ENABLE_CHAT
boolean
added in version 6.5.0
Default:
0

Enable the chat assistant
0, 1

Shows a chat button on every page. The assistant fills in a form with the user by talking, through the same form engine as the browser, and launches it only when the user clicks the Launch button on the exact payload it was shown.

It also needs a model provider on the Chat assistant settings page (or in the config seed), forms with enableForChat: true, and users whose roles allow allowChat (the default). Form definitions and the values being filled in are sent to that provider ; passwords, credentials and job output never are. Takes effect at once, without a restart. See the Chat assistant page of the documentation.

LAUNCH_VALIDATION
string
added in version 6.4.0
Choices:
  • off
  • log
  • enforce (default)

Validate every launch
off, log, enforce

Checks every launch from the browser or the REST API (POST /api/v2/job) on the server against the form’s validation rules - required, regex, minValue/maxValue, minLength/maxLength, minSize/maxSize, sameAs, in/notIn, validIf/validIfNot, valid YAML - with the same engine the browser and the MCP server use. The check runs the form’s expressions and queries again, as the user who launches, so it costs one extra evaluation of the form per launch.

  • enforce (default): a launch whose field values break the form’s rules is refused with status 422 and the failing fields. A launch that sends no rawFormData (a REST call that leaves it out) is refused as well, because its values cannot be checked. A valid launch runs the extravars and credentials the SERVER builds from the checked values, not the ones the client sent: computed fields (expressions, queries) are the server’s evaluation, and a file field must point at a real upload in UPLOAD_PATH. A wizard form is checked step by step, and a planned run (“Run later”) when it is planned and again when it fires.
  • log: a launch that would be refused is logged as a warning and still runs. It also names the extravars keys where what the client sent differs from what the server builds (never their values). Use it to see what enforcing refuses, for instance before an upgrade.
  • off: no check. The job runs the extravars and credentials the client sent, which a REST caller chooses freely: only for an instance whose every launcher is trusted. An unset or unknown value is enforce.

    What the user saw is not always what runs. The server evaluates every computed field again at launch, a moment after the browser did, as the launching user. A value that depends on WHEN or WHERE it is evaluated can differ, and then the server’s value runs:

    • time: fn.fnTime(), new Date(), a timestamp or a name built from it ;
    • outside data: a query, fnRestAdvanced / fnSsh / fnDnsResolve, a file read
      • if the data changed in between ;
    • the browser’s own settings: a runLocal expression using the user’s timezone or locale (toLocaleString) runs with the server’s. The same goes for validation: a rule that reads such a field (notIn against a query’s result, validIf on a computed flag) is checked against the server’s value. Run log for a while if you are unsure: it names every extravars key where the client and the server differ, so you see which forms this affects.

The rows of a list field that were added or edited go through their subform on the server as well, with the form’s values as __parent__: its rules are checked and its computed fields evaluated. Rows the list’s own expression produced, and rows marked deleted, are sent as they are - as in the browser. At most 500 rows are resolved per launch. Applied without a restart.

A form can be made stricter with its own launchValidation property ; the stricter of the two wins. See the Launch validation page of the documentation for the whole picture: what is checked, list rows, uploads, passwords and how to roll it out.

ENABLE_DB_QUERY_LOGGING
number
added in version 5.0.3
Choices:
  • 0 (default)
  • 1

Log database queries
0, 1

When you want to see the database queries that are executed, you can enable this option by setting this variable to 1.
introduced, due to massive amount of logging of database queries, which can be useful for debugging, but not for production.

SHOW_DESIGNER
number
added in version 4.0.0
Choices:
  • 0
  • 1 (default)

Enable the internal designer
0, 1

Although we encourage you to use an editor such as Visual Studio Code to edit the config.yaml file, preferably with some form of source control. AnsibleForms comes with an internal yaml designer.
And although only admins can see the designer, you might want to disable it completely by setting this variable to 0.

METRICS_TOKEN
string Secret
added in version 7.0.0
Default:
none (metrics off)

Prometheus metrics token
a long random string

Set, an app node (AF_ROLE all or app) serves Prometheus metrics at /api/v2/metrics and an RTE at /metrics, to a scraper that sends Authorization: Bearer <METRICS_TOKEN>. Unset, they answer 404. A worker (AF_ROLE=worker) serves no metrics: it answers only /api/v2/version and /health, for its container healthcheck.

  • the process: cpu, memory, event loop lag, garbage collection (af_process_*, af_nodejs_*) ;
  • af_http_requests_total{route,method,status}, af_http_request_duration_seconds{route} ;
  • af_jobs{status} running and awaiting approval now, af_jobs_ended_24h{status} ;
  • af_nodes{role,alive} ; af_login_failures_total, af_login_lockouts_total ;
  • an RTE: af_rte_running_jobs, af_rte_max_jobs ; a socket-mode RTE also af_rte_socket_connected (1 open, 0 not).

JOBS_LIST_SIZE
number
added in version 7.0.0
Default:
1000

Jobs in the jobs list
a whole number from 10 to 10000

The jobs list loads this many of the newest jobs (every job for an admin, a user’s own and those waiting for approval for the others): its pages, its search and its status menu cover these, an older job is not listed. A larger number reaches further back, at the cost of a larger list to read each time the jobs change. Applied without a restart.

AWX_LOST_MINUTES
number
added in version 7.0.0
Default:
5

AWX silence before a job is given up (minutes)
a positive number

While an AWX job runs, the app asks AWX for its status and output every second. When AWX does not answer (a network blip, a restart, a busy controller) it tries again with a backoff - 1, 2, 4 seconds up to 30 - and ends the job as “lost contact” only after this many minutes of failures in a row. The job may still be running in AWX ; the job’s output says so.

AWX_API_PREFIX
string
added in version 5.0.9
Default:
/api/v2

AWX API prefix
a relative url path

The prefix of the AWX / AAP API on the runners of type awx, typically /api/v2. It is added only to a runner whose uri has no API path of its own: a runner’s uri may carry it, as https://aap.example.com/api/controller/v2 for AAP 2.5 and later.