MCPServer completion handler returning more than 100 values fails on 2026-07-28 sessions and violates the 100-item limit on 2025-11-25 sessions
I maintainer di solito rispondono entro 1 giorno
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 88/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- python
- Ambito
- backend-api-design
Direzione di ricerca
Inizia dal wrapper MCPServer.completion in mcp/server/mcpserver.py (righe ~759-766), che passa il Completion dell'handler intatto; il limite di 100 elementi si trova in mcp_types/_v2026_07_28 ed è applicato a runner.py:381, quindi il wrapper deve troncare a 100 valori e impostare total/has_more prima della validazione, mantenendo i valori impostati dall'handler. Confronta con createCompletionResult dello SDK TypeScript. Per concludere: un test di regressione sotto tests/server/mcpserver/ che usa un Client in memoria deve passare sia per mode="auto" (2026-07-28) sia per mode="legacy" (2025-11-25), restituendo 100 valori con has_more=True.
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
An @mcp.completion() handler that returns more than 100 values behaves differently depending on the negotiated protocol version, and both behaviours are wrong:
- 2026-07-28 session: the whole
completion/completerequest fails with-32603 "Handler returned an invalid result". The user gets no suggestions at all. - 2025-11-25 session: all values go out on the wire. The spec says
values"Must not exceed 100 items", andtotal/hasMoreare left unset, so the client can't tell the list was too long.
It's easy to hit with the filter-by-prefix pattern from docs/servers/completions.md. When the user hasn't typed anything yet (argument.value == ""), every candidate matches, so any handler over a list of more than 100 options (countries, time zones, repos, file names, and so on) fails as soon as the field is focused.
The 100-item cap is only enforced by the 2026-07-28 wire model (Completion.values: Annotated[list[str], Field(max_length=100)] in mcp_types/_v2026_07_28). runner.py:381 checks results against that model and turns the ValidationError into a generic INTERNAL_ERROR. The 2025-11-25 wire model has no such constraint, so nothing stops the oversize list there. The MCPServer.completion wrapper (server.py:759-766) passes the handler's Completion through as-is.
For comparison, the TypeScript SDK's McpServer truncates to 100 and fills the pagination hints (createCompletionResult: values.slice(0, 100), total: suggestions.length, hasMore: suggestions.length > 100).
Expected: the same handler works on both protocol versions. The client receives the first 100 values with total / hasMore telling it more exist, as Completion's own docstring ("total … can exceed the number of values actually sent") and the docs' total= / has_more= note describe.
Server log on the 2026-07-28 session:
ERROR handler for 'completion/complete' returned an invalid result
pydantic_core._pydantic_core.ValidationError: 1 validation error for CompleteResult
completion.values
List should have at most 100 items after validation, not 150 [type=too_long, ...]
I reported this and would like to fix it. Proposed approach: in the MCPServer.completion wrapper, when the handler returns more than 100 values, send the first 100 and set total (to the full count) and has_more=True. Values the handler set explicitly win. Handlers returning ≤100 values are unchanged. The lowlevel Server stays as it is, since a lowlevel handler builds the CompleteResult itself. I'd add a regression test in tests/server/mcpserver/ using an in-memory Client, covering both mode="auto" (2026-07-28) and mode="legacy" (2025-11-25). It's roughly 10 lines of source. If you'd prefer a different behaviour (for example, raising a clear error at the wrapper instead of truncating), I'm happy to do that.
I used an AI assistant to help narrow this down; I ran the reproduction myself on 2.3.0 and on main.
Example Code
import anyio
from mcp_types import Completion, PromptReference
from mcp.client import Client
from mcp.server.mcpserver import MCPServer
COUNTRIES = [f"country-{i:03}" for i in range(150)]
mcp = MCPServer("demo")
@mcp.prompt()
def travel(country: str) -> str:
return f"Plan a trip to {country}"
@mcp.completion()
async def complete(ref, argument, context):
# Filter by the typed prefix, as in docs/servers/completions.md; an empty prefix matches everything.
return Completion(values=[c for c in COUNTRIES if c.startswith(argument.value)])
async def main() -> None:
for mode in ("auto", "legacy"):
async with Client(mcp, mode=mode) as client:
try:
result = await client.complete(
ref=PromptReference(type="ref/prompt", name="travel"),
argument={"name": "country", "value": ""},
)
c = result.completion
print(f"{client.protocol_version}: {len(c.values)} values, total={c.total}, has_more={c.has_more}")
except Exception as e:
print(f"{client.protocol_version}: {type(e).__name__}: {e}")
anyio.run(main)
Output:
2026-07-28: MCPError: Handler returned an invalid result
2025-11-25: 150 values, total=None, has_more=None
Python & MCP Python SDK
Python 3.12.12, mcp 2.3.0, pydantic 2.13.5 (PyPI release)
Python 3.14.0, mcp main @ 91941ed, pydantic 2.12.5
Windows 11
- Lingua principale
- Python
- Stelle
- 24.5k
- Fork
- 4k
- Merge medio
- 18h 19m
- PR unite (30g)
- 36
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 78/100
modelcontextprotocol/python-sdk#3685 ·
I maintainer di solito rispondono entro 1 giorno
-
Type annotation gaps and unhandled FileNotFoundError in src/mcp/cli/cli.pyForse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. Apertaenhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
modelcontextprotocol/python-sdk#3673 · 3 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Streamable HTTP server rejects a mixed-case Content-Type with 415Forse già presa @CRYPTONIKAV l’ha presa 2 giorni fa. Apertabug v1 v2
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
modelcontextprotocol/python-sdk#3670 · 4 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Bug in the MCP Apps documentation.Forse già presa @Kludex l’ha presa 1 giorno fa. Apertadocumentation v2
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
modelcontextprotocol/python-sdk#3662 ·
I maintainer di solito rispondono entro 1 giorno
-
Audio(data=b"") raises "Either path or data can be provided", while Image(data=b"") worksForse già presa @ajay206 l’ha presa oggi. Apertabug v1 v2
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 85/100
modelcontextprotocol/python-sdk#3656 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di modelcontextprotocol/python-sdk
Issue simili
-
enhancement from-review
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
khuisman/mcp-gee-sweet#1010 ·
I maintainer di solito rispondono entro 1 giorno
-
bug confirmed issue
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
open-webui/open-webui#32333 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
ll7/robot_sf_ll7#10368 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
-
mcp: a write that loses its answer is reported as "cannot reach", although it may have landedAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
flop-labs/technocore-chat#982 ·
I maintainer di solito rispondono entro 1 giorno