Bare `dict` / `list` / `tuple` return annotations silently produce no structured output
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 2/5
- Temps estimé
- 1-3 heures
- Accessibilité débutants
- 72/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Stack technique
- python
- Domaine
- backend-api-design
Piste de recherche
Commencez par lire _create_output_model dans src/mcp/server/mcpserver/utilities/func_metadata.py et la documentation sur la sortie structurée dans docs/servers/structured-output.md. Reproduisez la différence entre les annotations de conteneur simples et typées, puis examinez les tests existants pour les schémas de sortie et le contenu structuré. Le travail est terminé lorsque les annotations simples de dict, list et tuple ont le comportement attendu en matière de sortie structurée et que la documentation l’explique.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Initial Checks
- I confirm that I'm using the newest release of my line (the latest 2.x, or the latest 1.x if I'm still on v1)
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
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)
- Langage dominant
- Python
- Étoiles
- 24.5k
- Forks
- 4k
- Merge moyen
- 18 h 28 min
- PR mergées (30 j)
- 38
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de modelcontextprotocol/python-sdk
-
2026-07-28 SSE responses share one header list, so in-place middleware appends leak across responsesPeut-être à nouveau libre Une pull request pour cette issue a été fermée sans être fusionnée. Ouvertebug spec-2026-07-28 v2
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
modelcontextprotocol/python-sdk#3701 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
bug v1 v2
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
modelcontextprotocol/python-sdk#3698 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
Streamable HTTP: Content-Type handling is order dependent and accepts invalid valuesPeut-être pris @jayzuccarelli l’a pris il y a 5 jours. Ouvertebug v1 v2
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
modelcontextprotocol/python-sdk#3691 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
Skills: URI traversal validation skips percent-encoded dot-segmentsPeut-être pris @Varshith-Kali l’a pris il y a 4 jours. Ouvertebug v2
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
modelcontextprotocol/python-sdk#3685 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
Type annotation gaps and unhandled FileNotFoundError in src/mcp/cli/cli.pyPeut-être à nouveau libre Une pull request pour cette issue a été fermée sans être fusionnée. Ouverteenhancement
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
modelcontextprotocol/python-sdk#3673 · 4 commentaires ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de modelcontextprotocol/python-sdk
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
ok-oldking/ok-wuthering-waves#1785 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
healthchecks/healthchecks#1349 ·
-
deployment release-lag
Difficulté 1/5 Moins d'une heure Accessibilité débutants 68/100
nolte/kamerplanter#2374 ·
Les mainteneurs répondent en général sous 1 jour
-
batchterms() drops queries without a similar() clause, misaligning results with inputsPeut-être pris @MohammadHijjawi97 l’a pris aujourd’hui. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 86/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 77/100
lidofinance/diffyscan#239 ·
Les mainteneurs répondent en général sous 1 jour