google / google/adk-python

set_model_response is missing from the MCP _RESERVED_TOOL_NAMES guard

未关闭 适合新手
#7,144 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
主要语言
Python
星标
21.5k
派生
4k
平均合并
1 天 22 小时
30 天内合并 PR
31

描述

`_RESERVED_TOOL_NAMES` in `src/google/adk/tools/mcp_tool/mcp_tool.py` omits `set_model_response`, even though it is a tool name the framework itself puts on the wire. The guard added in #6796 states its own invariant in the comment above the set:

```python
# Tool names the framework itself puts on the wire. A server advertising one of
# these would have its tool dispatched in place of the framework's own, so the
# name is refused at registration.
_RESERVED_TOOL_NAMES = frozenset({
REQUEST_EUC_FUNCTION_CALL_NAME, # adk_request_credential
REQUEST_CONFIRMATION_FUNCTION_CALL_NAME, # adk_request_confirmation
REQUEST_INPUT_FUNCTION_CALL_NAME, # adk_request_input
transfer_to_agent.__name__, # transfer_to_agent
})
```

`set_model_response` satisfies that description but is not in the set, so an MCP server advertising it is accepted where the other four are refused.

### `set_model_response` is a framework-owned tool name

* Defined as `def set_model_response() -> str:` in `src/google/adk/tools/set_model_response_tool.py` (`self.func = set_model_response`), so that is its declaration name.
* Injected into the request whenever `output_schema` is set alongside other tools:
`src/google/adk/flows/llm_flows/prompt/_schema.py:54`
```python
set_response_tool = SetModelResponseTool(agent.output_schema)
llm_request.append_tools([set_response_tool])
```
* The framework then instructs the model to use it by name: *"you must provide your final response using the set_model_response tool"* (`_schema.py:57-64`).
* And it reads the answer back by that name — `get_structured_model_response()` (`_schema.py:97`) is reached from `base_llm_flow.py:710` with the comment *"Check if this is a set_model_response function response"*.

### Why that matters at an MCP boundary

`LlmRequest.append_tools` resolves a duplicate name by **last-wins with only a warning** (`src/google/adk/models/llm_request.py`):

```python
if tool.name in self.tools_dict:
# Both declarations are still advertised to the model, but only one
# tool can hold the name, so calls land on the survivor.
logging.warning(
"Duplicate tool name %r: the previously registered tool is shadowed ...",
tool.name,
)
self.tools_dict[tool.name] = tool
```

So if an MCP server advertises `set_model_response`, one of the two tools holds the name and the model's `set_model_response` call is dispatched there. If the server's tool is the survivor, the agent's **structured final answer is delivered to the third-party MCP server** and the framework never sees it — which is the outcome the reserved-name check exists to prevent. If the framework's tool is the survivor, the duplicate is still advertised and callable by name, so calls can land on the wrong one.

Either way the invariant stated in the #6796 comment is violated: the name is never refused at registration.

### Reproduction sketch

```python
agent = LlmAgent(
model=..., tools=[McpToolset(connection_params=)],
output_schema=MySchema,
)
# Expected: ValueError, as for transfer_to_agent / adk_request_confirmation
# Actual: accepted; a warning is logged at request build time
```

### Suggested fix

Add the name to the set:

```python
_RESERVED_TOOL_NAMES = frozenset({
REQUEST_EUC_FUNCTION_CALL_NAME,
REQUEST_CONFIRMATION_FUNCTION_CALL_NAME,
REQUEST_INPUT_FUNCTION_CALL_NAME,
transfer_to_agent.__name__,
'set_model_response',
})
```

If it is useful, the same reasoning may apply to other in-model names the framework injects (`google_search`, `google_maps`, `url_context`, `vertex_ai_search`, `code_execution`, `load_artifacts`, `load_memory`) — I have not verified each of those reaches `tools_dict`, so I have deliberately kept this report to the one name I traced end to end.

Happy to send the set change plus a unit test alongside `test_mcp_tool.py` if that is the preferred route.

贡献指南

打开贡献指南

调研方向

从 src/google/adk/tools/mcp_tool/mcp_tool.py 开始,检查 _RESERVED_TOOL_NAMES 保护逻辑,然后阅读 test_mcp_tool.py 中相关的测试。将 set_model_response 添加到保留名称中,并覆盖一个发布该名称的 MCP 服务器。完成标准是注册行为与其他保留工具名称一致地引发 ValueError。

由索引模型根据 Issue 内容生成。

评估

技术栈
python
领域
tooling
Issue 类型
缺陷
难度
2/5
预计耗时
1-3 小时
活跃度
活跃
描述清晰度
描述清楚
新手友好度
88/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。