I built a personal experiment that sorts support requests and gathers information before routing them by priority.
I connected an n8n workflow to an AI assistant and three tools: classify a request, find customer history, and search a knowledge base. The workflow routes the request using the assistant’s result. Technical setup details are below.
I explored how to divide a support workflow between fixed steps and an AI assistant.
I used n8n for the workflow, Google’s Agent Development Kit for the assistant, and Model Context Protocol for its tools. Each part has a separate job.
Webhook intake, branching on the agent's decision, downstream HTTP calls — helpdesk reply, triage queue, Slack escalation. Exported as JSON so the workflow lives in version control alongside the agent code.
A single Agent with three tools and a system instruction that pins the output schema. Vertex AI for production; Gemini API for dev. Env-var switch, no code change.
Three tools defined once: retrieval (customer history, KB search) and critique (intent classification). MCP means the same tools can be wired into Claude Desktop, Cursor, or another agent runtime without rewriting.
One ticket in, one of three outcomes: auto-reply with a drafted response (pending human approval), into the triage queue with the agent's category, or paged to Slack on escalation. The agent's decision shape is the contract.
┌─────────────┐ ┌─────────────┐ ┌──────────────────┐ │ Helpdesk │ POST │ │ POST │ ADK Agent │ │ webhook │ ──────▶ │ n8n │ ──────▶ │ (Gemini 2.5 Flash)│ └─────────────┘ │ workflow │ │ │ │ │ │ Tools via MCP: │ │ webhook │ │ - classify │ │ │ │ │ - get_history │ │ ▼ │ │ - search_kb │ │ http call │ └──────────────────┘ │ │ │ ▲ │ ▼ │ │ stdio │ switch │ ┌────────┴─────────┐ │ / \ │ │ MCP server │ │ / | \ │ │ (FastMCP) │ │ auto queue │ │ │ │ reply esc │ │ data/ │ └─────┬─┬─┬───┘ │ customers.json │ │ │ │ │ kb.json │ ┌───────────┘ │ └─────────┐ └──────────────────┘ ▼ ▼ ▼ ┌─────────┐ ┌─────────┐ ┌──────────┐ │Helpdesk │ │ Triage │ │ Slack │ │ reply │ │ queue │ │ #escal- │ │ (gated) │ │ │ │ ations │ └─────────┘ └─────────┘ └──────────┘
Customer C-1008 (Heliotrope Media · Enterprise) reports the API is returning 503s for the last 20 minutes. Here's the event sequence the agent and n8n produce.
/webhook/support-triage with the ticket payload (id, customer_id, subject, body).http://adk-agent:8080/triage. n8n waits up to 30s for the agent's structured response.classify_intent{intent: "outage", category: "incident", priority: "critical", matched_signals: ["503", "slow", "down"]}. The agent has its baseline.get_customer_historysearch_knowledge_basepriority: critical, auto_responseable: false, escalation_reason: "Enterprise customer reporting production-impacting outage". Three tool calls in the trace.#support-escalations with the ticket id, the customer name, the escalation reason, and the linked KB articles for the on-call to use.The agent's system instruction pins the output to a JSON schema. n8n's Switch node reads priority and auto_responseable to branch — no parsing fragility, no prompt-injection surface.
{
"ticket_id": "ZD-9182",
"decision": {
"priority": "critical", // critical | high | medium | low
"category": "incident",
"auto_responseable": false,
"draft_response": "Hi Devon, we're investigating reports of...",
"escalation_reason": "Enterprise customer reporting production-impacting outage",
"kb_articles": ["KB-008", "KB-007"]
},
"trace": [
{ "tool": "classify_intent", "arguments": { "ticket_text": "..." } },
{ "tool": "get_customer_history", "arguments": { "customer_id": "C-1008" } },
{ "tool": "search_knowledge_base", "arguments": { "query": "API 503 outage degraded" } }
]
}
The trace array is what makes the system auditable. Every tool call is logged with its arguments — useful for debugging, compliance review, and tuning the agent's instruction over time.
A single Switch node on priority + auto_responseable. Three outcomes, each a real HTTP call to the right downstream system.
status: pending_review. A human approves before the customer sees it. The agent is a recommender, not a sender.#support-escalations with the escalation reason and the relevant KB articles already linked. On-call has context before they open the ticket.$ git clone https://github.com/iambrucedavis/adk-mcp-n8n-flow $ cd adk-mcp-n8n-flow $ python3 -m venv .venv && source .venv/bin/activate $ pip install -r requirements.txt $ export GEMINI_API_KEY=... $ python scripts/demo-end-to-end.py # critical incident $ python scripts/demo-end-to-end.py examples/sample-ticket-howto.json # how-to
$ echo "GEMINI_API_KEY=..." > .env $ docker compose up # n8n on :5678, agent on :8080 # In another terminal: $ curl -X POST http://localhost:5678/webhook/support-triage \ -H 'Content-Type: application/json' \ -d @examples/sample-ticket.json