Configuration 

All settings are managed via Admin Tools > Settings > Extension Configuration > nr_mcp_agent.

LLM connection 

llmTaskUid

llmTaskUid
Type
int
Default
0

UID of an nr-llm Task record. This Task defines which LLM provider and model to use (e.g. OpenAI GPT-4, Anthropic Claude). Required -- the extension will not work without a valid Task UID.

Create the Task record in the nr-llm backend module first, then enter its UID here.

With groupTaskMapping set, this is the Task of the users no mapping applies to; it can then stay 0 if every user of the chat is in a mapped group.

groupTaskMapping

groupTaskMapping
Type
string
Default
(empty)

A different nr-llm Task per backend user group, written as comma-separated groupUid:taskUid pairs, for example 3:12,5:14. The first pair whose group the user belongs to decides -- the order of the setting, not the order of the user's groups. Membership includes subgroups, so mapping a parent group covers the groups below it. Users in none of the mapped groups use llmTaskUid. A malformed pair is skipped; the others still apply.

The Task decides the provider, the model and the prompts; what the assistant may do is still decided per user by nr-llm, so a mapping never widens a user's permissions. Before each turn the chat checks the Task's Configuration: it must be active, and if it is restricted to backend groups, the user must be in one of them (administrators always are). Otherwise the turn fails and says why. This applies to llmTaskUid too. See ADR-015.

processRunMaxIterations

processRunMaxIterations
Type
int
Default
12

How many model rounds a run of a guided process (a skill marked as a process, such as the SEO tour) may take before it stops. A round is one answer of the model, with or without tool calls. The chat asks nr-llm for this cap on every run that starts or continues a process; nr-llm caps it at its own ceiling of 20. Ordinary chat runs ask for nothing and keep nr-llm's default of 5. A value below 1 uses the default.

A run that reaches the cap says so in the chat, and a tour offers Weiter to go on. See ADR-023.

Processing 

processingStrategy

processingStrategy
Type
string
Default
exec

How chat messages are processed in the background:

exec

Forks a CLI process per request (ai-chat:process). Simple, no extra setup. Best for development and low-traffic sites.

The process runs the typo3 binary from the Composer bin-dir of the project (default vendor/bin), or typo3/sysext/core/bin/typo3 in a classic installation. If the binary is not there, the conversation fails with a message and the path that was checked is written to the TYPO3 log.

worker

Uses a long-running worker process (ai-chat:worker) that polls for new messages. Better for production -- lower latency, no process forking overhead.

A site set to worker must run ai-chat:worker (see below); without it, conversations stay in processing until ai-chat:cleanup marks them failed.

With either strategy, a turn whose process crashes stays locked until ai-chat:cleanup marks it failed after five minutes, so schedule ai-chat:cleanup.

Access control 

allowedGroups

allowedGroups
Type
string
Default
(empty)

Comma-separated list of backend user group UIDs that are allowed to use the AI Chat module. Leave empty to allow all backend users with module access.

Chat panel 

When llmTaskUid is configured, a chat button appears automatically in the TYPO3 backend toolbar (top right). Clicking it opens a floating bottom panel that stays visible across module navigation.

The panel supports four states:

  • Hidden -- Default. Only the toolbar button is visible.
  • Collapsed -- Minimal header bar showing the active conversation title and status.
  • Expanded -- Resizable panel with chat messages, input, and a compact conversation switcher.
  • Maximized -- Full-height panel with a sidebar for conversation management (search, pin, archive).

The panel height and state are persisted per user in the browser's localStorage.

System prompt 

The system prompt sent to the LLM is not configured in the extension configuration itself, but in the nr-llm records:

Configuration record (tx_nrllm_configuration.system_prompt)

The primary system prompt. Set this to define the AI assistant's persona, language, and behavior. Also use this field for instructions on how the tools registered in nr-llm are to be used.

Example:

Du bist ein TYPO3-Assistent.

## Tool-Nutzung
- Vor jeder Aussage über den Seitenbaum erst
  get_pagetree aufrufen, nie aus dem Verlauf raten.
- Datensatzfelder über read_records lesen, nicht aus
  einer früheren Antwort zitieren.
- create_content_element_draft legt ein verstecktes
  Element an; sag danach, wo es liegt und dass es
  noch freigeschaltet werden muss.
Copied!

Name the tools your installation actually has -- AI > Operation > Tools in nr-llm lists them, and AI > Operation > MCP Servers is where an external server's tools come from.

Task record (tx_nrllm_task.prompt_template)
Additional instructions appended after the Configuration prompt. Use this for task-specific context.

When both fields are set, they are combined (separated by a blank line). If neither is set, a locale-based default prompt is used.

Instructions for a conversation (tx_nrmcpagent_conversation.system_prompt)
Set by the user in the chat (the sliders button, see Usage). They are added after the two prompts above, which stay in force: the assistant is told to follow the user's instructions only where they do not contradict the configured ones. The assistant's identity, the site-language rules and the user's own context are added either way.

Every prompt ends with the user's context:

  • Answer language -- the language the user's backend is set to. The assistant answers in it whatever language the message is written in, unless the message explicitly asks for another language.
  • Where the user is -- the open backend module and, when the module shows a page, that page's uid and title. The page is included only if the user may see it; the check runs with the user's page permissions when the turn is processed. It lets "summarise this page" work without naming a uid.

User interface 

maxConversationsPerUser

maxConversationsPerUser
Type
int
Default
50

Maximum number of conversations to keep per user. Set to 0 for unlimited. When the limit is reached, the oldest non-pinned conversations are archived automatically.

autoArchiveDays

autoArchiveDays
Type
int
Default
30

Automatically archive conversations that have been inactive for this many days. Set to 0 to disable auto-archiving.

Auto-archiving runs via the ai-chat:cleanup command.

File attachments 

File attachments are always available — no special provider configuration required. Text is extracted server-side for document formats, so they work with any LLM provider.

Always supported (server-side text extraction):

  • PDF: application/pdf — requires smalot/pdfparser (hard dependency)
  • DOCX: application/vnd.openxmlformats-officedocument.wordprocessingml.document — requires phpoffice/phpword (hard dependency)
  • TXT: text/plain — no dependencies
  • XLSX: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet — requires phpoffice/phpspreadsheet (optional; install via composer require phpoffice/phpspreadsheet:^3.0)

Additionally available for vision-capable providers (Claude 3+, Gemini, GPT-4o, etc.):

  • Images: image/png, image/jpeg, image/webp

When the provider natively handles a document format (e.g. Claude natively processes PDFs via DocumentCapableInterface), the file is sent as binary instead of being extracted. The file picker automatically restricts to formats the active provider can process.

Storage: An uploaded file is a managed TYPO3 file from the moment it arrives: it is written into the default storage, indexed in sys_file and given a sys_file_metadata record, like any other file in the file module. It is then read at LLM call time and sent as Base64-encoded multimodal content, and the assistant is told its sys_file uid and path — so it can reference the attachment from a content element with nr-llm's file tools instead of asking for it to be uploaded again.

Nothing is ever overwritten or deleted. A name already taken in the folder yields report_01.pdf; if the file of that name has identical content, the existing one is returned instead of a copy. Where the user may not write, the upload is refused with 403 rather than failing as a server error — the file mounts and permissions of the logged-in backend user apply throughout.

attachmentFolder

attachmentFolder
Type
string
Default
ai-chat

Folder for chat attachments in the default storage, relative to its root — ai-chat means fileadmin/ai-chat/. A per-user subfolder (<be_user_uid>) is created inside it and is not configurable: it is what keeps one user's attachments out of another's. An empty value falls back to the default rather than writing into the storage root.

Limits:

  • Maximum 5 files per conversation.
  • Maximum file size: 20 MB per file.
  • File count is enforced both in the frontend (before upload) and in the backend API.

Security: Decide deliberately whether the attachment folder is publicly readable, because the two things it is used for pull in opposite directions.

An attachment is material a backend user hands to the assistant, and it is stored under a path that is guessable by name. Where attachments are only ever read by the assistant, deny direct HTTP access to the folder:

# fileadmin/ai-chat/.htaccess
Require all denied
Copied!

Where editors are meant to place an attached image or PDF into a content element — the file is already in FAL, so this needs no second upload — the folder must stay publicly readable, or the reference renders as a broken image in the frontend. Denying access to the folder and referencing files out of it is a contradiction, not a hardened setup. Point attachmentFolder at a folder your editors publish from in that case, and treat what is uploaded through the chat as publishable.

Security 

maxMessageLength

maxMessageLength
Type
int
Default
10000

Maximum length of a single user message in characters. Set to 0 for unlimited (not recommended).

Messages exceeding this limit are rejected with an error.

maxActiveConversationsPerUser

maxActiveConversationsPerUser
Type
int
Default
3

Maximum number of simultaneously active (processing) conversations per user. Prevents a single user from overloading the system. Set to 0 for unlimited.

Choices in guided processes 

A guided process asks its plain choices -- which point first, whether to continue, how to go on when a source is missing -- through nr-llm's tool ask_choice. The chat shows its answers as reply buttons above the input. nr-llm ships ask_choice switched off: enable it under AI > Operation > Tools in nr-llm before a process relies on it. Without it a process cannot ask such a choice and has to put it into its answer instead. ask_choice needs an nr-llm that has it (nr-llm PR 1029).

