Release v1.15.2 — abuse query-pattern blocklist + query_log IP/UA attribution#113
Merged
Conversation
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.
Summary
Two related changes, shipped together as v1.15.2:
Abuse query-pattern blocklist (
src/mcp/abuse-blocklist.ts) — short-circuits searches for off-topic terms identified from production analytics (Toy Story 5 / Disclosure Day / Obsession 2026 / Scary Movie / box-office / SCOTUS Kalshi / CFTC certiorari / sports event contracts). Matched queries return a structured{ results: [], blocked: true, domain: ..., hint: ... }response — teaches the calling LLM what's actually in scope. Zero false-positives on legitimate documentation queries (negative tests insrc/__tests__/abuse-blocklist.test.tscover near-miss phrasings likeuseCopilotAction box for the office layout). Wired into bothregisterSearchToolandregisterKnowledgeTool(search-mode only on knowledge; browse mode has no user query).query_logattribution columns — addedclient_ip,user_agent,blocked,block_reason. Per-request IP/UA captured at MCP session init via the same trust-proxy boundary asoauthClientIp, then closed over for the lifetime of the session so every tool call records identical attribution — no more session-id-prefix joins against PostHog for IP attribution. Schema additions are nullable / defaulted (blocked DEFAULT FALSE); backward compatible.Context
A recent analytics investigation traced a high-volume off-topic empty-query cluster to Anthropic's
Claude-Useregress pool (160.79.106.32/29) — a shared Anthropic infrastructure pool that ALSO serves legitimate Claude-User fetches to this server (~46k legit sessions/7d). IP-level block would punish ~99.9% legit users. Pattern-based block is the surgical alternative. Long-term defense (scope classifier with adaptive per-session/per-IP reputation) is still on the roadmap.Observability
A new
oauthLog.searchBlocked({ ip, reason, tool })helper emits[oauth] search_blocked reason=pattern:<name> ip=<ip> tool=<tool>on every block, parallel to the existing[oauth] bearer_failuresurface. Greppable for abuse volume independent of the per-rowquery_log.blockedflag.Test plan
Toy Story 5 box office) onmcp.copilotkit.ai→ expectblocked: trueresponse +[oauth] search_blockedlog lineuseCopilotAction onClick handler) → normal resultsSELECT client_ip, user_agent, blocked, block_reason FROM query_log ORDER BY created_at DESC LIMIT 10;— confirm new columns populated