Skip to content

AX-1694 — Align VS Code copilot-instructions with Claude/Cursor agent-guard docs#21

Open
MatanEden1 wants to merge 9 commits into
mainfrom
AX-1694-vscode-plugin-alignment
Open

AX-1694 — Align VS Code copilot-instructions with Claude/Cursor agent-guard docs#21
MatanEden1 wants to merge 9 commits into
mainfrom
AX-1694-vscode-plugin-alignment

Conversation

@MatanEden1

@MatanEden1 MatanEden1 commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Jira Ticket Path: https://jfrog-int.atlassian.net/browse/AX-1694

The VS Code copilot-instructions.md template had drifted from the updated Claude and Cursor agent-guard instructions — it was missing the newer structure (Pre-flight rules, catalog-first flow, managed-settings enforcement) while the other two plugins moved ahead. This aligns the VS Code template with the same structure and rules, while preserving the VS Code-native mechanics that intentionally differ from Claude/Cursor.

Changes

  • Restructure to match the Claude/Cursor layout: Pre-flight section (live-execution / no-local-resolution rule, mandatory <PROJECT>, auto-resolvable <SERVER_ID>, sandbox/network note), catalog-first "Adding an MCP" flow, and numbered Steps 1–5 with explicit start+verify (4a) and OAuth login (5).
  • Keep the VS Code secrets model: top-level inputs + ${input:...} substitution + OS-keychain prompt-on-first-start (not shell env-var export).
  • Add a Managed Settings section: block non-agent-guard installs and block removal of MCPs protected by managed settings.
  • Add a routing table for listing (available vs installed), explicit project re-sync on switch/update, orphaned-input cleanup on removal, and expanded Key Rules / Troubleshooting.
  • Restore the type: "http" qualifier on the Step 5 OAuth condition to match Claude/Cursor.

Tests
Matan ran manual tests, and the results look good.

🤖 Generated with Claude Code

MatanEden1 and others added 4 commits June 15, 2026 15:30
…-guard docs

Bring the VS Code MCP management instructions up to the structure of the
updated Claude and Cursor agent-guard docs, while keeping VS Code-native
mechanics:

- Add Pre-flight section (live-execution/no-local-resolution rule,
  mandatory <PROJECT>, auto-resolvable <SERVER_ID>, network/sandbox note)
- Catalog-first "Adding an MCP" flow; numbered Steps 1-5 with explicit
  start+verify (4a) and OAuth login (5)
- Keep VS Code secrets model: top-level `inputs` + `${input:id}` +
  keychain prompt-on-first-start (NOT env-var export)
- Routing table for Listing MCPs; available vs installed
- New Managed Settings section: block non-agent-guard installs and
  removal of protected MCPs
- Explicit project re-sync on update/switch; orphaned-input cleanup on
  removal; expanded Key Rules and Troubleshooting

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ror project-switch priority into Pre-flight

- "live execution" exemption now says "local config files" (covers both
  workspace .vscode/mcp.json and the user-level MCP config) instead of
  naming only the workspace file
- mirror the explicit project-switch priority into the Pre-flight
  <PROJECT> bullet so it also governs listing/inspecting, not just writes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Regression check vs the Claude/Cursor sources found the only dropped
canonical detail: both gate --login on a remote section *with
type:"http"*. VS Code had generalized it to "a remote section", which
could fire --login for non-http remotes. Restore the qualifier.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@YoniMelki YoniMelki left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review: requesting changes

Reviewed against the canonical Claude (claude-plugin/templates/jfrog-mcp-management.md) and Cursor (cursor-plugin/plugins/jfrog/templates/jfrog-mcp-management.md) templates, since the goal of this PR is cross-plugin alignment.

The alignment work itself is solid — structure, command blocks, Pre-flight resolution chains, and Key Rules all track the other two templates, and the VS Code-native mechanics (servers / inputs / ${input:...} keychain model, CodeLens, MCP: List Servers) are preserved correctly. Nice work.

Requesting changes for the items below — details in the inline comments.

Must fix (this file):

  • Trailing whitespace, plus a . For HTTP.For HTTP missing-space regression in the Step 4 inputs rules.

Needs a decision / release step:

  • Version bump: this changes the template that ships to users, but marketplace.json (currently 1.0.2) isn't bumped. Per our release convention vscode-plugin bumps marketplace.json only — please bump it so the new instructions actually ship.
  • A few additions here are ahead of / diverge from Claude & Cursor (the ## Managed Settings section, the <PROJECT> re-sync Exception: clause, and the richer Step 2 error handling). Each is good on its own, but for true alignment we should either back-port them to the other two plugins or mark them as intentional VS-Code-only. Please also correct the PR description line about VS Code 'missing ... managed-settings enforcement' — it's actually ahead there.

Confirmed separately: the registry env var JFROG_AGENT_GUARD_REPO is correct (matches Claude). Cursor's JFROG_MCP_GATEWAY_REPO is the stale outlier and can be fixed in a separate change.

Comment on lines +30 to +34
`JF_PROJECT` env var → ASK the user. Exception: when the user
EXPLICITLY asks to switch project or re-sync the configuration, the
project they name (or the current `JF_PROJECT`) takes priority over
existing `_JF_ARGS`. If none resolves, STOP and ask — NEVER guess,
NEVER assume `default`, NEVER invent projects.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This Exception: clause — an explicit switch/re-sync overriding existing _JF_ARGS — is a good addition, but it does not exist in the Claude or Cursor <PROJECT> Pre-flight bullets. Since this PR's goal is cross-plugin alignment, let's either back-port it to claude-plugin/cursor-plugin or explicitly note it as deliberate VS-Code-only behavior.

Comment on lines +107 to +111
NEVER try multiple servers — pick one. Once chosen, pass it
If a server from the jf cli configuration is supposed to be used:
Always explicitly as `--server <ID>` in every agent guard invocation.
Otherwise, if environment variables for `JFROG_URL` and `JFROG_ACCESS_TOKEN`
are used: Do NOT pass `--server <ID>`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This server-resolution block reads as broken prose ("...Once chosen, pass it / If a server from the jf cli configuration is supposed to be used: / Always explicitly as --server <ID>..."). It's copied verbatim from the Claude/Cursor templates so it doesn't hurt alignment, but since all three are being touched it's worth rewording consistently, e.g.: "Once chosen: if using a jf CLI server, always pass it explicitly as --server <ID> in every invocation; if using JFROG_URL + JFROG_ACCESS_TOKEN instead, do NOT pass --server."

Comment on lines +160 to +170
On non-zero exit (typo, MCP not in catalog, network error, etc.),
show the error verbatim, then run `--list-available` (see "Listing
MCPs") so the user can pick a valid name and retry. If the failure is
because the MCP is **not allowed in the current project**, say so
conversationally and name the project — do NOT retry against a
different project.

**If the user did NOT specify a name** (e.g. "what can I install?"),
run `--list-available` instead (see "Listing MCPs" below).
If the user gave a name that is NOT in the catalog (typo, near-miss),
do NOT auto-install or guess. Run `--list-available`, present the
nearest matching names, and ask the user to confirm which one they
meant before proceeding.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The "not allowed in the current project" and "name not in catalog / near-miss" handling here is richer than the Claude/Cursor Step 2 (which only says "show the error verbatim, then run --list-available"). Good content — flagging only because it widens the gap with the two templates this PR aims to align with. Consider back-porting for consistency.

Comment on lines +251 to +253
`description` field. If the catalog leaves the description as an empty
string `""`, construct a brief context-appropriate description instead.
- Reference the input from `env` with `"${input:<id>}"`.For HTTP

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Two small fixes in this block:

  • Line 251 ends with a trailing space (after empty).
  • Line 253: "${input:<id>}".For HTTP is missing a space after the period (.For. For). The pre-rewrite text had the space; it regressed in this rewrite.

Comment on lines +397 to +412
## Managed Settings

Managed settings (`managed-settings.json`) can enforce
organization-level policy. When managed settings are in effect, they
override everything below and CANNOT be bypassed:

- **Agent-guard-only installation is enforced.** If the user asks to
install an MCP by any other means (`npm install`, `pip`, `docker`,
hand-editing `.vscode/mcp.json` with a direct `url`/`http`/`sse`
entry, etc.), BLOCK it immediately, run nothing, and respond
conversationally that all MCP installations must go through the
JFrog Agent Guard.
- **Protected MCPs cannot be removed.** If the target of a removal is
protected by managed settings, BLOCK the uninstall immediately and
respond conversationally that the MCP is protected by managed
settings and cannot be removed. Do not edit any config file.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This entire ## Managed Settings section is net-new and is not present in the Claude or Cursor templates today (Claude references managed-settings.json only in passing under Listing/Troubleshooting; Cursor not at all). So the PR description's claim that VS Code was "missing ... managed-settings enforcement while the other two plugins moved ahead" isn't accurate — VS Code is actually ahead here. Two asks: (1) correct that sentence in the PR description, and (2) decide whether this section should be back-ported to Claude/Cursor so all three stay genuinely aligned.

MatanEden1 and others added 3 commits June 16, 2026 10:56
Address YoniMelki's review on PR #21:
- Remove the VS-Code-only <PROJECT> switch/re-sync Exception clause from
  the Pre-flight bullet (not present in Claude/Cursor).
- Reword the broken server-resolution prose into a single clear sentence.
- Fix two regressions in the Step 4 inputs rules: trailing whitespace and
  a missing space ("${input:<id>}".For -> . For).
- Remove the net-new Managed Settings section (and its cross-reference in
  Removing an MCP); not present in Claude/Cursor.

Step 2's richer not-allowed/near-miss handling is kept intentionally
(to be back-ported to Claude/Cursor for alignment).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…js injector

Consolidate ensure-instructions.sh and ensure-instructions.ps1 into a
single inject-instructions.mjs that works on all platforms.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ions

Add resolveCredentials() with strict priority chain: --server flag,
env vars, CLI config default profile, and single-profile fallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@MatanEden1 MatanEden1 requested a review from YoniMelki June 16, 2026 11:34

@YoniMelki YoniMelki left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-review (head 3585b81): still requesting changes

Thanks for the updates. Confirmed resolved from the previous round: the . For HTTP space regression and the trailing whitespace in the template are fixed, and the project-switch priority is now mirrored into Pre-flight.

The scope grew to replace the shell scripts with inject-instructions.mjs, and that new file has blocking issues — details inline. Summary:

Blocking

  • inject-instructions.mjs reads the wrong template filename (jfrog-mcp-management.md vs this repo's copilot-instructions.md) and fails silently → nothing is ever injected.
  • The injector no longer writes .github/copilot-instructions.md, which is the file VS Code / GitHub Copilot actually reads — only the Claude-Code additionalContext is emitted now. Need confirmation this delivery-model change is intentional.

Should fix

  • Asymmetric force-flag env-var names (disable has a leading _, enable doesn't).
  • --server resolution is dead code, since the hook invokes the script with no args.
  • New per-session network call on SessionStart (minor; please note it in the PR).

Process

  • marketplace.json is 1.0.3 on both main and this branch, so the PR doesn't bump it — confirm these changes ship under a fresh version (if 1.0.3 is already published, this needs 1.0.4).
  • The PR description is now stale: it doesn't mention the script→Node-injector replacement (the largest code change here), and still claims VS Code was 'missing … managed-settings enforcement while the other two plugins moved ahead' (VS Code is actually ahead). Please update both.

Comment on lines +168 to +175
try {
template = readFileSync(
path.join(root, "templates", "jfrog-mcp-management.md"),
"utf8",
);
} catch {
process.exit(0);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Critical — wrong template filename; the feature silently injects nothing. This reads templates/jfrog-mcp-management.md, but the only template in this repo is templates/copilot-instructions.md (jfrog-mcp-management.md is the Claude/Cursor filename — this looks copy-pasted from the Claude plugin). Because the read is wrapped in catch { process.exit(0) }, the failure is silent: the read throws, the script exits 0, and no instructions are ever injected. Change line 170 to "copilot-instructions.md".

Comment on lines +177 to +184
process.stdout.write(
JSON.stringify({
hookSpecificOutput: {
hookEventName: "SessionStart",
additionalContext: template,
},
}),
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Major — this no longer writes .github/copilot-instructions.md. The old ensure-instructions.sh copied the template into .github/copilot-instructions.md in the workspace (the file VS Code / GitHub Copilot actually reads) and emitted this additionalContext. This injector only emits additionalContext, which is a Claude Code session mechanism that Copilot does not consume — so for a Copilot-instructions plugin, the instructions no longer reach Copilot. If the delivery model intentionally pivoted to Claude-Code-session-only injection, please call that out in the PR/Jira; otherwise the file-write half needs to be restored.

Comment thread plugin/scripts/inject-instructions.mjs Outdated
Comment on lines +22 to +25
const forceDisabled =
env("_JF_AGENT_GUARD_FORCE_DISABLE", "_JF_MCP_GATEWAY_FORCE_DISABLE") === "true";
const forceEnabled =
env("JF_AGENT_GUARD_FORCE_ENABLE", "JF_MCP_GATEWAY_FORCE_ENABLE") === "true";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Likely bug — asymmetric env-var naming. The disable flags carry a leading underscore (_JF_AGENT_GUARD_FORCE_DISABLE / _JF_MCP_GATEWAY_FORCE_DISABLE) but the enable flags don't (JF_AGENT_GUARD_FORCE_ENABLE / JF_MCP_GATEWAY_FORCE_ENABLE). A user setting JF_AGENT_GUARD_FORCE_DISABLE (the natural guess, no underscore) would silently have no effect. Confirm the underscore is intentional, or align the two.

Comment thread plugin/scripts/inject-instructions.mjs Outdated
Comment on lines +31 to +42
function getServerFlagValue() {
const args = process.argv;
for (let i = 0; i < args.length; i++) {
if (args[i].startsWith("--server=")) {
return args[i].split("=")[1];
}
if (args[i] === "--server" && i + 1 < args.length) {
return args[i + 1];
}
}
return null;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Dead code as invoked. hooks.json runs node ".../inject-instructions.mjs" with no arguments, so process.argv never contains --server; this always returns null and Priority 1 of resolveCredentials (lines 64–75) can never fire. Either thread --server through from the hook, or drop the branch — as-is it misrepresents the actual resolution order.

Comment thread plugin/scripts/inject-instructions.mjs Outdated
Comment on lines +109 to +123
async function isGatewayEnabledViaSettings() {
const credentials = resolveCredentials();
if (!credentials) {
debug("No credentials resolved; skipping settings check");
return false;
}
const { baseUrl, token } = credentials;
const url =
baseUrl.replace(/\/+$/, "") +
"/ml/core/api/v1/administration/account-settings/mcp_gateway_plugin_enabled";

debug(`Fetching gateway setting from ${url}`);

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Minor — new per-session network dependency. Every SessionStart now makes this call (5s timeout, fails closed). The old script made no network call. The behavior is reasonable, but worth noting in the PR: an unreachable/slow JFrog server can add up to ~5s to session start, and instructions won't load when offline.

MatanEden1 and others added 2 commits June 16, 2026 16:47
- Fix template filename to copilot-instructions.md (was injecting nothing)
- Restore .github/copilot-instructions.md write for Copilot delivery
- Align force-enable env vars with underscore-prefixed convention
- Remove unreachable --server resolution branch and fix precedence docs
- Lower gateway settings-check timeout from 5s to 3s

Co-authored-by: Cursor <cursoragent@cursor.com>
--login launches the system browser and runs a local OAuth callback
server, so a sandboxed run needs unrestricted permissions.

Co-authored-by: Cursor <cursoragent@cursor.com>
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