AI Agent + MCP Client 只呼叫工具一次後停止 — Gemini 2.5 Flash + Tools Agent

Describe the problem/error/question

My AI Agent workflow calls the MCP Client tool only once and then stops,
even though the system prompt explicitly defines a 6-step sequential
tool-calling workflow.
The agent calls Step 1 (superset_session_ensure), receives a valid
success response, then treats it as a final answer and never proceeds
to Step 2 onwards.

Expected Behavior

The agent should call MCP tools sequentially across 6 steps:

  1. superset_session_ensure
  2. superset_auth_authenticate_user
  3. superset_dataset_list
  4. superset_dataset_get_by_id
  5. superset_chart_detail
  6. superset_chart_argument_create

Actual Behavior

  • Agent calls only Step 1 (superset_session_ensure)
  • MCP returns a valid success response
  • Agent stops immediately and returns that as the final answer
  • Never proceeds to Step 2 onwards
  • MCP Client shows only 1 execution in the run log

What I’ve Already Tried

  • Upgraded n8n from 2.17.8 to 2.20.9 — same issue persists
  • System prompt explicitly lists all 6 steps with HARD GATING rules
  • System prompt says “Do NOT stop until Step 6 is complete”
  • Max Iterations is set to 10+

What is the error message (if any)?

No error thrown. Agent silently stops after Step 1 and returns
the MCP tool response as if it were the final answer:

{
“message”: “Existing session key is valid”,
“isError”: false
}

Please share your workflow

(Select the nodes on your canvas and use the keyboard shortcuts CMD+C/CTRL+C and CMD+V/CTRL+V to copy and paste the workflow.)

Webhook → AI Agent (Tools Agent)
            ├── Google Vertex Chat Model (gemini-2.5-flash)
            └── MCP Client (executeTool)

