MCP tool outputSchema is dropped on the LiteLLM path
- Lenguaje dominante
- Python
- Estrellas
- 21.5k
- Forks
- 4k
- Merge medio
- 1 d 14 h
- PR fusionados (30 d)
- 37
Descripción
## 🔴 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%)
Guía de contribución
Evaluación
Este issue todavía no se ha evaluado.