Skip to content

MCP tool outputSchema is dropped on the LiteLLM path #6784

Description

@schlaepf

🔴 Required Information

Describe the Bug:

An MCP tool's outputSchema never reaches the model when the agent is backed by LiteLlm. MCPTool._get_declaration() can populate response_json_schema, but _function_declaration_to_tool_param() in lite_llm.py builds the tool payload from name, description and parameters only, so the output schema is silently dropped.

The result is that the model cannot describe or rely on a tool's result shape, which is the same user-visible symptom as #2828 (fixed for the Gemini path in c8e5340, later refactored behind the JSON_SCHEMA_FOR_FUNC_DECL feature flag).

Enabling ADK_ENABLE_JSON_SCHEMA_FOR_FUNC_DECL=1 does not help on this path: the declaration is built correctly, but the LiteLLM conversion still discards it. The payload is byte-identical with the flag on and off.

Steps to Reproduce:

  1. pip install google-adk==1.34.1
  2. Save the script under Minimal Reproduction Code as adk_repro.py
  3. Run python adk_repro.py
  4. Run ADK_ENABLE_JSON_SCHEMA_FOR_FUNC_DECL=1 python adk_repro.py
  5. Compare the printed payloads — they are identical, and neither contains the output schema

Expected Behavior:

The declared output schema should reach the model on the LiteLLM path, as it does on the Gemini path. Most OpenAI-compatible providers have no dedicated field for a tool's result schema, so a reasonable approach would be to append a rendering of the schema to the tool description (which is forwarded) rather than inventing a non-standard key.

Observed Behavior:

ADK_ENABLE_JSON_SCHEMA_FOR_FUNC_DECL = 1
declaration.response             is set: False
declaration.response_json_schema is set: True

Payload LiteLlm sends to the model:
{
  "type": "function",
  "function": {
    "name": "get_widget",
    "description": "Return a widget.",
    "parameters": {
      "type": "object",
      "properties": {"service": {"type": "string"}},
      "required": ["service"]
    }
  }
}

output schema present in payload: False

declaration.response_json_schema is set, yet nothing derived from it appears in the payload.

Environment Details:

  • ADK Library Version (pip show google-adk): 1.34.1
  • Desktop OS: macOS 26.6
  • Python Version (python -V): 3.12

Model Information:

  • Are you using LiteLLM: Yes
  • Which model is being used: GPT models via a LiteLLM-compatible endpoint (not model-specific — the schema is dropped before any request is made)

🟡 Optional Information

Regression:

Partly. #2828 was fixed in c8e5340 by setting response=_to_gemini_schema(output_schema) on the FunctionDeclaration. That assignment no longer exists on main; _get_declaration() now sets either parameters alone or parameters_json_schema + response_json_schema depending on FeatureName.JSON_SCHEMA_FOR_FUNC_DECL (WIP, default_on=False). Either way _function_declaration_to_tool_param() ignores both response and response_json_schema, so the LiteLLM path has no route for it.

Additional Context:

Relevant code on main:

  • src/google/adk/tools/mcp_tool/mcp_tool.py_get_declaration() sets response_json_schema=output_schema only when the feature flag is enabled.
  • src/google/adk/models/lite_llm.py_function_declaration_to_tool_param() reads parameters / parameters_json_schema and returns {"type": "function", "function": {"name", "description", "parameters"}}.
  • src/google/adk/models/lite_llm.py_build_function_declaration_log() does read func_decl.response, but that is logging only and does not affect the request.

grep -c response_json_schema src/google/adk/models/lite_llm.py returns 0; only google_llm.py and apigee_llm.py reference it.

Happy to send a PR if the description-appending approach sounds right, or another shape if you prefer.

Minimal Reproduction Code:

"""Minimal reproduction: an MCP tool's outputSchema never reaches a LiteLLM-backed model."""

import json
import os

from google.adk.models.lite_llm import _function_declaration_to_tool_param
from google.adk.tools.mcp_tool.mcp_tool import McpTool as AdkMcpTool
from mcp.types import Tool as McpTool

OUTPUT_SCHEMA = {
    "type": "object",
    "additionalProperties": False,
    "required": ["status", "data"],
    "properties": {
        "status": {"type": "string", "enum": ["success", "error"]},
        "data": {"type": "string", "description": "Preformatted text, not JSON."},
    },
}
INPUT_SCHEMA = {
    "type": "object",
    "properties": {"service": {"type": "string"}},
    "required": ["service"],
}

mcp_tool = McpTool(
    name="get_widget",
    description="Return a widget.",
    inputSchema=INPUT_SCHEMA,
    outputSchema=OUTPUT_SCHEMA,
)

tool = AdkMcpTool(mcp_tool=mcp_tool, mcp_session_manager=None)
declaration = tool._get_declaration()

flag = os.environ.get("ADK_ENABLE_JSON_SCHEMA_FOR_FUNC_DECL", "<unset>")
print(f"ADK_ENABLE_JSON_SCHEMA_FOR_FUNC_DECL = {flag}")
print(f"declaration.response             is set: {declaration.response is not None}")
print(f"declaration.response_json_schema is set: {declaration.response_json_schema is not None}")

payload = _function_declaration_to_tool_param(declaration)
print("\nPayload LiteLlm sends to the model:")
print(json.dumps(payload, indent=2))

print(f"\noutput schema present in payload: {'success' in json.dumps(payload)}")

How often has this issue occurred?:

  • Always (100%)

Metadata

Metadata

Assignees

Labels

tools[Component] This issue is related to tools

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions