Skip to content

fix(scanner): inspect only the scanned server's tools, keep peers as index context - #1812

Merged
Dumbris merged 1 commit into
mainfrom
claude/mcpproxy-high-cpu-idle-5c313c
Nov 1, 2026
Merged

Dumbris merged 1 commit into
mainfrom
claude/mcpproxy-high-cpu-idle-5c313c

Conversation

@Dumbris

@Dumbris Dumbris commented Nov 1, 2026

Copy link
Copy Markdown
Member

Summary

Closes #1724 (core at >100% CPU while idle, battery drain).

Root cause. The per-tool change-gate scan (Runtime.scanToolEvidence → scanner.ScanToolMetadataVerdict) feeds every other connected server's tools to the detect engine as cross-server context (needed by the shadowing/impersonation check), but Engine.Scan then ran every check — phrase and bundle regex detection included — over the whole fleet for each held tool, and threw the peer findings away afterwards. Every 5-minute discovery pass re-evaluates every still-held (changed/pending) tool, so the cost is held tools × fleet size × all checks per pass. The reporting install has 471 tools on 11 servers with 108 held changes: ~11 minutes at 100% CPU, then a 5-minute gap, forever.

Fix. detect.NewScopedRegistryView(targets, peers): only the scanned server's tools go into the scan set (Tools); peers are indexed into ToolsByName/ToolNames, which is the only way any check (Shadowing) reads them. Peers are no longer normalized or inspected. Target findings are identical to a full view's — the cross-server rug-pull tests still fire. Both scanner entry points (ScanToolMetadataVerdict and detectEngineFindings) use it.

Measured. BenchmarkScanToolMetadataVerdict_PerToolWithPeers (11 servers, 43 tools each, one held tool per op) on an M4 Pro:

ns/op allocs/op
before 3,065,462,617 (3.07 s) 2,339,383
after 5,416,844 (5.4 ms) 6,682

Peer collection (collectPeerToolMetadata, ~1.5 ms for 470 schemas) was measured and left as is: a pass with 108 held tools now spends well under a second every 5 minutes.

Test plan

  • TestNewScopedRegistryView_InspectsTargetsOnly / _TargetFindingsMatchFullView (new, fail without the fix)
  • go test ./internal/security/detect/... ./internal/security/scanner/...
  • go test -race ./internal/security/detect/...
  • go test ./internal/runtime/ -run 'Scan|Quarantine|Approval|Baseline|Peer|Shadow'
  • golangci-lint run --config .github/.golangci.yml ./internal/security/... — 0 issues

🤖 Generated with Claude Code

…index context (#1724)

The per-tool change-gate scan (trust_mode: scan approval and the manual-mode
hold evidence) fed every other connected server's tools to the detect engine
as cross-server context, and Engine.Scan then ran every check — the phrase
and bundle regex detection included — over the whole fleet for each held
tool, discarding the peer findings afterwards. Every discovery pass rescans
every still-held tool, so an install with a few hundred tools and a few
dozen held changes burned tools x fleet every 5 minutes: 471 tools, 108 held,
~11 minutes at 100% CPU per pass on the reporting machine.

detect.NewScopedRegistryView(targets, peers) puts only the targets in the
scan set and indexes peers into ToolsByName/ToolNames, which is the only way
a check (Shadowing) ever reads them. Target findings are identical to a full
view's; peers are no longer normalized or inspected. Both scanner entry
points (ScanToolMetadataVerdict, detectEngineFindings) use it. One held-tool
scan against a 470-tool fleet: ~3 s -> ~5 ms
(BenchmarkScanToolMetadataVerdict_PerToolWithPeers).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 498fcf2
Status: ✅  Deploy successful!
Preview URL: https://a69e59cc.mcpproxy-docs.pages.dev
Branch Preview URL: https://claude-mcpproxy-high-cpu-idl.mcpproxy-docs.pages.dev

View logs

@Dumbris
Dumbris enabled auto-merge (squash) November 1, 2026 11:23
@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

📦 Build Artifacts

Workflow Run: View Run
Branch: claude/mcpproxy-high-cpu-idle-5c313c

Available Artifacts

  • archive-darwin-amd64 (32 MB)
  • archive-darwin-arm64 (29 MB)
  • archive-linux-amd64 (20 MB)
  • archive-linux-arm64 (18 MB)
  • archive-windows-amd64 (32 MB)
  • archive-windows-arm64 (28 MB)
  • frontend-dist-pr (0 MB)
  • installer-dmg-darwin-amd64 (28 MB)
  • installer-dmg-darwin-arm64 (25 MB)
  • smart-mcp-proxymcpproxy-go89QQZU.dockerbuild (0 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page linked above
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 41301136638 --repo smart-mcp-proxy/mcpproxy-go

Note: Artifacts expire in 14 days.

@Dumbris
Dumbris merged commit 62401d5 into main Nov 1, 2026
55 of 56 checks passed
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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.

[bug] Hi, I noticed today that mcp proxy is using very high CPU (>100%) even when idl

2 participants