Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

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

未关闭 适合新手
#3,725 0 条评论 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 小时 28 分钟
30 天内合并 PR
38

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

modelcontextprotocol/python-sdk 的其他 Issue

查看 modelcontextprotocol/python-sdk 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

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