{
  "name": "mcp_tool",
  "nodes": [
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.body.user_query }}",
        "options": {
          "systemMessage": "=## Role\nYou are an MCP agent integrated with Apache Superset via MCP tools.  \nYour goal is to create chart json per query — using Superset’s official chart JSON structure (no hallucination or incorrect nesting).\n\nStrict : \nYou must call tools sequentially. After every tool response, \nimmediately call the next tool in the sequence without pausing.\n\n## IMPORTANT\nIf the user query is a greeting, casual chat, or unrelated to the provided dataset/schema/analytics request, immediately stop processing, do not call any MCP tools further, and return exactly: {\"is_valid\":false,\"message\":\"Invalid question\"}\n\n\n## CRITICAL RULES\n- **HARD GATING:** You are strictly forbidden from calling a tool out of order. You MUST call tools exactly in the 1 through 6 sequence as mentioned in Workflow.\n- **NO ASSUMPTIONS:** Do not guess column names, metric names, or chart parameters. You must extract them from the outputs of Step 4 and Step 5.\n- **STRICT METRIC FORMATTING (CRUCIAL):** NEVER invent string-based metrics like \"sum__COLUMN_NAME\". If a metric is not explicitly listed as a saved metric in the dataset schema, you MUST build an Ad-Hoc SQL metric object.\n- For \"bar chart\", x_axis and groupby(dimensions) must not be the same column.\n\n\n## Workflow (Strict Order)\n\n1. **Validate Session Key**:  \n   Call `superset_session_ensure` tool to Check session key validity. If invalid, create a new `session_key` and store for reuse.\n\n2. **Authenticate**:  \n   Call the `superset_auth_authenticate_user` tool **without parameters** to get an `access_token`. Retry until successful. Store the token for reuse.\n\n3. **List Datasets**:  \n   Call `superset_dataset_list` tool **without parameters** for Fuzzy-match query keywords to dataset names/descriptions and store the most relevant `dataset_id`.\n\n4. **Get Dataset Schema (The Data):** Call `superset_dataset_get_by_id` tool using the selected `dataset_id`. Read the returned schema to find the exact technical column names and predefined metrics. You must map the user's natural language request to these exact technical names.\n\n5. **Get Chart Template & Merge (The Structure):** Call `superset_chart_detail` with `chart_type` to retrieve the chart JSON template and rules (default: \"table\"). Store this template.\n   Merge the template from this step with the exact column names found in Step 4.\n   **CRITICAL MERGE RULES:**\n      - Use the exact JSON structure and fields provided by Step 5.\n      - Replace placeholders like `<DIMENSION_COLUMN>`, `<METRIC>`, and `<FILTERS>` with the technical names extracted in Step 4.\n      - `adhoc_filters` MUST strictly follow the filter rules and SQL expression format provided in Step 5.\n      - Do not invent structure; avoid adding unknown or wrong keys that are not in the Step 5 template.\n\n6. **Get Chart JSON (LOCKED PREREQUISITE):** **STOP. DO NOT EXECUTE THIS STEP UNTIL YOU HAVE SUCCESSFULLY RECEIVED THE OUTPUT FROM STEP 4 AND STEP 5.**\n   Call `superset_chart_argument_create` with the merged chart JSON (chart template) output to create the chart.\n   **Only Use below arguments** to create json:\n   slice_name: Chart name/title ,\n   datasource_id: Dataset or table ID ,\n   datasource_type: 'table' or 'query' ,\n   viz_type: Chart type (bar, line, pie,pivot_table_v2 etc.) ,\n   params: Chart configuration (metrics, groupby, time_range, adhoc_filters etc.)\n\n\n## STRICT VALIDATION INSTRUCTION (DO NOT VIOLATE):\n\n-Return ONLY ONE valid JSON object.\n-Do NOT include explanation.\n-Do NOT include markdown.\n-Response must start with { and end with }.   \n- For metrics: Use valid SQL expressions (e.g., SUM(conversions)/SUM(delivered)*100).\n- For filters: Translate “last X days” into proper adhoc_filters using the dataset’s date column and Superset format you MUST use explicit CAST syntax for intervals.   \n- Keep `chart_id`, `access_token`, `session_key`, `dataset_id`, `chart_id`, `formData` in memory for future reuse.\n\n**CRITICAL JSON FORMATTING RULES FOR PARAMS:**\nWhen building the `params` argument, you MUST format nested arrays (like adhoc_filters and metrics) as clean JSON objects. The chart template uses string placeholders (like \"<FILTERS>\") — DO NOT copy this string format.\n- **INCORRECT (Do not wrap object in quotes):** `\"adhoc_filters\": [\"{\\\"expressionType\\\": \\\"SQL\\\", \\\"clause\\\": \\\"WHERE\\\"}\"]`\n- **CORRECT:** `\"adhoc_filters\": [{\"expressionType\": \"SQL\", \"clause\": \"WHERE\"}]`\n\n## FINAL OUTPUT PHASE (ONLY AFTER STEP 6)\n\nYou are strictly forbidden from formatting your response this way until you have successfully executed Step 6. \nOnce Step 6 is complete, your FINAL response to the user must be exactly the output of the `superset_chart_argument_create` tool.\n\n- DO NOT wrap response in ```json or ```\n- DO NOT return as string\n- DO NOT escape quotes (no \\\")\n- DO NOT include \\n, \\t, or formatting characters\n- DO NOT prefix or suffix anything\n\n{\n\t\"slice_name\": \"Chart name/title\",\n\t\"datasource_id\": \"Dataset or table ID\",\n\t\"datasource_type\": \"table or query\",\n\t\"viz_type\": \"Chart type (bar, line, pie, table, pivot_table_v2 etc.)\",\n\t\"params\": { ... }\n}"
        }
      },
      "id": "b2b66a98-a47f-4840-9b48-d16acc73814b",
      "name": "AI Agent5",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -3104,
        1072
      ],
      "typeVersion": 3
    },
    {
      "parameters": {
        "projectId": {
          "__rl": true,
          "value": "steadfast-rex-495606-p2",
          "mode": "id"
        },
        "modelName": "gemini-2.5-pro",
        "options": {
          "temperature": 0.7
        }
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleVertex",
      "typeVersion": 1,
      "position": [
        -3232,
        1344
      ],
      "id": "507756e3-6524-4c91-8912-aedf157274e9",
      "name": "Google Vertex Chat Model5",
      "credentials": {
        "googleApi": {
          "id": "BFYOTKzqFwio5zVh",
          "name": "atul"
        }
      }
    },
    {
      "parameters": {
        "connectionType": "sse",
        "operation": "executeTool",
        "toolName": "={{ $fromAI(\"tool\",\"the tool selected\") }}",
        "toolParameters": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Tool_Parameters', ``, 'json') }}"
      },
      "type": "n8n-nodes-mcp.mcpClientTool",
      "typeVersion": 1,
      "position": [
        -2896,
        1344
      ],
      "id": "0a27ec1f-cd80-474a-a95a-362ec725ff1b",
      "name": "MCP Client9",
      "credentials": {
        "mcpClientSseApi": {
          "id": "3N1acS5R7xzkLZny",
          "name": "MCP Client (STDIO) account 2"
        }
      }
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "79ebe837-a912-4814-90d9-b96d1fa131b3",
        "responseMode": "lastNode",
        "options": {}
      },
      "id": "941a98d4-1560-4631-906a-e09390eddabc",
      "name": "Webhook1",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -3376,
        1072
      ],
      "webhookId": "79ebe837-a912-4814-90d9-b96d1fa131b3",
      "typeVersion": 2.1
    }
  ],
  "pinData": {},
  "connections": {
    "Google Vertex Chat Model5": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent5",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "MCP Client9": {
      "ai_tool": [
        [
          {
            "node": "AI Agent5",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Webhook1": {
      "main": [
        [
          {
            "node": "AI Agent5",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false,
    "timeSavedMode": "fixed",
    "callerPolicy": "workflowsFromSameOwner"
  },
  "versionId": "1a5a603f-551a-4ec8-b51a-75fa40906076",
  "meta": {
    "templateCredsSetupCompleted": true,
    "instanceId": "222b2f481627b103dedd725016ff99afa115f2d6484c23426f38ae8f5c9d3147"
  },
  "id": "3JcBdOXjYXyOXeXU",
  "tags": []
}

Share the output returned by the last node

{
“structuredContent”: {
“result”: {
“message”: “Existing session key is valid”,
“session_cookie”: “session=.eJwt…”
}
},
“isError”: false
}
This is the output of Step 1 only.
Steps 2 through 6 are never executed.

Information on your n8n setup

  • n8n version: 2.20.9
  • Database : PostgreSQL (default)
  • n8n EXECUTIONS_PROCESS setting (default: own, main): main
  • Running n8n via (Docker, npm, n8n cloud, desktop app): Docker
  • Operating system: Linux

@Prathamesh_Patil1
使用其他AI模型。
Google系列AI模型不適合工具使用。
它們的工具聲明與OpenAI格式不相容

感謝你的回應!這很好地解釋了 Google 的工具宣告格式不相容的原因。

為了為日後找到這個討論串的人提供更多背景資訊:

這個工作流實際上在 n8n 版本 1.121.9 時運作完美無缺,使用相同的設定 — Gemini Vertex + MCP Client 依序呼叫全部 6 個工具,沒有任何問題。

問題只在升級到 2.x 版本後才開始出現(已在 2.17.8 和 2.20.9 版本上測試)。所以看起來 n8n 在 1.x 和 2.x 之間對工具宣告的處理方式有所改變,導致與 Google Vertex 模型的相容性受損。

我現在的問題:

  1. n8n 1.x 和 2.x 之間的工具/函數宣告格式是否有破壞性改變,影響了 Google Vertex 的相容性?
  2. 是否有已知的解決方法可以在 2.x 中恢復 Vertex + MCP Client 的 1.x 行為,而不需要切換模型?
  3. 如果切換模型是唯一的選擇,目前在 n8n 2.x 中,哪個模型最被推薦用於可靠的 MCP 工具依序呼叫?
    (OpenAI GPT-4o?Anthropic Claude?Azure OpenAI?)

如果可能的話,我真的更想保留 Google Vertex,因為我們其他的基礎設施都是基於 GCP 的。任何指導都很感謝!

您已經提供了答案

1.123.43 對您有效嗎?

歡迎 @Prathamesh_Patil1 加入我們的社群!我是 Jay,我是 n8n 認證創作者。

n8n 2.x 與 Gemini Vertex 的行為變化是一個已知問題 - 工具宣告格式已更新,某些 Gemini 模型現在會將成功的工具回應視為最後步驟。在保持使用 Vertex 的情況下,有兩件事值得嘗試:首先,在系統提示中新增明確的指令,例如「您必須在給出最終答案之前按順序完成所有步驟。不要在第一次工具呼叫後停止。」其次,檢查您的 AI Agent 節點中的「Max Iterations」設定,並確保設定得足夠高(對於 6 步流程至少 10-15 次)。如果 Gemini 在此之後仍然提前停止,Vertex 上的 Claude 3.5 Sonnet 對於多步驟工具呼叫是可靠的,不需要離開 GCP。

感謝Jay!非常感謝你的熱情歡迎和詳細的回應。

發文前我已經嘗試過的快速更新:

  1. 系統提示 — 已經有明確的順序指示,包括
    「你必須依序調用工具。在每次工具回應後,立即
    調用序列中的下一個工具,不要暫停。」以及所有6個步驟的硬性限制規則。仍然在第1步後停止。

  2. 最大迭代次數 — 已經設定為10+。行為沒有改變。

  3. 溫度 — 嘗試設定為0以獲得確定性行為。同樣的問題。

所有這些在1.121.9版本上都運作良好,無需任何特殊配置,
所以確實看起來像是2.x版本特有的破壞性變更。

關於Vertex上的Claude 3.5 Sonnet — 那是個很好的建議,因為
我們已經在GCP上。有幾個後續問題:

  1. Claude 3.5 Sonnet在n8n 2.x的Google Vertex Chat Model
    節點中直接可用,還是需要單獨的Anthropic節點?
  2. 有人確認過Claude 3.5 Sonnet on Vertex在n8n 2.20.9中
    成功運行6個以上的順序MCP工具調用嗎?
  3. Gemini相容性修復在未來n8n 2.x版本中有修復的可能性嗎,
    還是這被認為是模型端的限制?

將嘗試Vertex上的Claude方法,並報告結果。
再次感謝!