Skip to content

Document MCP per-client rate limiting and the durable quota hook#571

Merged
kylebernhardy merged 3 commits into
mainfrom
docs/mcp-identity-quota-1610
Jul 8, 2026
Merged

Document MCP per-client rate limiting and the durable quota hook#571
kylebernhardy merged 3 commits into
mainfrom
docs/mcp-identity-quota-1610

Conversation

@kylebernhardy

Copy link
Copy Markdown
Member

Companion docs for HarperFast/harper#1633 (fixes HarperFast/harper#1610).

Changes to reference/mcp/configuration.md

  • Three new mcp.<profile>.rateLimit.* entries: perClientPerSecond, perClientBurst (with the one-token floor semantics), and identityHeader (with the proxy-must-strip warning).
  • New mcp.<profile>.quota.* section: the config keys, a complete counter-table example matching the reporter's use case, denial shape (quota_exceeded + retryAfterSeconds), and the fail-closed + runs-after-buckets semantics.

Note for review

Version references say "5.1.18+" assuming harper#1633 (stacked on harper#1613) ships in the patch after 5.1.17 — confirm at merge time. Hold merging until harper#1633 lands.

Generated by an LLM (Claude Fable 5).

…per#1633)

Companion to HarperFast/harper#1633 (fixes HarperFast/harper#1610):
rateLimit.perClientPerSecond/perClientBurst/identityHeader and the
mcp.<profile>.quota.* hook with the counter-table example.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds documentation for MCP per-client rate limiting and durable quota configurations, including an example of a custom quota hook implementation. The review feedback correctly identifies an issue in the example code where the quota counter is incremented and written to the database before checking the limit, which could lead to excessive database write I/O under spam; a code suggestion is provided to check the limit first.

Comment on lines +156 to +165
static async allowMcpCall({ identity, tool, user, profile, sessionId }) {
const id = identity ?? 'unknown';
const existing = await McpQuota.get(id);
const used = (existing?.used ?? 0) + 1;
await McpQuota.put({ id, used });
if (used > DAILY_LIMIT) {
return { allowed: false, message: 'daily quota reached', retryAfterSeconds: 3600 };
}
return true;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In the current implementation, the quota counter is incremented and written to the database (McpQuota.put) before checking if the limit has been exceeded. This means that once a client exceeds their daily quota, every subsequent blocked request will still trigger a database write. A malicious or misconfigured client spamming the endpoint could cause excessive database write I/O.

Additionally, checking the limit before incrementing prevents the counter from growing infinitely beyond the daily limit.

We should check the limit first, and only perform the database write if the quota is not yet exceeded.

Suggested change
static async allowMcpCall({ identity, tool, user, profile, sessionId }) {
const id = identity ?? 'unknown';
const existing = await McpQuota.get(id);
const used = (existing?.used ?? 0) + 1;
await McpQuota.put({ id, used });
if (used > DAILY_LIMIT) {
return { allowed: false, message: 'daily quota reached', retryAfterSeconds: 3600 };
}
return true;
}
static async allowMcpCall({ identity, tool, user, profile, sessionId }) {
const id = identity ?? 'unknown';
const existing = await McpQuota.get(id);
const used = existing?.used ?? 0;
if (used >= DAILY_LIMIT) {
return { allowed: false, message: 'daily quota reached', retryAfterSeconds: 3600 };
}
await McpQuota.put({ id, used: used + 1 });
return true;
}

@github-actions github-actions Bot temporarily deployed to pr-571 July 7, 2026 01:21 Inactive
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-571

This preview will update automatically when you push new commits.

@kylebernhardy kylebernhardy marked this pull request as ready for review July 7, 2026 02:15
@kylebernhardy kylebernhardy requested a review from a team as a code owner July 7, 2026 02:15
@kriszyp

kriszyp commented Jul 7, 2026

Copy link
Copy Markdown
Member

Reviewed via Claude review-queue (full review: documentation-571-27fb8cc.md). Well-written companion docs for harper#1633 — cross-checked every documented key/behavior against the implementation and they match, except one drift: perClientBurst's default is documented as "the perClientPerSecond value," but the code actually floors it at Math.max(1, perClientPerSecond). For a fractional perClientPerSecond (e.g. 0.1 for "6/minute" — a realistic setting for a cost-bearing public tool), the real default burst is 1, not 0.1. The PR description says this section documents "the one-token floor semantics," but the merged text doesn't mention a floor at all.

Suggested addition: "Floored at 1 whole token — a fractional perClientPerSecond (e.g. 0.1) still yields perClientBurst: 1 by default, since a bucket capped below one token could never admit a call."

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-571

This preview will update automatically when you push new commits.

@github-actions github-actions Bot temporarily deployed to pr-571 July 7, 2026 20:58 Inactive
@kriszyp

kriszyp commented Jul 7, 2026

Copy link
Copy Markdown
Member

Reviewed via Claude review-queue (re-review, full review: documentation-571-0ac01aa.md). The commit pushed since my last review only adds a race-safety caveat to the quota-hook section — good addition, accurate and well-placed — but it doesn't touch the perClientBurst finding from the prior pass. Still documented as defaulting to "the perClientPerSecond value" with no mention that the implementation floors it at Math.max(1, perClientPerSecond). Low real-world impact (0 already means disabled) but still an open accuracy gap from last round. Still gated on harper#1633 landing per your own PR note either way.

…ed to main)

kriszyp review: the floor semantics were claimed but not written; and
harper#1633 landed on main rather than v5.1, so the feature ships in
5.2.0, not 5.1.18.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kylebernhardy

Copy link
Copy Markdown
Member Author

Both addressed in b9c98ad: the perClientBurst default now documents the one-token floor with the fractional-rate example (apologies for claiming it was there in the PR description when it wasn't — fact-check miss), and version refs moved 5.1.18 → 5.2.0 since harper#1633 merged to main. harper#1633 has landed, so this is unblocked whenever you're ready. Comment generated by an LLM (Claude Fable 5).

@github-actions github-actions Bot temporarily deployed to pr-571 July 8, 2026 14:41 Inactive
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-571

This preview will update automatically when you push new commits.

@kylebernhardy kylebernhardy merged commit 87ae73b into main Jul 8, 2026
7 checks passed
@kylebernhardy kylebernhardy deleted the docs/mcp-identity-quota-1610 branch July 8, 2026 20:48
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

🧹 Preview Cleanup

The preview deployment for this PR has been removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP: rate limiting is per-session/in-memory — no durable, identity-scoped quota for unauthenticated public tools

3 participants