Google ADK · MCP · n8n · Cross-Protocol Architecture

Workflow-Driven
Triage Agent

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.

Google ADK · Gemini 2.5 Flash 3 MCP tools · stdio transport n8n workflow · 3 routes docker compose up
At a glance 30-second read

What it is

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.

Maps to

AI Engineer (Agentic) · AI Automation Engineer · Forward-Deployed AI Engineer · AI Transformation Lead

Skills demonstrated

  • Google ADK agent definition + tool registration
  • MCP server (FastMCP) + stdio client transport
  • n8n workflow design — webhook + Switch + multi-output routing
  • FastAPI wrapper around an async agent runtime
  • Vertex AI or Gemini API — env-var swap, no code change
  • Cross-protocol architecture (ADK + MCP + n8n)
Google ADK Gemini 2.5 MCP n8n FastAPI Docker Compose Python
01 — The Three Pieces each picked for what it's best at

Right tool, right layer.

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.

Workflow Layer
n8n
Workflow runtime · ops-team-readable

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.

Agent Layer
Google ADK
Gemini 2.5 Flash · structured tool use

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.

Tool Layer
MCP
FastMCP · stdio transport

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.

02 — Architecture end-to-end data flow

From webhook to routed response.

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.

data flow · request → decision → route [ ARCHITECTURE ]
┌─────────────┐         ┌─────────────┐         ┌──────────────────┐
│  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   │
            └─────────┘   └─────────┘  └──────────┘
03 — A Real Run critical incident scenario

Walk-through, one ticket.

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.

01
Helpdesk → n8n webhook
POST to /webhook/support-triage with the ticket payload (id, customer_id, subject, body).
02
n8n → ADK agent
HTTP node forwards to http://adk-agent:8080/triage. n8n waits up to 30s for the agent's structured response.
03
ADK agent → MCP classify_intent
Returns {intent: "outage", category: "incident", priority: "critical", matched_signals: ["503", "slow", "down"]}. The agent has its baseline.
04
ADK agent → MCP get_customer_history
C-1008 is Enterprise · $8,400/mo, owned by Devon Park, with one open ticket already this week. Confirms the critical priority — Enterprise SLA, account at risk.
05
ADK agent → MCP search_knowledge_base
Top hit: KB-008 "Service degradation — what to do". Second: KB-007 "Webhook signature mismatch troubleshooting". Drafted response references KB-008 and points to the status page.
06
ADK agent → emits decision
Returns the structured JSON: priority: critical, auto_responseable: false, escalation_reason: "Enterprise customer reporting production-impacting outage". Three tool calls in the trace.
07
n8n Switch → escalation branch
Priority = critical sends to the Slack branch. Posts to #support-escalations with the ticket id, the customer name, the escalation reason, and the linked KB articles for the on-call to use.
04 — Decision Schema the contract n8n routes on

Structured output, every time.

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.

/triage · response shape [ AGENT OUTPUT ]
{
  "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.

05 — Routes three outcomes, one switch

What n8n does with the decision.

A single Switch node on priority + auto_responseable. Three outcomes, each a real HTTP call to the right downstream system.

When priority = low / medium AND auto_responseable = true
Auto-reply (gated)
POST drafted reply to the helpdesk with status: pending_review. A human approves before the customer sees it. The agent is a recommender, not a sender.
When priority = low / medium AND auto_responseable = false
Triage queue
POST to the triage queue with the agent's category, draft, and KB references. Saves a tier-1 analyst 5–10 minutes of context-gathering per ticket.
When priority = critical OR high
Escalate to Slack
Page #support-escalations with the escalation reason and the relevant KB articles already linked. On-call has context before they open the ticket.
06 — Try it demo without n8n · full stack with

Two ways to run.

demo · no n8n required [ FAST PATH ]
$ 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
full stack · n8n + agent [ DOCKER ]
$ 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