One client connection costs two initialize charges #22
Labels
No labels
waiting-on-julian
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jlxq0/carddav-mcp#22
Loading…
Add table
Add a link
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?
claude-code 2.1.248posts twice to/mcpwithout anmcp-session-id, about30 ms apart. Both are authenticated, both pass
is_fresh_mcp_session_request,both are charged by
InitializeLimiter, and both cause rmcp to create asession. Only the second reaches
Service initialized as server.Measured on the
v0.1.4pod over twelve hours: 16 charged creates produced 5usable sessions, six of them orphans that were charged and produced nothing at
all.
So any capacity stated in connections is half the number in the constant,
which is why
v0.1.5sizes the burst at 32 for eight agents rather than 8.Charging only the session that survives would double effective capacity
without touching the limit, which is the fix Alan asked for and I did not
ship. The reason it is an issue rather than a commit: the charge sits in a tower
middleware and the surviving session is established inside rmcp, so moving it to
on_initializedwould leave the "half-open but un-handshaken" state ungoverned— which is the exact thing
session.rsdocuments Mitigation A as existing toprevent. Doing that at 02:00 with the fleet locked out was not a trade worth
making.
What is unestablished and would decide the design: why the client posts
twice. Two authenticated POSTs 30 ms apart with different session ids could be
protocol-version negotiation, a probe, or an SSE stream open. Nothing in this
server's log distinguishes them, because the middleware does not record what the
body was. That measurement comes first.
Candidate approaches, none evaluated:
methodof a fresh POST so the two are distinguishable, thencharge only
initialize.N then covers up to N connections rather than N/2.
ratio written down — which is what
v0.1.5does.Confirmed on
v0.1.5, and cleanlyThe acceptance window, three connections from three agent sessions:
Exactly 2:1, every create paired, no orphans at all — against 16 creates for
5 sessions with 6 orphans on
v0.1.4. Whatever the orphans were on the old pod,they are not an inevitable part of the two-POST pattern.
And what is not charged, since it was misread once during acceptance
A tool call inside an established session carries
mcp-session-id, sois_fresh_mcp_session_requestis false andInitializeLimiternever sees it.The window makes this directly visible: 23 authenticated requests produced 6
charged creates, and the other 17 carried a session id and went to the
read/write tool buckets instead.
So a second tool call in the same session does not test this limiter, and a
per-session call count says nothing about initialize capacity. Only a fresh POST
without a session id is charged, and there are two of those per connection.