Skip to content

Device sweep: resolve Claude connector UUIDs#220

Merged
zeus-12 merged 2 commits into
stagingfrom
vv/mcp-connector-sweep
Jun 29, 2026
Merged

Device sweep: resolve Claude connector UUIDs#220
zeus-12 merged 2 commits into
stagingfrom
vv/mcp-connector-sweep

Conversation

@zeus-12

@zeus-12 zeus-12 commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

What

Device-side sweep that resolves bare Claude connector UUIDs to their real names so the control plane can group/policy them. Companion backend PR: ai-gateway-data #2340.

OAuth remote connectors are named by a per-registration UUID at runtime; the real display name only lives in the local Claude session files on the device, so the backend can't resolve it alone.

How (sweep_connectors.py, wired into ai_tools_discovery.main)

  1. GET /api/v1/ai-tools/unresolved-connector-uuids/ — the worklist of UUIDs the backend still needs. Empty → skip.
  2. Read the local session files in both folders (claude-code-sessions = Claude Code, local-agent-mode-sessions = CoWork) → remoteMcpServersConfig{uuid, name, tools}, newest-file-first, name-consistent tool union.
  3. For each requested UUID we can resolve locally, POST the real name + tools + originating connector_uuid to /api/v1/ai-tools/mcp-server-scan/.

Runs at the end of every discovery (run_sweep) so it self-heals on the tool's existing periodic cadence. Best-effort — never affects the discovery outcome. Only UUIDs the backend asked for leave the device; HTTP via curl (Zscaler constraint, no urllib).

Notes / follow-ups

  • Early-exit (stop scanning files once all requested UUIDs are found) is not in this PR yet.
  • Verified end-to-end locally against the backend branch: orphan UUID row → resolved into the claude-connector:<name> keeper with tools, worklist entry cleared.

🤖 Generated with Claude Code


Note

Medium Risk
New outbound posts carry MCP connector names and tool metadata (worklist-scoped), and local reads use the running user's Claude app-support dir only, which may miss connectors under other users on multi-user/root scans.

Overview
Adds a device-side connector UUID sweep so the control plane can turn orphan claude-connector rows (UUID-only names) into real display names and tool lists that only exist in local Claude session files.

New sweep_connectors.py implements run_sweep: GET /api/v1/ai-tools/unresolved-connector-uuids/, parse remoteMcpServersConfig from claude-code-sessions and local-agent-mode-sessions local_*.json (newest-first, same-name tool union), then POST each backend-requested match to /api/v1/ai-tools/mcp-server-scan/ with connector_uuid, claude-connector scope, and tools. HTTP uses curl + stdin config (same pattern as other discovery scripts). Runnable standalone via CLI.

ai_tools_discovery imports run_sweep and invokes it after the scan completed event inside a try/except so failures are logged only and do not change discovery exit status.

Reviewed by Cursor Bugbot for commit c728c8d. Bugbot is set up for automated code reviews on this repo. Configure here.

Greptile Summary

This PR adds a device-side sweep (sweep_connectors.py) that resolves bare Claude connector UUIDs to real display names by reading local Claude session files and reporting matches back to the control plane. It is wired into the existing discovery run as a best-effort post-scan step.

  • sweep_connectors.py fetches an unresolved-UUID worklist from the backend, reads remoteMcpServersConfig from both claude-code-sessions and local-agent-mode-sessions (newest-file-first), then POSTs each matched UUID's real name and tools to the single-server scan endpoint one at a time via curl.
  • ai_tools_discovery.py imports and calls run_sweep at the tail of main(), wrapping it in a broad try/except so failures can't disrupt the discovery outcome.

Confidence Score: 3/5

The sweep is isolated behind a try/except and cannot crash the main discovery run, but it ships with no metrics instrumentation and sweep failures are logged at debug level making them invisible in production.

The core logic for reading session files and posting resolutions looks correct and the isolation from the main discovery flow is handled properly. The main gap is that the new flow has zero Prometheus metrics — no counters for resolved/failed items, no latency histograms for either HTTP call — which means any regression in resolution rate or backend latency is undetectable until a user-visible symptom appears.

sweep_connectors.py needs the most attention: it is the entire new flow and is missing all metrics instrumentation. The logging style (print to stderr) also needs updating to integrate cleanly with the discovery runner's structured logger.

Important Files Changed

Filename Overview
scripts/coding_discovery_tools/sweep_connectors.py New module implementing the Claude connector UUID sweep: reads local session files, fetches the backend worklist, and POSTs resolutions one-by-one via curl. Missing Prometheus metrics on all HTTP paths; uses print() to stderr instead of the structured logger; one curl subprocess per UUID rather than batching.
scripts/coding_discovery_tools/ai_tools_discovery.py Wires run_sweep into the end of main(); sweep exceptions are caught and logged at debug level rather than warning, making failures invisible in production without debug logging enabled.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant D as Discovery (main)
    participant S as sweep_connectors
    participant BE as Control Plane
    participant FS as Local Session Files

    D->>S: run_sweep(domain, api_key)
    S->>BE: GET /api/v1/ai-tools/unresolved-connector-uuids/
    BE-->>S: "{uuids: [...]}"
    alt nothing to resolve
        S-->>D: (0, 0, 0)
    else UUIDs needed
        S->>FS: "glob **/local_*.json (claude-code-sessions + local-agent-mode-sessions)"
        FS-->>S: session JSON files (sorted newest-first)
        S->>S: "parse remoteMcpServersConfig → {uuid: {name, tools}}"
        loop for each matched UUID
            S->>BE: "POST /api/v1/ai-tools/mcp-server-scan/ {mcp_server, connector_uuid}"
            BE-->>S: 2xx / error
        end
        S-->>D: (sent, failed, matched)
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant D as Discovery (main)
    participant S as sweep_connectors
    participant BE as Control Plane
    participant FS as Local Session Files

    D->>S: run_sweep(domain, api_key)
    S->>BE: GET /api/v1/ai-tools/unresolved-connector-uuids/
    BE-->>S: "{uuids: [...]}"
    alt nothing to resolve
        S-->>D: (0, 0, 0)
    else UUIDs needed
        S->>FS: "glob **/local_*.json (claude-code-sessions + local-agent-mode-sessions)"
        FS-->>S: session JSON files (sorted newest-first)
        S->>S: "parse remoteMcpServersConfig → {uuid: {name, tools}}"
        loop for each matched UUID
            S->>BE: "POST /api/v1/ai-tools/mcp-server-scan/ {mcp_server, connector_uuid}"
            BE-->>S: 2xx / error
        end
        S-->>D: (sent, failed, matched)
    end
Loading

Reviews (1): Last reviewed commit: "Run the connector sweep as part of disco..." | Re-trigger Greptile

Greptile also left 4 inline comments on this PR.

zeus-12 added 2 commits June 30, 2026 00:08
Fetch the backend's unresolved-UUID worklist, match each against the local Claude
session files (Claude Code + CoWork folders), and report the resolved name + tools
back via the single-server scan endpoint with the originating UUID. Only UUIDs the
backend asked for are sent; HTTP via curl per the Zscaler constraint.
Call run_sweep at the end of the discovery run so connector UUIDs self-heal on the
tool's existing periodic cadence. Best-effort — never affects the discovery outcome.
@zeus-12 zeus-12 requested a review from a team June 29, 2026 18:39

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c728c8d. Configure here.

Comment thread scripts/coding_discovery_tools/sweep_connectors.py

@vigneshsubbiah16 vigneshsubbiah16 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.

🛡️ Automated Security Review (consensus)

1 finding — 0 high-confidence, 1 to triage. Reviewers: Cursor, Claude, Semgrep, Gitleaks.

🟡 TRIAGE

API key not escaped for newlines in curl --config

  • scripts/coding_discovery_tools/sweep_connectors.py:139 (_auth_header / _curl_config_quote)
  • Impact: A newline or other control character in the device API key could break out of the double-quoted Authorization line in the stdin curl config and inject extra curl directives.
  • Fix: Reject/strip control characters (especially \n/\r) from api_key before embedding, or pass the token via -H @- / an env-based form instead of string interpolation.
  • Reviewers: Claude

Previously acknowledged (not re-flagged)

  • Outbound connector names and tool metadata to the control plane — accepted by design (PR scope: worklist-scoped resolution of backend-requested UUIDs only).

🤖 consensus review · reviewers: Cursor,Claude,Semgrep,Gitleaks · head c728c8db · 2026-06-29T18:42Z

Comment thread scripts/coding_discovery_tools/sweep_connectors.py
Comment thread scripts/coding_discovery_tools/ai_tools_discovery.py
Comment thread scripts/coding_discovery_tools/sweep_connectors.py
Comment thread scripts/coding_discovery_tools/sweep_connectors.py
@zeus-12 zeus-12 merged commit 99e8c54 into staging Jun 29, 2026
9 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.

3 participants