[Bug]: Inconsistent structured output wrapping and opt-out for typing.Dict and typing sequence generics in func_metadata
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
- #3772 di @chauvuusvn — chiusa senza merge
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 82/100
Direzione di ricerca
Inizia da src/mcp/server/mcpserver/utilities/func_metadata.py e leggi _create_output_model() e func_metadata(), dove la issue individua le due incongruenze. Controlla i test esistenti per l’introspezione dei tipi restituiti e aggiungi casi di test per typing.Dict, typing.List e typing.Tuple senza argomenti di tipo, insieme ai corrispondenti tipi integrati. Il lavoro è completato quando typing.Dict senza argomenti di tipo produce uno schema oggetto non avvolto e le sequenze del modulo typing senza argomenti di tipo rinunciano all’output strutturato come descritto.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
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
In src/mcp/server/mcpserver/utilities/func_metadata.py, return type introspection handles built-in types differently from their unsubscripted typing generic counterparts (typing.Dict, typing.List, typing.Tuple).
Issue 1: typing.Dict is forcibly wrapped in {"result": ...} instead of top-level object
When a tool returns dict or dict[str, Any], _create_output_model sets wrap_output = False and derives a top-level JSON object schema:
elif type_annotation is dict:
model = dict[str, Any]
However, when a tool is annotated with typing.Dict (unsubscripted), get_origin(typing.Dict) is dict while get_args(typing.Dict) is (). In _create_output_model():
if origin is dict:
args = get_args(type_expr)
if len(args) == 2 and args[0] is str:
model = type_expr
else:
# dict with non-str keys needs wrapping
model = _create_wrapped_model(func_name, original_annotation)
wrap_output = True
Because len(args) == 0 != 2, it falls through to else (intended only for non-str keys like dict[int, str]). As a result:
dict: treated as top-level JSON object (wrap_output = False)typing.Dict: unexpectedly wrapped into{"result": ...}(wrap_output = True)
Issue 2: typing.List and typing.Tuple bypass the opt-out gate
In func_metadata():
if structured_output is None and (return_type_expr in (list, tuple) or _returns_content(return_type_expr)):
return FuncMetadata(arg_model=arguments_model)
Because typing.List is not list (typing.List in (list, tuple) evaluates to False), tools annotated with -> typing.List or -> typing.Tuple fail to opt out and are forced through _create_output_model(), generating an unwanted wrapper schema { "result": typing.List }.
Example Code
import typing
from mcp.server.mcpserver.utilities.func_metadata import func_metadata
def tool_built_in_dict() -> dict:
return {"status": "ok"}
def tool_typing_dict() -> typing.Dict:
return {"status": "ok"}
def tool_built_in_list() -> list:
return ["a", "b"]
def tool_typing_list() -> typing.List:
return ["a", "b"]
meta_bi_dict = func_metadata(tool_built_in_dict)
meta_ty_dict = func_metadata(tool_typing_dict)
meta_bi_list = func_metadata(tool_built_in_list)
meta_ty_list = func_metadata(tool_typing_list)
# Inconsistent wrapping:
print("dict wrap_output:", meta_bi_dict.wrap_output) # False
print("typing.Dict wrap_output:", meta_ty_dict.wrap_output) # True (Expected: False)
# Inconsistent opt-out:
print("list schema:", meta_bi_list.output_schema) # None
print("typing.List schema:", meta_ty_list.output_schema) # {'type': 'object', 'properties': {'result': ...}} (Expected: None)
Proposed Fix
- In
_create_output_model():
elif origin is dict:
args = get_args(type_expr)
if len(args) == 2 and args[0] is str:
model = type_expr
elif len(args) == 0:
# Bare typing.Dict is equivalent to bare dict
model = dict[str, Any]
else:
model = _create_wrapped_model(func_name, original_annotation)
wrap_output = True
- In
func_metadata():
if structured_output is None and (
return_type_expr in (list, tuple, typing.List, typing.Tuple) or _returns_content(return_type_expr)
):
return FuncMetadata(arg_model=arguments_model)
Version
Python 3.10+, MCP Python SDK 2.x
- Lingua principale
- Python
- Stelle
- 24.7k
- Fork
- 4.1k
- Merge medio
- 18h 27m
- PR unite (30g)
- 15
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di modelcontextprotocol/python-sdk
-
bug v2
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
modelcontextprotocol/python-sdk#3811 ·
I maintainer di solito rispondono entro 1 giorno
-
bug v2
Difficoltà 2/5 1-3 ore Idoneità per principianti 79/100
modelcontextprotocol/python-sdk#3810 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
bug v1 v2
Difficoltà 2/5 1-3 ore Idoneità per principianti 79/100
modelcontextprotocol/python-sdk#3781 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
bug v2
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
modelcontextprotocol/python-sdk#3769 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
2026 Streamable HTTP rejects whitespace-padded Mcp-Name valuesForse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. Apertabug spec-2026-07-28 v2
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
modelcontextprotocol/python-sdk#3763 · 4 commenti ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di modelcontextprotocol/python-sdk
Issue simili
-
Server mode OAuth2: 'NoneType' object is not subscriptable on every request after re-submitting the OAuth2 login while already logged inForse già presa @Rarasinhoo l’ha presa oggi. Aperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
pgadmin-org/pgadmin4#10733 ·
I maintainer di solito rispondono entro 3 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
aws-samples/sample-per-model-bedrock#752 ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
int-brain-lab/mpci#32 ·
-
area:docs priority:p2 type:docs
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
jejjohnson/geostack#120 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
sublimelsp/LSP-vue#203 · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno