Skip to content

fix(scanner): resolve uvx source from ephemeral archive cache (MCP-2400)#664

Merged
Dumbris merged 1 commit into
mainfrom
mcp-2400-uvx-archive-cache
Jun 14, 2026
Merged

fix(scanner): resolve uvx source from ephemeral archive cache (MCP-2400)#664
Dumbris merged 1 commit into
mainfrom
mcp-2400-uvx-archive-cache

Conversation

@Dumbris

@Dumbris Dumbris commented Jun 14, 2026

Copy link
Copy Markdown
Member

Summary

Fixes MCP-2400: uvx-launched (PIP) MCP servers always fell back to
tool_definitions_only (0 source files scanned) because the host source
resolver never looked in the right cache.

resolveUvxCache only checked:

  1. ~/.cache/uv/git-v0/checkouts/… (git+URL packages), and
  2. ~/.local/share/uv/tools/<pkg> (persistent uv tool install).

But the common case — a plain uvx <pkg> server — unpacks its published
wheel into the content-addressed ~/.cache/uv/archive-v0/<hash>/ cache,
keyed by an opaque hash, not by package name. So even a server that had
been run locally missed both strategies and degraded to a definitions-only scan.

Fix

Add a third local-cache strategy to resolveUvxCache that:

  • scans every archive-v0/<hash> entry and matches the target distribution by
    its wheel .dist-info directory (robust to dist-name vs import-name
    differences, e.g. python-dotenvdotenv);
  • supports both the flat (<hash>/<dist>-<ver>.dist-info) and venv-style
    (<hash>/lib/python*/site-packages/…) layouts observed in real uv caches;
  • picks the newest entry when several versions are cached (consistent with
    resolveNpxCache);
  • strips PEP 508 version specifiers (==, >=, [extras], …) before matching.

The container resolver (findContainerTargetDir) already searched archive-v0;
this brings the host resolver to parity.

Relationship to #658 (MCP-2206)

This is the residual local-cache-resolve gap MCP-2400 was scoped down to.
PR #658 adds a published-source network fetch as the final fallback; this PR
makes the local cache path succeed first — avoiding a redundant network
round-trip and working in air-gapped deployments where the fetch is disabled.
The two are logically independent (#658 touches Resolve/ResolveFullSource
and a new package_fetch.go; this touches only resolveUvxCache), so they
compose cleanly regardless of merge order.

Tests (TDD)

internal/security/scanner/source_resolver_test.go — 5 new tests (all
offline/deterministic): flat layout, venv-style layout, name normalization +
version pin, newest-entry-wins, and clean fall-through on no match.

Verification

  • go test ./internal/security/scanner/ -race
  • go build ./cmd/mcpproxy
  • golangci-lint v2 (CI config) ✅ 0 issues

Docs

docs/features/security-scanner-plugins.md — note that uvx resolution now
covers the ephemeral archive-v0 cache.

Related #658
Related MCP-2400

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 14, 2026

Copy link
Copy Markdown

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1e26701
Status: ✅  Deploy successful!
Preview URL: https://a26cecf5.mcpproxy-docs.pages.dev
Branch Preview URL: https://mcp-2400-uvx-archive-cache.mcpproxy-docs.pages.dev

View logs

@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

❌ Patch coverage is 79.45205% with 15 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/security/scanner/source_resolver.go 79.45% 7 Missing and 8 partials ⚠️

📢 Thoughts on this report? Let us know!

resolveUvxCache only checked the persistent `uv tool install` tools dir and
git checkouts, so a server launched via plain `uvx <pkg>` — whose wheel is
unpacked into the content-addressed ~/.cache/uv/archive-v0 cache, keyed by an
opaque hash rather than package name — always missed and fell through to a
tool-definitions-only scan.

Add a third local-cache strategy that scans archive-v0 entries and matches the
target distribution by its wheel .dist-info (robust to dist-name vs import-name
differences), supporting both the flat and venv-style layouts and picking the
newest entry when several versions are cached. Also strip PEP 508 version
specifiers (==, >=, [extras]) from the spec before matching.

The container resolver (findContainerTargetDir) already searched archive-v0;
this brings the host resolver to parity. Complements the published-source fetch
in #658 (MCP-2206) by resolving locally first, avoiding a network round-trip and
working in air-gapped deployments.

Related #658
Related MCP-2400
@Dumbris Dumbris force-pushed the mcp-2400-uvx-archive-cache branch from 1f1feca to 1e26701 Compare June 14, 2026 14:32

@mcpproxy-gatekeeper mcpproxy-gatekeeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approved via Claude Code review (Codex out): uvx ephemeral-cache source resolve (MCP-2400). Reviewer verified fix + tests + CI green; VERDICT ACCEPT.

@Dumbris Dumbris enabled auto-merge (squash) June 14, 2026 14:56
@Dumbris Dumbris merged commit be485ad into main Jun 14, 2026
45 checks passed
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.

2 participants