IA Router, Free Text and MCP Confirmation
1. What? — Definition and context
Section titled “1. What? — Definition and context”Three N8N sub-workflows form the intelligent routing layer of the Telegram bot. The IA Router detects the intent of a free-text message and picks the target service. The Free Text Handler dispatches plain-text replies sent in answer to an interactive question opened by the cli-ollama API. The MCP Confirmation Handler triggers a Telegram approval flow before executing a critical MCP tool (create, update, delete N8N workflow).
These three workflows share the same philosophy: they carry no business logic of their own. Their job is to steer the main flow towards the right handler based on context.
Position in the Telegram pipeline
Section titled “Position in the Telegram pipeline”| Workflow | ID | Type | Trigger |
|---|---|---|---|
| IA Router - Intent Detection | HWryf7aJkZa5FuUA | wait-for-result | Execute Workflow from Orchestrator |
| Telegram Free Text Handler | xwGcEOpzHkvx0HTR | fire-and-forget | Execute Workflow from Orchestrator |
| MCP Confirmation Handler | lyDYsxzTrDzZrfJk | webhook | Internal POST /webhook/mcp-confirmation |
None of these workflows is called directly by Telegram: they are internal entry points triggered by the Orchestrator or the cli-ollama gateway at the right moment.
2. Why? — Stakes and motivations
Section titled “2. Why? — Stakes and motivations”Without this routing layer, the Orchestrator would have to carry the entire intent detection logic and the sensitive-action validation. The workflow size would explode, and a strategy change (adding an AI provider, changing the confirmation policy) would require touching the core of the central system.
Problems solved
Section titled “Problems solved”| Problem | Without this layer | With this layer |
|---|---|---|
| Rigid intent detection | Keyword pattern matching only | LLM with fallback chain plus regex as last resort |
| Provider overload | Direct call without quota check | /api/usage/summary pre-computes the available provider |
| Orphan free-text replies | No link between question and free-text answer | question_mappings ties each expected message |
| Uncontrolled critical MCP | Agent silently executes destructive tools | Mandatory Telegram confirmation with 90s timeout |
| Telegram callback > 64 bytes | Silent API error | mcp_approve_{id} / mcp_reject_{id} (39 chars) below limit |
Architectural choice
Section titled “Architectural choice”Why split these three workflows rather than inline them in the Orchestrator?
| Approach | Pro | Con |
|---|---|---|
| Inline | No Execute Workflow overhead | Orchestrator > 200 nodes, fragile editing |
| Extracted sub-workflows | Isolated refactoring, independent evolution | API surface between parent and sub to maintain |
Refactoring #273 explicitly extracted the Free Text Handler as SW-8, and #295 delivered the MCP Confirmation Handler as a standalone webhook to decouple the cli-ollama gateway from the main graph.
3. How? — Technical implementation
Section titled “3. How? — Technical implementation”Components
Section titled “Components”| Workflow | ID | Nodes | Role |
|---|---|---|---|
| IA Router - Intent Detection | HWryf7aJkZa5FuUA | 13 | Multi-provider intent detection with fallback |
| Telegram Free Text Handler | xwGcEOpzHkvx0HTR | 10 | Dispatch free reply to /api/questions/{id}/answer |
| MCP Confirmation Handler | lyDYsxzTrDzZrfJk | 3 | Webhook + format + Telegram send with inline keyboard |
Lifecycle of a message
Section titled “Lifecycle of a message”IA Router: fallback chain
Section titled “IA Router: fallback chain”The workflow starts by hitting GET http://cli-ollama:11434/api/usage/summary which returns a pre-computed fallback_chain based on quotas and provider availability:
{ "can_use": true, "fallback_chain": ["codex", "gemini"], "providers": { "codex": { "available": true, "can_use": true }, "gemini": { "available": true, "can_use": true } }}The Switch node Route by Availability reads fallback_chain[0] and routes to the matching branch:
| Branch | Provider | Model | Typical confidence |
|---|---|---|---|
codex | OpenAI Codex via cli-ollama | codex-yolo | 0.85 - 0.95 |
gemini | Google Gemini via cli-ollama | gemini-flash-yolo | 0.80 - 0.90 |
keyword | Regex fallback (no LLM) | — | 0.6 - 0.7 |
Each LLM branch calls POST /api/generate with a prompt that forces a strict JSON response of the form {"intent": ..., "service": ..., "action": ..., "params": {...}, "confidence": ...}. The Parse Response node extracts the JSON via regex, applies safe defaults, and returns everything to the parent.
Free Text Handler: from message to API
Section titled “Free Text Handler: from message to API”When an interactive question is opened by cli-ollama (for instance: “what is the title of the new workflow?”), a row is inserted into the question_awaiting_text Data Table with a qid_short. At the next message the Orchestrator detects this state and delegates to SW-8:
Execute Workflow Trigger -> Handle Free Text Answer (extract qid_short, chat_id, free_text) -> Load Question for Answer (DT question_mappings by qid_short) -> POST Free Text Answer (cli-ollama /api/questions/{id}/answer) -> Cleanup Messages (prepare message_ids for edit) -> Edit Header Free Text (edit original message with answer) -> Loop Over Items [0] -> Send Confirmation "Your answer has been forwarded" [1] -> Delete Awaiting (DT question_awaiting_text) -> Delete Question Mapping (DT question_mappings)Two Data Tables are involved: question_awaiting_text (YYEsLEk9s3XDbo89) stores pending inputs, question_mappings (mXrPedR5PKYCUSpo) ties a qid_short to the Telegram message_id so the message holding the question can be edited retroactively.
MCP Confirmation Handler: approving critical tools
Section titled “MCP Confirmation Handler: approving critical tools”The MCP gateway (mcp-gateway:3001) keeps a list of tools considered critical (any write operation against N8N: create, update, delete, activate, deactivate). When Codex CLI invokes one of these tools during a conversation, the gateway pauses execution, generates a confirmation_id (12 hex chars via secrets.token_hex(6)), and POSTs the following payload to /webhook/mcp-confirmation:
{ "type": "mcp_confirmation", "confirmation_id": "mcp_a1b2c3d4e5f6", "session_id": "tg_5883063462_1234567890", "tool_name": "n8n_create_workflow", "arguments_summary": "{\"name\": \"Test Workflow\", ...}", "chatId": "5883063462", "callback_url": "http://mcp-gateway:3001/confirm/mcp_a1b2c3d4e5f6/respond", "timeout_seconds": 90}The workflow has three nodes:
- Webhook Trigger — Receives the POST in
responseMode: immediately(200 OK direct) - Format Confirmation Message (Code) — Builds the HTML text and the
mcp_approve_{id}/mcp_reject_{id}callbacks - Send Confirmation (Telegram sendMessage) — Sends the message with a 2-button inline keyboard
MCP callback convention
Section titled “MCP callback convention”| Pattern | Meaning |
|---|---|
mcp_approve_{confirmation_id} | Approve the critical tool execution |
mcp_reject_{confirmation_id} | Reject the execution |
The total length of a mcp_approve_mcp_a1b2c3d4e5f6 callback is 39 characters, well under the Telegram 64-byte limit. The confirmation_id coming from secrets.token_hex(6) stays non-guessable, which prevents an attacker with access to the conversation from forging a callback for another confirmation_id.
Callbacks flow through the normal Telegram path: Orchestrator -> Callback Router -> SW-11 (Conversation Callback Handler, e0bLff6av97daYvi, 87 nodes). SW-11 detects the mcp_ prefix and routes to Parse MCP Action, which splits confirm actions (the approve/reject pair) from other MCP actions. For confirm two nodes are added:
- Call MCP Confirm (HTTP Request) — POST to
http://mcp-gateway:3001/confirm/{confirmation_id}/respondwith body{"approved": true|false}, headerAuthorization: Bearer {{ $env.N8N_MCP_AUTH_TOKEN }} - Edit Confirm Result (Telegram editMessageText) — Replaces the original message with “MCP tool approved.” or “MCP tool rejected.”
Per-conversation MCP config (#294)
Section titled “Per-conversation MCP config (#294)”Each conversation carries its own MCP config stored in the conversations Data Table (column mcp_config, JSON string). The /mcp command opens a paginated menu (SW-11) that lets the user enable or disable each tool. The derived mcp_enabled flag is computed by the Orchestrator on every turn:
- If no tool is enabled:
mcp_enabled = false-> Codex CLI is launched with-c 'mcp_servers={}'(no MCP server loaded) - If at least one tool is enabled:
mcp_enabled = true+allowed_toolswhitelist -> Codex can call tools, but cli-ollama filters unauthorized calls (403 if a tool is outside the list)
This per-conversation configuration allows a “read-only” conversation against N8N (list_workflows only) and an “admin” conversation on the same infrastructure, without mixing permissions.
4. What if? — Outlook and limits
Section titled “4. What if? — Outlook and limits”Current limits
Section titled “Current limits”| Limit | Impact | Mitigation |
|---|---|---|
| IA Router latency 2-5s | First hop on every free-text message | Acceptable, masked by Telegram latency |
| Approximate keyword fallback | Confidence 0.6 - 0.7 when no LLM is available | Wide regex patterns, route to general when in doubt |
| MCP timeout fixed at 90s | No per-tool configuration | Sufficient for human confirmation on mobile |
| Free Text not context-aware | No N8N-side validation of the expected format | cli-ollama validates downstream, error visible if malformed |
Evolution scenarios
Section titled “Evolution scenarios”If more LLM providers are needed:
- Add a case in the
Route by AvailabilitySwitch - Add a Prepare Prompt + Call Provider + Parse Response node trio
- Update
/api/usage/summaryso it exposes the new provider infallback_chain
If MCP pre-approval is needed:
- Add a “whitelisted user” mode in the gateway that bypasses confirmation for pre-validated tools
- Or add a per-conversation policy (auto-approve when
mcp_auto_approve = true)
If IA Router precision needs measuring:
- Log decisions into an
intent_decisionsData Table (text, predicted_service, actual_service after feedback) - Compute weekly precision via a scheduled workflow
Related pages
Section titled “Related pages”Workflows
Section titled “Workflows”- Telegram Orchestrator — Central hub that calls the IA Router and the Free Text Handler
- Conversational System — Multi-turn conversations that trigger the MCP confirmations
- Service Handlers — Docker, Odoo, N8N, General handlers invoked after the IA Router
- Question Hub — Interactive questions whose answers flow through the Free Text Handler
Infrastructure
Section titled “Infrastructure”- AI Stack — cli-ollama, MCP gateway, Codex CLI
Reference
Section titled “Reference”- Glossary — MCP, Intent, Callback, Sub-workflow