No per-agent identity: the initialize limit is a fleet limit and raising the burst only moves the cliff #21
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#21
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?
Filed at Clark's request so the next person raising
MAX_INITIALIZES_PER_IDENTITYknows why it keeps needing raising.
Every session mounting this server authenticates as one Logto subject,
julian@kampong.social. Measured 2026-08-28: six distinct bearer hashes intwelve hours, one
sub.InitializeLimiterkeys on that subject, so there isexactly one bucket for the entire fleet however many agents are running and
however many distinct tokens they hold.
v0.1.5raised the burst from 8 to 32 and that is correct for today's fleetsize. It moves the cliff; it does not make the limit per-agent. Eight agents
today, sixteen tomorrow, and the number needs raising again with no principle
saying where it stops.
This is an identity problem, not a rate-limiting one. A per-agent limit
needs a per-agent identity, and there is none to key on: the bearer hash looks
like one and is not, because a single agent's reconnect rotates it while the
subject stays fixed, so a bearer-keyed limit is both too loose (a reconnecting
agent gets a fresh bucket) and useless as an aggregate control.
Not started, and it should not be started to make a number tidier. It becomes
worth solving if either happens:
one bucket for all of them stops being merely inelegant.
Options if it is ever taken, none evaluated:
client_info.nameandversionare in theinitializeparams (claude-code 2.1.248today), butthey are client-supplied and identical across the fleet, so they identify a
product rather than an agent.
fleet authenticates rather than to this server.
session::MAX_SESSIONS,which the code already calls the real flood defence.
Measured on
v0.1.5, and it closes the door this issue left openThe
v0.1.5acceptance window, three MCP connections from three differentagent sessions in four minutes:
One bearer, not merely one subject. Every request from all three sessions
carried the same
token_hash.v0.1.4saw six distinct hashes over twelvehours, which is the same credential rotating over time rather than several
credentials coexisting.
That replaces the argument in the issue body with a stronger one. It is not that
several bearers happen to map to one Logto subject: right now there is one
credential. So
key it per bearer instead, which is the obvious alternativeand the one a reader would reach for first, is measured not to work — a
per-bearer bucket separates nothing today either.
The fleet is three mounts, not eight
Established from the configs rather than assumed.
lucy,mantisandpennyhold
carddav;alan,clark,nexo,vryanandhonokado not, and eachconfirmed independently from inside its own session. The eight in
v0.1.5'ssizing came from an unvalidated roster, so
MAX_INITIALIZES_PER_IDENTITY = 32is oversized by more than 2x in the safe direction and the number is no longer
the thing under test.
The identity problem is unchanged by that. Three mounts today, one bucket for
however many exist tomorrow.
A withdrawn mount outlives the refusal, and a restart is the only remedy
Measured rather than inferred.
lucy's client tried to connect at session startagainst
v0.1.4, was refused, withdrew the tools, and never retried:ToolSearchreturned nothing plus a cached 429 string from that originalfailure — a 429 quoting an image that had already been replaced.
Clark restarted her session at 02:12:1x; her first MCP connect appears in this
server's log at 02:12:20.893, within a second, and
whoamiandlist_address_booksboth then succeeded with real data.So: the fix stops new refusals and returns nothing already lost. Every
session that was up during the livelock needs restarting before it has carddav
again, waiting does nothing, and nothing in the cluster identifies which
sessions are in that state — a session whose mount was withdrawn is
indistinguishable from one that never had it.