Skip to content

Tool input schemas carry a pydantic-derived title on every property #3391

Open

Description

@wromansky

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:

  1. Default or opt-in. Changing the default updates 12 test expectations in this repo (mostly snapshot(...) in tests/docs_src/), so it's visible. An opt-in flag on MCPServer(...) avoids that but adds public API.
  2. 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

Activity

  1. added
    v2Affects the v2 line (2.x on main)
    v1Affects the v1.x maintenance line
    on Aug 25, 2026
  2. Ben-Home commented on Aug 25, 2026

    @Ben-Home
  3. ktz03 commented on Sep 8, 2026

    @ktz03

    Taking this — will stop emitting pydantic auto-derived property \ itle\ fields on tool input schemas (or strip them after schema generation) so tools/list stops paying ~20% context for restated field names.

  4. ktz03 commented on Sep 8, 2026

    @ktz03

    PR up: will keep scope to input schemas only (default change) and preserve explicit \Field(title=...). Happy to expand to output schemas if maintainers prefer.

  5. mkanetsuna commented on Sep 8, 2026

    @mkanetsuna

    I think changing the default behavior could have a fairly broad impact, so what about making this configurable instead?

    For example:

    MCPServer(
        ...,
        include_generated_titles=False,
    )

    This would allow the current behavior to remain the default, while still giving users like us the option to disable the generated titles when we don't want them.

  6. ktz03 commented on Sep 8, 2026

    @ktz03

    Happy to take this — I already opened #3475 with a ToolInputJsonSchema that sets field_title_should_be_set to False (keeps explicit Field(title=...)), plus the snapshot updates for the docs/client/server tests that asserted the old auto titles.

    CI on the first push failed only on those expected snapshot mismatches; the follow-up commit on fix/omit-auto-tool-input-titles (90ace4f3) strips them. Could a maintainer assign me (@ktz03) to this issue (or add help wanted) so the intake gate can reopen #3475?

  7. mkanetsuna commented on Sep 8, 2026

    @mkanetsuna

    Just to make sure I understand correctly, this would effectively make the generated titles always disabled, right?

    I think it might be safer to make this configurable so users can choose whether to keep or omit the generated titles, rather than changing the behavior unconditionally.

    Also, I’m only a user of this repository, so I’m not able to assign issues or add the label.

  8. added
    enhancementRequest for a new feature that's not currently supported
    on Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementRequest for a new feature that's not currently supportedv1Affects the v1.x maintenance linev2Affects the v2 line (2.x on main)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions