google / google/adk-python

MCP tool outputSchema is dropped on the LiteLLM path

Ouverte
#6,784 1 commentaire 0 réactions 1 personne assignée Réclamée par @sanketpatil06 Voir sur GitHub
tools
Langage dominant
Python
Étoiles
21.5k
Forks
4k
Merge moyen
1 j 14 h
PR mergées (30 j)
37

Description

## 🔴 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:**

```python
"""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", "")
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%)

Guide de contribution

Ouvrir le guide de contribution

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.