modelcontextprotocol / modelcontextprotocol/python-sdk
Tool input schemas carry a pydantic-derived title on every property
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Python
- Sterne
- 24.3k
- Forks
- 4k
- Ø Merge
- 1 T. 1 Std.
- Gemergte PRs (30 T.)
- 31
Beschreibung
Description
Every tool's inputSchema carries a title on every property, derived by pydantic from the field name. A parameter named exercise_id gets "title": "Exercise Id" — a restatement of the key it already sits under. Tool schemas are re-sent to the model on every request, so this is paid for in context on every turn.
I ran into this running a local 27B model against the wger MCP server, where context is genuinely scarce. Measuring its live tools/list:
| bytes | share | |
|---|---|---|
| whole payload, 49 tools | 43,710 | 100% |
| tool descriptions (prose) | 10,904 | 25% |
auto-derived title keys (297 of them) |
8,333 | 19% |
anyOf null-wrapping on optionals |
1,869 | 4% |
My agent is granted 43 of those tools, which is ~11,100 tokens of schema against a 32k window — 42% of the context gone before the first message, once the system prompt is counted. Roughly 2,000 of those tokens are titles.
Reproduction — any tool at all:
from mcp.server.mcpserver import MCPServer
mcp = MCPServer("demo")
@mcp.tool()
def log_set(exercise_id: str, reps: int) -> str:
"""Log a set."""
return "ok"
inputSchema.properties is:
{
"exercise_id": {"title": "Exercise Id", "type": "string"},
"reps": {"title": "Reps", "type": "integer"}
}
I'd expect the titles not to be there, since they add nothing a model can act on that the property name doesn't already say.
GenerateJsonSchema has a hook for exactly this — field_title_should_be_set — and Tool.from_function already passes a custom generator elsewhere in the file, so it's a small change. Suppressing the automatic titles leaves an explicit Field(title=...) intact, which seems like the right line to draw: an explicit title is the author's choice, an auto-derived one is a default nobody asked for.
Two things I'd want a maintainer's call on before this is worth doing:
- Default or opt-in. Changing the default updates 12 test expectations in this repo (mostly
snapshot(...)intests/docs_src/), so it's visible. An opt-in flag onMCPServer(...)avoids that but adds public API. - Scope. Output schemas, prompts and resource templates generate titles the same way. Output schemas alone are another 61 titles in the payload I measured. Worth doing together, or separately?
Happy to open a PR if it's useful — I have the change and the test updates working locally against main, full suite green. Equally happy to leave it if you'd rather write it yourselves.
Disclosure: I used an AI agent to take the measurements and draft the change. The problem is one I actually hit, and I've read and can explain the result.
References
field_title_should_be_set— https://docs.pydantic.dev/latest/api/json_schema/#pydantic.json_schema.GenerateJsonSchema.field_title_should_be_set- Server measured — https://github.com/wger-project/mcp-server
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne bei Tool.from_function und seinem vorhandenen benutzerdefinierten Generator und untersuche anschließend Pydantics Hook GenerateJsonSchema.field_title_should_be_set. Überprüfe die Snapshot-Erwartungen in tests/docs_src/ und entscheide gemeinsam mit einem Maintainer, ob die Änderung nur Eingabeschemas oder auch andere generierte Schemas abdeckt. Als abgeschlossen gilt die Änderung, wenn automatische Eigenschaftstitel entfernt werden, explizite Field-Titel jedoch erhalten bleiben und die betroffenen Tests aktualisiert sind und erfolgreich durchlaufen.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- python
- Bereich
- api, backend
- Issue-Typ
- Feature
- Schwierigkeit
- 3/5
- Geschätzter Aufwand
- 1-2 Tage
- Aktivitätsstatus
- Aktiv
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 52/100