Conversation
…ayer #600 #601 Add in-process guards that run inside the MCP tool wrapper (not DIAL Core): - Per-caller rate limiting keyed by a tool cost class (cheap/moderate/ expensive), enforced before the LLM-backed guardrail and execution so an over-limit caller is rejected without spending that work. - A payload budget that keeps each tool result within the host's size limit. Cost classes are assigned per tool: data query and web/RAG tools are expensive, glossary lookups are cheap, and upstream metadata reads keep the moderate default. App-only tools are exempt from both guards, since their results are consumed by the application rather than loaded into an agent's context. Measure structured content as compact UTF-8 JSON so non-ASCII text in a multi-language deployment is not over-counted as escaped sequences.
kryachkow
requested review from
Fedir-Yatsenko and
navalnica
as code owners
September 14, 2026 14:48
CodeQL (py/weak-sensitive-data-hashing) flagged hashing the bearer/API token with plain SHA-256 as weak hashing of sensitive data. Switch to an HMAC keyed with a per-process random key: a keyed construction CodeQL accepts that also prevents brute-forcing a leaked digest back to the raw token. The key is per process because rate-limit buckets already live in process, so it never needs to outlive the process or match a replica.
…ol-rate-limits-and-payload-budgets # Conflicts: # statgpt/app/mcp/tools/base.py
CodeQL (py/weak-sensitive-data-hashing) still flagged the keyed HMAC-SHA256 as weak hashing of a credential: it rejects any fast crypto hash of a credential and accepts only a computationally expensive KDF. Putting a KDF here would be worse than the "risk" it flags, since caller_identity runs on every tool call ahead of the rate-limit check and would become a CPU-exhaustion vector. Derive the id with Python's builtin hash (a per-process-seeded SipHash) instead: cheap, non-reversible for a high-entropy token, never holds or logs the raw token, and not a crypto-API sink CodeQL flags. Drop the now-unused hashlib/hmac/secrets imports and _CALLER_ID_KEY.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Applicable issues
Description of changes
Marketplace guidance requires MCP tools that are expensive to serve or externally reachable to have rate limits, and requires tool results to stay within the host's payload caps. This adds both guards inside the StatGPT MCP tool wrapper (not DIAL Core), so they can key off the validated bearer token and skip app-only tools.
Per-caller rate limiting (#600)
(caller, cost class), giving both a burst allowance (capacity) and a sustained rate (refill), enforced before the LLM-backed guardrail and execution so an over-limit caller is rejected without spending that work.expensive, glossary lookups arecheap, and upstream metadata reads keep themoderatedefault.hash(a per-process-seeded SipHash): the raw secret is never used as a dict key or logged, and a high-entropy token cannot be recovered from the id. Unidentifiable callers share oneanonymousbucket. A cryptographic hash is avoided on purpose here — CodeQL flags any fast crypto hash of a credential as weak, and its only accepted alternative (a computationally expensive KDF) would itself be a CPU-exhaustion vector, since the id is derived on every call ahead of the rate-limit check.ToolErrortelling the model how long to wait, rather than a bare 429.Payload budget (#601)
structuredContentplus a note; if it still does not fit, it returns an actionable error asking the caller to narrow the query.\uXXXXsequences.Both guards are configurable via
MCP_*env vars (enable flags, window, per-class allowances, max chars), documented in the app README, and exempt app-only tools, whose results are consumed by the application rather than loaded into an agent's context. Covered by unit tests for the limiter, the budget, per-tool cost classes, and the wrapper guards.Checklist
ReviewenvironmentBy submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.