An n8n workflow triggers a Google ADK agent on Gemini 2.5 Flash, which calls three MCP tools to triage incoming support tickets. n8n routes the result. Three different protocols, each doing what it's best at.
A complete customer-support triage stack — n8n receives a ticket webhook, calls the agent, routes by priority. The agent is a Google ADK Agent on Gemini 2.5 Flash that calls three tools exposed by a FastMCP server over stdio: classify_intent, get_customer_history, search_knowledge_base. Runs as a two-container docker-compose stack; has a no-n8n demo script for fast iteration.
AI Engineer (Agentic) · AI Automation Engineer · Forward-Deployed AI Engineer · AI Transformation Lead
The combination matters: ops teams read and edit workflows in n8n; engineers tune the reasoning step in ADK; tools defined once in MCP get reused by Claude, an IDE, or another agent without rewriting.
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