Hacktoberfest 2026:維護者為十月標記出來的 issue,仍然開放、適合新手。 瀏覽 Hacktoberfest issue

Bare `dict` / `list` / `tuple` return annotations silently produce no structured output

未關閉 適合新手
#3,725 3 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

維護者通常 1 天內回覆

還沒有人認領這個 Issue。

評估

難度
2/5
預估耗時
1-3 小時
新手友好度
72/100
Issue 類型
缺陷
描述清晰度
描述清楚
活躍度
活躍
技術堆疊
python

研究方向

先閱讀 src/mcp/server/mcpserver/utilities/func_metadata.py 中的 _create_output_model,以及 docs/servers/structured-output.md 中關於結構化輸出的文件。重現未指定型別的容器註記與指定型別的容器註記之間的差異,然後檢查現有的輸出 schema 和結構化內容測試。未指定型別的 dict、list 和 tuple 註記具有預期的結構化輸出行為,且文件對此有所說明,即為完成。

由索引模型根據 Issue 內容生成。

描述

bug v1 v2
Initial Checks
Release line

2.x (current stable)

Description

A tool annotated with a bare dict (or list / tuple) gets no outputSchema and no structuredContent. The result only arrives as JSON text. -> dict[str, Any] works, and -> str gets {"result": ...}. With structured_output=True the bare annotation raises InvalidSignature: Function f: return type <class 'dict'> is not serializable for structured output, which reads as if a dict weren't serializable.

Expected: -> dict behaves like dict[str, Any], and -> list / -> tuple like list[Any] (wrapped in {"result": ...}). Failing that, the structured-output docs could say that bare containers opt out.

Cause: _create_output_model sends bare dict / list / tuple to the "other class types" case. get_type_hints(dict) is empty, so the model stays None: the silent opt-out documented for classes without type hints, which isn't obvious for builtins. We hit it while building an MCP server: our tools were -> dict, and our client code expected structured_content that was always None.

Proposed fix: a case before the class fallback that sends bare dict down the dict[str, ...] path and wraps bare list / tuple like their generic forms, plus a test and one sentence in docs/servers/structured-output.md. It's about 10 lines of code, and the full suite passes (6206 passed). One behaviour change to weigh: existing bare -> dict / -> list tools would start publishing an outputSchema and validating their results.

I'd like to send this as a PR if you're open to it. It's on a branch: https://github.com/g-s-jithesh/python-sdk/commit/6ecfa04ece6032816c7d3a087fd8c841cb0c43e1

I used an AI coding assistant (Claude Code) to help investigate this and draft the fix. I reproduced the bug myself and reviewed the change.

Example Code
import asyncio
from typing import Any

from mcp import Client
from mcp.server.mcpserver import MCPServer

mcp = MCPServer("repro")


@mcp.tool()
def bare() -> dict:
    return {"id": 1}


@mcp.tool()
def typed() -> dict[str, Any]:
    return {"id": 1}


async def main() -> None:
    async with Client(mcp) as client:
        for name in ("bare", "typed"):
            print(name, (await client.call_tool(name, {})).structured_content)


asyncio.run(main())
# bare None
# typed {'id': 1}
Python & MCP Python SDK
Python 3.14, Windows 11; mcp 2.3.0, and main at 9f66f37 (src/mcp/server/mcpserver/utilities/func_metadata.py, _create_output_model)
主要語言
Python
星號
24.5k
分支
4k
平均合併
18 小時
30 天內合併 PR
39

環境準備

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

modelcontextprotocol/python-sdk 的其他 Issue

查看 modelcontextprotocol/python-sdk 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。