AI Agent + MCP Client only calls tool once and stops — 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
Use other AI models.
Google family of AI models is not compatible for tooling use.
Their tooling declaration is not compatible with OpenAI format

Thanks for the response! That makes sense regarding Google’s
tool declaration format incompatibility.

Just to add more context for anyone who finds this thread later:

This workflow was actually working perfectly on n8n version 1.121.9
with the same setup — Gemini Vertex + MCP Client calling all 6 tools
sequentially without any issues.

The problem started only after upgrading to 2.x (tested on 2.17.8
and 2.20.9). So it seems like something changed in how n8n handles
tool declarations between 1.x and 2.x that broke compatibility with
Google Vertex models specifically.

My questions now:

  1. Was there a breaking change in tool/function declaration format
    between n8n 1.x and 2.x that affected Google Vertex compatibility?
  2. Is there a known workaround to restore the 1.x behavior for
    Vertex + MCP Client in 2.x without switching models?
  3. If switching models is the only option, which model is currently
    recommended for reliable sequential MCP tool calling in n8n 2.x?
    (OpenAI GPT-4o? Anthropic Claude? Azure OpenAI?)

Would really prefer to stay on Google Vertex if possible since the
rest of our infrastructure is GCP-based. Any guidance appreciated!

You have already stated the answer

Does 1.123.43 work for you?

If my answer does help you, please mark it as solution. Thank you!

Welcome @Prathamesh_Patil1 to our community! I’m Jay and I am a n8n verified creator.

The behavior change in n8n 2.x with Gemini Vertex is a known issue - the tool declaration format was updated and some Gemini models now treat a successful tool response as the final step. Two things worth trying while staying on Vertex: first, add explicit instruction in your system prompt like “You must complete all steps sequentially before giving a final answer. Do not stop after the first tool call.” Second, check the “Max Iterations” setting in your AI Agent node and make sure it’s set high enough (at least 10-15 for a 6-step flow). If Gemini still stops early after that, Claude 3.5 Sonnet on Vertex is reliable for multi-step tool calling and doesn’t require switching away from GCP.

Thanks Jay! Really appreciate the warm welcome and the detailed response.

Quick update on what I’ve already tried before posting:

  1. System prompt — already has explicit sequential instructions including
    “You must call tools sequentially. After every tool response, immediately
    call the next tool in the sequence without pausing.” and hard gating rules
    for all 6 steps. Still stops after Step 1.

  2. Max Iterations — already set to 10+. No change in behavior.

  3. Temperature — tried setting to 0 for deterministic behavior. Same issue.

All of these worked fine on 1.121.9 without any special configuration,
so it does seem like a 2.x breaking change specifically.

Regarding Claude 3.5 Sonnet on Vertex — that’s a great suggestion since
we’re already on GCP. A couple of follow-up questions:

  1. Is Claude 3.5 Sonnet available directly in the Google Vertex Chat Model
    node in n8n 2.x, or does it require a separate Anthropic node?
  2. Has anyone confirmed Claude 3.5 Sonnet on Vertex successfully running
    6+ sequential MCP tool calls in n8n 2.20.9?
  3. Is there any chance of a fix coming for Gemini compatibility in a future
    n8n 2.x release, or is this considered a model-side limitation?

Will try the Claude on Vertex approach and report back with results.
Thanks again!