The answers are the options the process passes, shown as they are. A "go on without" option, such as "Ohne Bild weiter", is worded by the process's skill, not by the chat.

Dashboard 

These settings fill the AI assistant dashboard widgets (see Dashboard widget). The chat's skill catalogue names a skill by nr-llm's <source uid>:<path>, such as 3:seo-optimieren, so the same skill has a different identifier on every installation. A setting names a skill in one of two ways:

  • a bare slug without :, such as seo-optimieren: the catalogue skill whose identifier is <source uid>:seo-optimieren. Where several sources carry the slug, the source with the highest trust level wins (nr-llm's skill trust: first party, verified, community, untrusted), then the one with the lowest source uid;
  • a catalogue identifier, such as 3:seo-optimieren: exactly that skill.

Letters, digits and ._:/- are accepted, starting with a letter or digit and at most 100 characters; any other entry is ignored.

What an editor reads for a skill comes from EXT:nr_mcp_agent/Resources/Private/Language/locallang_dashboard.xlf: skill.<key>.title, skill.<key>.description and, for a frequent task, task.<key>. <key> is the identifier with every character other than a letter, digit, - or _ replaced by _: 3:skills/seo is labelled by skill.3_skills_seo.title. A catalogue identifier without labels of its own uses those of its slug, so 3:seo-optimieren reads skill.seo-optimieren.title. For a skill of your own, add these labels through a language override ($GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride']). An entry without a title is left out rather than shown by its identifier.

An entry is offered only when the chat can start its skill for the user looking at the dashboard: the skill is in the chat's skill catalogue for that user, nr-llm can pass a skill to a run, and the configuration does not require a second person to approve every change. Otherwise the entry is left out, and a widget left with nothing to offer says that nothing is set up yet. A configured skill that does not exist therefore never leads to a link the chat would refuse.

dashboardGuidedSkills

dashboardGuidedSkills
Type
string
Default
seo-optimieren,inhalt-verbessern

The guided tours the Improve a page widget offers, comma-separated, in this order.

dashboardQuickTasks

dashboardQuickTasks
Type
string
Default
(empty)

The entries of the Frequent tasks widget, comma-separated. Append |page to a task that works on one page: the widget then asks for the page first. Without it the entry is a link that starts the task in the chat. Empty by default, so the preset does not repeat the guided tours; the widget then says that no task is set up yet.

A skill that declares page in its frontmatter (see Whether a skill works on a page) decides this itself: page: required asks for the page, optional and none do not, whatever the suffix says. The suffix applies to skills that declare nothing.

Missing alt texts 

The check for images without an alt text (see Decorative images and ADR-026: A Site-Wide Check for Missing Alt Texts) reads every image field of type file in the TCA, so the image fields of a newly installed extension are checked without any setting. These two settings leave fields and tables out.

altTextExcludedTables

altTextExcludedTables
Type
string
Default
(empty)

Tables whose images are not checked, comma-separated, such as records that are never shown in the frontend. Content elements inside such a record are left out with it. By default every table is checked.

altTextExcludedFields

altTextExcludedFields
Type
string
Default
pages.og_image,pages.twitter_image,pages.nav_icon,be_users.avatar,backend_layout.icon

Image fields that are not checked, as table.field, comma-separated: fields whose images the frontend does not output as an image with an alt text. The default leaves out the page's social-media images, the navigation icon (bootstrap_package renders it as an icon without the alt text), the backend user's avatar and the backend layout's icon, which only the backend shows. A value set here replaces the default, so keep the entries you still want.

Worker mode production setup 

For production use with processingStrategy = worker, set up a systemd service to keep the worker running:

# /etc/systemd/system/typo3-ai-chat-worker.service
[Unit]
Description=TYPO3 AI Chat Worker
After=mysql.service

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/html
ExecStart=/var/www/html/vendor/bin/typo3 \
    ai-chat:worker --poll-interval=200
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
Copied!

Enable and start the service:

sudo systemctl daemon-reload
sudo systemctl enable typo3-ai-chat-worker
sudo systemctl start typo3-ai-chat-worker
Copied!

Scheduled cleanup 

Add the cleanup command to your cron or TYPO3 scheduler to handle stuck conversations, auto-archiving, and deletion of old data. A conversation whose worker never finished stays in processing until this command marks it failed after five minutes — without the schedule it can stay there indefinitely:

# Run cleanup daily at 3:00 AM
0 3 * * * /var/www/html/vendor/bin/typo3 \
    ai-chat:cleanup --delete-after-days=90
Copied!