Skip to content

[BUG] ADK LiteLlm tool calling fails with Groq — model outputs XML tags instead of function_call JSON #1532

@vitas

Description

@vitas

Environment

  • kagent-adk v0.8.0-beta9
  • Google ADK with LiteLlm model adapter
  • Groq API (llama-3.3-70b-versatile)
  • MCP tools via StreamableHTTPConnectionParams

Description

When using kagent-adk with Groq's llama-3.3-70b-versatile via LiteLlm, MCP tool calling fails. The model outputs XML-style tool call tags instead of proper OpenAI function_call JSON.

Groq rejects with:
```
{"error":{"message":"Failed to call a function. Please adjust your prompt. See 'failed_generation'",
"type":"invalid_request_error","code":"tool_use_failed",
"failed_generation":"<function=run_command {"command": "kubectl get deployments -n demo"} "}}
```

Root Cause

LiteLLM itself works correctly with Groq. Direct LiteLLM call inside the kagent container with the same model and same tool schema returns proper `tool_calls` JSON with `finish_reason: "tool_calls"`.

The issue is in how ADK converts MCP tool schemas through `FunctionDeclaration` and structures the messages/system prompt before passing to LiteLLM. Something in that conversion makes the model fall back to XML-style tool calling.

Reproduction

```python

This works (direct LiteLLM):

import litellm
result = litellm.completion(
model="groq/llama-3.3-70b-versatile",
messages=[{"role": "user", "content": "Get pods in namespace demo"}],
tools=[{"type": "function", "function": {"name": "run_command", "description": "Execute command", "parameters": {"type": "object", "required": ["command"], "properties": {"command": {"type": "string"}}}}}]
)

Returns proper tool_calls JSON ✓

This fails (via ADK):

from google.adk import Agent
from google.adk.models.lite_llm import LiteLlm
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StreamableHTTPConnectionParams

agent = Agent(
model=LiteLlm(model="groq/llama-3.3-70b-versatile"),
tools=[MCPToolset(connection_params=StreamableHTTPConnectionParams(url="http://mcp-server:3001/mcp"))],
instruction="Use run_command to execute kubectl commands"
)

Model outputs: <function=run_command {...}

Groq rejects: "Failed to call a function" ✗

```

Full reproduction

https://github.com/vitas/evidra-kagent-bench — Docker Compose stack with kagent + Evidra MCP server.

Related

Expected

Agent executes tool calls via proper function calling protocol.

Actual

Model falls back to XML-style tool call text, Groq rejects it with 400.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions