Skip to content

mcp-http: pin the outer-permit-held-for-full-request invariant (now conventional, not structural) #2241

Description

@jamie8johnson

Gap

The MCP-HTTP concurrency cap's "normal request holds the outer permit for its full duration" invariant is now conventional, not structural — and no test pins it.

Before the 3b-2 transport lane, the outermost permit (#2220, enforce_concurrency_cap) was held structurally: the middleware acquired it and held it across next.run(...). To let tasks/result swap onto the isolated blocking budget (RT-DOS-2), the permit now rides request extensions as an owned permit, and handle_post extracts and keeps it alive by convention — every method except tasks/result holds it for the whole request; tasks/result deliberately drops it before entering the poll loop.

Failure mode

A future refactor that drops outer_permit early in handle_post (or an extension type mismatch that makes the extraction silently return None) would pass the entire existing suite:

  • concurrency_cap_permit_released_after_response only proves release (it would still pass).
  • ..._503s_before_auth holds the permit externally (unaffected).
  • tasks_result_block_releases_outer_permit_rt_dos_2 proves the complement (release-during-block for tasks/result).

Result: silently unbounded concurrent daemon relays — the exact class #2218/#2220 closed.

Suggested shape

A test that drives a NORMAL (non-tasks/result) request through the real router with a size-1 semaphore and asserts the permit is unavailable mid-handling. Needs an injectable slow point in the normal relay path (the tasks/result loop got one — an injected poll fn; the normal path has no equivalent seam today), which is why this wasn't folded into the lane: the test requires a small production reshape, not just a test file.

Found by the pre-land review of the 3b-2 transport lane (part of #2216); current code verified correct by inspection.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions