gate: cap startup/tool-schema payload including plugin disclosures #71
Labels
No labels
code-review
correctness
dos
performance
security
severity/high
severity/low
severity/medium
tech-debt
Kind/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
Reference
h-dv/code-index#71
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
I040 measured the fixed startup tax for the first time and cut where it was safe. Nothing stops it growing back.
Measured 2026-08-18 (real
initialize+tools/listoff the wire)tools/listinstructions77% of that payload is English prose, not structure — 26,374 bytes of tool descriptions plus 9,370 bytes of per-parameter prose inside
inputSchema.Prior art for the ratchet
Copy has grown three times deliberately (
175613a0,25cd1698,21c8ae66) and was pinned in place by regression tests asserting the marketing anchors. I040 retargeted those tests and addedINSTRUCTIONS_MAX_BYTES = 4096for the instructions string only.tools/list— the 90% — is still unbounded.Ask
A test that drives a real
initialize+tools/listand asserts total bytes under a ceiling, failing with a diff of the per-tool ranking so the offender is named. Set the ceiling at roughly the current value; it is a ratchet, not a target.Second lever, untouched
9,370 bytes (20% of the payload) is per-parameter
descriptionprose insideinputSchema—search_textalone carries 1,407 B,change_impact819 B,file_outline788 B. Independent of the description pass; plausibly another ~2,000 B.The rule this enforces
From I040: prose in a tool description is not a disclosure. If an agent needs it at call time it goes in the RESPONSE, where it ships with the data. A disclosure attached to the number beats one in a schema the agent read 200k tokens ago — and is cheaper, because it is only paid when the situation arises.
code-index://docs/{topic}exists now as the destination for anything that is reference rather than contract.Runtime-plugin architecture expansion
#75 adds packages, generations, capabilities, bridges and reason-code families. None of that reference material belongs duplicated across every tool description or parameter schema.
Extend the ratchet to report bytes by category:
Plugin state travels in responses only when relevant, preferably as one package dictionary plus compact row handles. Full capability, ABI and reason-code documentation lives under code-index://docs/plugins/*.
The real initialize + tools/list gate must run with the complete #80 surface enabled and fail with a per-tool/per-category size diff. Adding runtime plugins may not raise the fixed session tax without an explicitly reviewed baseline reason.
gate: startup payload budget — cap initialize + tools/list bytes in CIto gate: cap startup/tool-schema payload including plugin disclosuresClosing: this shipped in v0.23.0. Verified first-hand.
crates/mcp-server/tests/startup_payload_budget_e2e.rs, landed by3a83a50("#71/#80 S20"),git tag --contains→ v0.23.0.It spawns the real binary, speaks the real protocol, and measures
recv_line()— the bytes the client's socket actually saw, explicitly not a re-serialised constant, which is the difference between measuring the payload and measuring your own belief about it.It is a two-sided bound, which is the part worth quoting, because a ceiling alone would have been decorative here:
That is exactly the "which direction does the likely bug push this number?" discipline, applied by the test's own author. Failure output names the three largest tool entries split into
desc + schema, so a breach is actionable rather than a number. Four mutations were executed and two honest survivors are recorded rather than hidden.The other half of this issue is also closed:
no_tool_description_restates_a_docs_resource(:379), plusINSTRUCTIONS_MAX_BYTES = 4096atcrates/mcp-server/src/server.rs:16568.One sub-ask genuinely unbuilt, split out
This issue asks the ratchet to report bytes by category — instructions / schema structure / tool prose / plugin-specific prose / resource references. Three of the five exist. Filed separately.
For whoever picks that up: the ceiling has been raised once, 15,300 → 16,555 for #89, with an itemised bill, and the payload has grown from this issue's measured 46,444 B to 55,081 B. The test's own doc is unambiguous that a raise is "a bill sent to every client on every session" and that the correct response to a breach is to trim — the category split exists precisely to make that trim targetable.
Why this close matters
#80 quotes this issue as live grounds — "#71 does not cap the enlarged startup/schema payload" — and it does cap it, with a floor, on the real wire. Same correction as #65, closed alongside this one.