From 313277e15c9b715d428f6340fdf31b317a78ec81 Mon Sep 17 00:00:00 2001 From: Matan Eden <57892946+MatanEden1@users.noreply.github.com> Date: Sun, 28 Jun 2026 16:00:48 +0300 Subject: [PATCH 01/11] =?UTF-8?q?AX-1742=20=E2=80=94=20Add=20JFrog=20MCP?= =?UTF-8?q?=20server=20via=20.mcp.json=20(without=20Agent=20Guard)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Auto-attach the remote JFrog MCP server (${JFROG_URL}/mcp, OAuth) to every session via plugin/.mcp.json, mirroring jfrog/claude-plugin#23. Bump plugin version to 1.0.5 and document the MCP server + trailing-slash note in README. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 3 ++- marketplace.json | 2 +- plugin/.claude-plugin/plugin.json | 2 +- plugin/.mcp.json | 8 ++++++++ 4 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 plugin/.mcp.json diff --git a/README.md b/README.md index d4ed663..74ad9c8 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ The JFrog plugin provides the following capabilities, grouped by component: | Component | Feature | Description | | --- | --- | --- | +| **MCP** | JFrog MCP server | Remote JFrog MCP server auto-attached to every session via `.mcp.json` at `${JFROG_URL}/mcp` (OAuth, no API keys). | | **Hook** | Agent Guard | Copilot manage MCPs through the JFrog Agent Guard. Through it you can discover, install, configure, update, and remove MCP servers from the JFrog AI Catalog approved for your project, and authenticate to remote HTTP MCPs via OAuth, API key, or bearer token. | --- @@ -82,7 +83,7 @@ VS Code opens, prompts you to install the plugin, and asks you to **Trust** the | Variable | Description | | --- | --- | -| `JFROG_URL` | Your JFrog platform URL, e.g. `https://mycompany.jfrog.io` | +| `JFROG_URL` | Your JFrog platform URL, e.g. `https://mycompany.jfrog.io` (no trailing `/`) | | `JFROG_ACCESS_TOKEN` | Your JFrog access token | ### 2. Configure the JFrog CLI diff --git a/marketplace.json b/marketplace.json index 655c1b2..b956269 100644 --- a/marketplace.json +++ b/marketplace.json @@ -9,7 +9,7 @@ { "name": "jfrog", "description": "JFrog Platform integration with MCP, security skills, and supply-chain best practices", - "version": "1.0.4", + "version": "1.0.5", "source": "plugin", "categories": ["security", "artifact-management", "supply-chain", "devops", "mcp", "mlops", "agent-guard", "ai-catalog"], "platforms": ["darwin", "linux", "windows"], diff --git a/plugin/.claude-plugin/plugin.json b/plugin/.claude-plugin/plugin.json index 095ca0a..6c0de44 100644 --- a/plugin/.claude-plugin/plugin.json +++ b/plugin/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "jfrog", "description": "JFrog Platform integration with MCP, security skills, and supply-chain best practices", - "version": "1.0.4", + "version": "1.0.5", "author": { "name": "JFrog", "url": "https://jfrog.com" }, "hooks": "hooks/hooks.json" } diff --git a/plugin/.mcp.json b/plugin/.mcp.json new file mode 100644 index 0000000..d7b7ef3 --- /dev/null +++ b/plugin/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "jfrog": { + "type": "http", + "url": "${JFROG_URL}/mcp" + } + } +} From 86d3f5ae5916ba295275cfdbafbb17be4cca1e41 Mon Sep 17 00:00:00 2001 From: Matan Eden <57892946+MatanEden1@users.noreply.github.com> Date: Sun, 28 Jun 2026 17:48:46 +0300 Subject: [PATCH 02/11] Warn on missing or trailing-slash JFROG_URL at session start --- plugin/scripts/inject-instructions.mjs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugin/scripts/inject-instructions.mjs b/plugin/scripts/inject-instructions.mjs index 365f657..9ae95f1 100644 --- a/plugin/scripts/inject-instructions.mjs +++ b/plugin/scripts/inject-instructions.mjs @@ -20,6 +20,16 @@ const debug = (message) => { const env = (newName, oldName) => process.env[newName] ?? process.env[oldName]; +// Validate JFROG_URL early to surface misconfigurations before the MCP server +// attempts to connect and fails with a confusing DNS or double-slash error. +const jfrogUrl = env("JFROG_URL", "JF_URL"); +if (!jfrogUrl) { + log("JFROG_URL is not set. The JFrog MCP server will be unreachable — set JFROG_URL to your Artifactory base URL (e.g. https://mycompany.jfrog.io) and restart."); +} +if (jfrogUrl?.endsWith("/")) { + log("JFROG_URL has a trailing slash. This produces a double-slash in the MCP URL and will silently fail — remove the trailing slash and restart."); +} + const forceDisabled = env("_JF_AGENT_GUARD_FORCE_DISABLE") === "true"; const forceEnabled = From 39a7c4ffd26be51d18e035b17be468f8f05fcfd9 Mon Sep 17 00:00:00 2001 From: Matan Eden <57892946+MatanEden1@users.noreply.github.com> Date: Sun, 28 Jun 2026 17:56:45 +0300 Subject: [PATCH 03/11] Fix JFROG_URL validation: move below force-disable guard and handle JF_URL-only case - Validation no longer fires for users with Agent Guard force-disabled - Adds explicit warning when JF_URL is set but JFROG_URL (required by .mcp.json) is not Co-Authored-By: Claude Sonnet 4.6 --- plugin/scripts/inject-instructions.mjs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/plugin/scripts/inject-instructions.mjs b/plugin/scripts/inject-instructions.mjs index 9ae95f1..a659c7f 100644 --- a/plugin/scripts/inject-instructions.mjs +++ b/plugin/scripts/inject-instructions.mjs @@ -20,16 +20,6 @@ const debug = (message) => { const env = (newName, oldName) => process.env[newName] ?? process.env[oldName]; -// Validate JFROG_URL early to surface misconfigurations before the MCP server -// attempts to connect and fails with a confusing DNS or double-slash error. -const jfrogUrl = env("JFROG_URL", "JF_URL"); -if (!jfrogUrl) { - log("JFROG_URL is not set. The JFrog MCP server will be unreachable — set JFROG_URL to your Artifactory base URL (e.g. https://mycompany.jfrog.io) and restart."); -} -if (jfrogUrl?.endsWith("/")) { - log("JFROG_URL has a trailing slash. This produces a double-slash in the MCP URL and will silently fail — remove the trailing slash and restart."); -} - const forceDisabled = env("_JF_AGENT_GUARD_FORCE_DISABLE") === "true"; const forceEnabled = @@ -129,6 +119,17 @@ if (forceDisabled) { process.stdout.write("{}"); process.exit(0); } + +// Validate JFROG_URL now that we know Agent Guard is active — surfaces +// misconfigurations before the MCP server fails with a confusing error. +if (!process.env.JFROG_URL && !process.env.JF_URL) { + log("JFROG_URL is not set. The JFrog MCP server will be unreachable — set JFROG_URL to your Artifactory base URL (e.g. https://mycompany.jfrog.io) and restart."); +} else if (!process.env.JFROG_URL && process.env.JF_URL) { + log("JF_URL is set but the MCP server requires JFROG_URL — set JFROG_URL to your Artifactory base URL and restart."); +} else if (process.env.JFROG_URL.endsWith("/")) { + log("JFROG_URL has a trailing slash. This produces a double-slash in the MCP URL and will silently fail — remove the trailing slash and restart."); +} + debug("Injecting instructions"); const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); From 9c274237cc102ec1ef14fa8a2d74b24f7489acb7 Mon Sep 17 00:00:00 2001 From: Matan Eden <57892946+MatanEden1@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:05:14 +0300 Subject: [PATCH 04/11] Run JFROG_URL validation before the Agent Guard gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .mcp.json attaches the JFrog MCP server regardless of whether Agent Guard is enabled, but the JFROG_URL validation ran after the agent-guard-enabled gate — so it was skipped in exactly the "without Agent Guard" case this PR targets, leaving a misconfigured MCP server with no warning. Move the validation above the gate (still after force-disable) and document why it reads process.env.* directly. Co-Authored-By: Claude Opus 4.8 (1M context) --- plugin/scripts/inject-instructions.mjs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/plugin/scripts/inject-instructions.mjs b/plugin/scripts/inject-instructions.mjs index a659c7f..f4d1a95 100644 --- a/plugin/scripts/inject-instructions.mjs +++ b/plugin/scripts/inject-instructions.mjs @@ -112,16 +112,15 @@ if (forceDisabled) { debug("Force-disable flag is set."); process.stdout.write("{}"); process.exit(0); -} else if (forceEnabled) { - debug("Force-enable flag is set."); -} else if (!(await isAgentGuardEnabledViaSettings())) { - debug("Agent Guard not enabled; exiting without injecting instructions"); - process.stdout.write("{}"); - process.exit(0); } -// Validate JFROG_URL now that we know Agent Guard is active — surfaces -// misconfigurations before the MCP server fails with a confusing error. +// Validate JFROG_URL before the Agent Guard gate: the static .mcp.json attaches +// the JFrog MCP server regardless of whether Agent Guard is enabled, so these +// warnings must surface even when the gate below exits early. We read +// process.env.* directly (not the env() helper) on purpose — the helper +// collapses JFROG_URL/JF_URL into one value, but .mcp.json only substitutes +// ${JFROG_URL}, so we must distinguish "neither set", "only JF_URL set", and +// "JFROG_URL has a trailing slash" to give an accurate, actionable message. if (!process.env.JFROG_URL && !process.env.JF_URL) { log("JFROG_URL is not set. The JFrog MCP server will be unreachable — set JFROG_URL to your Artifactory base URL (e.g. https://mycompany.jfrog.io) and restart."); } else if (!process.env.JFROG_URL && process.env.JF_URL) { @@ -130,6 +129,14 @@ if (!process.env.JFROG_URL && !process.env.JF_URL) { log("JFROG_URL has a trailing slash. This produces a double-slash in the MCP URL and will silently fail — remove the trailing slash and restart."); } +if (forceEnabled) { + debug("Force-enable flag is set."); +} else if (!(await isAgentGuardEnabledViaSettings())) { + debug("Agent Guard not enabled; exiting without injecting instructions"); + process.stdout.write("{}"); + process.exit(0); +} + debug("Injecting instructions"); const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); From 3b74788c3d7b0b7b8aca37f002cd6da22c12b1b5 Mon Sep 17 00:00:00 2001 From: Matan Eden <57892946+MatanEden1@users.noreply.github.com> Date: Mon, 29 Jun 2026 09:38:39 +0300 Subject: [PATCH 05/11] Warn on missing or trailing-slash JFROG_URL at session start --- plugin/scripts/inject-instructions.mjs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/plugin/scripts/inject-instructions.mjs b/plugin/scripts/inject-instructions.mjs index f4d1a95..eb0cde1 100644 --- a/plugin/scripts/inject-instructions.mjs +++ b/plugin/scripts/inject-instructions.mjs @@ -114,17 +114,10 @@ if (forceDisabled) { process.exit(0); } -// Validate JFROG_URL before the Agent Guard gate: the static .mcp.json attaches -// the JFrog MCP server regardless of whether Agent Guard is enabled, so these -// warnings must surface even when the gate below exits early. We read -// process.env.* directly (not the env() helper) on purpose — the helper -// collapses JFROG_URL/JF_URL into one value, but .mcp.json only substitutes -// ${JFROG_URL}, so we must distinguish "neither set", "only JF_URL set", and -// "JFROG_URL has a trailing slash" to give an accurate, actionable message. +// Validate JFROG_URL early to surface misconfigurations before the MCP server +// attempts to connect and fails with a confusing DNS or double-slash error. if (!process.env.JFROG_URL && !process.env.JF_URL) { log("JFROG_URL is not set. The JFrog MCP server will be unreachable — set JFROG_URL to your Artifactory base URL (e.g. https://mycompany.jfrog.io) and restart."); -} else if (!process.env.JFROG_URL && process.env.JF_URL) { - log("JF_URL is set but the MCP server requires JFROG_URL — set JFROG_URL to your Artifactory base URL and restart."); } else if (process.env.JFROG_URL.endsWith("/")) { log("JFROG_URL has a trailing slash. This produces a double-slash in the MCP URL and will silently fail — remove the trailing slash and restart."); } From 79bad8b0728a9aca4393c975bfc53bc48f28f36f Mon Sep 17 00:00:00 2001 From: Matan Eden <57892946+MatanEden1@users.noreply.github.com> Date: Mon, 29 Jun 2026 09:51:15 +0300 Subject: [PATCH 06/11] Fix JFROG_URL validation: guard endsWith with optional chaining Co-Authored-By: Claude Sonnet 4.6 --- plugin/scripts/inject-instructions.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/scripts/inject-instructions.mjs b/plugin/scripts/inject-instructions.mjs index eb0cde1..4474707 100644 --- a/plugin/scripts/inject-instructions.mjs +++ b/plugin/scripts/inject-instructions.mjs @@ -118,7 +118,7 @@ if (forceDisabled) { // attempts to connect and fails with a confusing DNS or double-slash error. if (!process.env.JFROG_URL && !process.env.JF_URL) { log("JFROG_URL is not set. The JFrog MCP server will be unreachable — set JFROG_URL to your Artifactory base URL (e.g. https://mycompany.jfrog.io) and restart."); -} else if (process.env.JFROG_URL.endsWith("/")) { +} else if (process.env.JFROG_URL?.endsWith("/")) { log("JFROG_URL has a trailing slash. This produces a double-slash in the MCP URL and will silently fail — remove the trailing slash and restart."); } From 4f6837b69c220a0078782b04199554cf2109c154 Mon Sep 17 00:00:00 2001 From: Matan Eden <57892946+MatanEden1@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:20:06 +0300 Subject: [PATCH 07/11] remove log prefix --- plugin/scripts/inject-instructions.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/scripts/inject-instructions.mjs b/plugin/scripts/inject-instructions.mjs index 4474707..f2656ad 100644 --- a/plugin/scripts/inject-instructions.mjs +++ b/plugin/scripts/inject-instructions.mjs @@ -11,7 +11,7 @@ import { fileURLToPath } from "node:url"; // Logs go to stderr; stdout is reserved for the hook JSON payload. const debugEnabled = process.env.JF_AGENT_GUARD_DEBUG === "true"; -const log = (message) => console.error(`[jfrog-agent-guard] ${message}`); +const log = (message) => console.error(message); const debug = (message) => { if (debugEnabled) log(message); }; From 1653c1283bc5c022388654e7bd415d40e8825c47 Mon Sep 17 00:00:00 2001 From: Matan Eden <57892946+MatanEden1@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:30:34 +0300 Subject: [PATCH 08/11] Validate JFROG_URL early to prevent connection issues with the MCP server --- plugin/scripts/inject-instructions.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/scripts/inject-instructions.mjs b/plugin/scripts/inject-instructions.mjs index f2656ad..ff44fca 100644 --- a/plugin/scripts/inject-instructions.mjs +++ b/plugin/scripts/inject-instructions.mjs @@ -116,7 +116,7 @@ if (forceDisabled) { // Validate JFROG_URL early to surface misconfigurations before the MCP server // attempts to connect and fails with a confusing DNS or double-slash error. -if (!process.env.JFROG_URL && !process.env.JF_URL) { +if (!process.env.JFROG_URL) { log("JFROG_URL is not set. The JFrog MCP server will be unreachable — set JFROG_URL to your Artifactory base URL (e.g. https://mycompany.jfrog.io) and restart."); } else if (process.env.JFROG_URL?.endsWith("/")) { log("JFROG_URL has a trailing slash. This produces a double-slash in the MCP URL and will silently fail — remove the trailing slash and restart."); From a51eb57f52ffb335560f99b16aade8a635b64790 Mon Sep 17 00:00:00 2001 From: Matan Eden <57892946+MatanEden1@users.noreply.github.com> Date: Mon, 29 Jun 2026 13:56:23 +0300 Subject: [PATCH 09/11] Surface JFROG_URL misconfiguration warnings to the user via additionalContext When JFROG_URL is unset or has a trailing slash, write a hookSpecificOutput payload so Claude immediately surfaces the warning to the user, in addition to the existing stderr log. Also set JFROG_URL in the force-enable validator test so it reaches template injection instead of the new early-exit path. Co-Authored-By: Claude Sonnet 4.6 --- plugin/scripts/inject-instructions.mjs | 20 ++++++++++++++++++-- scripts/validate-hook-injector.mjs | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/plugin/scripts/inject-instructions.mjs b/plugin/scripts/inject-instructions.mjs index ff44fca..331bb1c 100644 --- a/plugin/scripts/inject-instructions.mjs +++ b/plugin/scripts/inject-instructions.mjs @@ -117,9 +117,25 @@ if (forceDisabled) { // Validate JFROG_URL early to surface misconfigurations before the MCP server // attempts to connect and fails with a confusing DNS or double-slash error. if (!process.env.JFROG_URL) { - log("JFROG_URL is not set. The JFrog MCP server will be unreachable — set JFROG_URL to your Artifactory base URL (e.g. https://mycompany.jfrog.io) and restart."); + const missingUrlWarning = "JFROG_URL is not set. The JFrog MCP server will be unreachable — set JFROG_URL to your Artifactory base URL (e.g. https://mycompany.jfrog.io) and restart."; + log(missingUrlWarning); + process.stdout.write(JSON.stringify({ + hookSpecificOutput: { + hookEventName: "SessionStart", + additionalContext: `IMPORTANT: Immediately tell the user: "${missingUrlWarning}"`, + }, + })); + process.exit(0); } else if (process.env.JFROG_URL?.endsWith("/")) { - log("JFROG_URL has a trailing slash. This produces a double-slash in the MCP URL and will silently fail — remove the trailing slash and restart."); + const trailingSlashWarning = "JFROG_URL has a trailing slash. This produces a double-slash in the MCP URL and will silently fail — remove the trailing slash and restart."; + log(trailingSlashWarning); + process.stdout.write(JSON.stringify({ + hookSpecificOutput: { + hookEventName: "SessionStart", + additionalContext: `IMPORTANT: Immediately tell the user: "${trailingSlashWarning}"`, + }, + })); + process.exit(0); } if (forceEnabled) { diff --git a/scripts/validate-hook-injector.mjs b/scripts/validate-hook-injector.mjs index 9c9c0e6..c30984b 100644 --- a/scripts/validate-hook-injector.mjs +++ b/scripts/validate-hook-injector.mjs @@ -140,7 +140,7 @@ function main() { section("Format (injected payload shape)"); let injectedContext; check("force-enable emits valid JSON with a SessionStart additionalContext", () => { - const stdout = runInjector({ JF_AGENT_GUARD_FORCE_ENABLE: "true" }); + const stdout = runInjector({ JF_AGENT_GUARD_FORCE_ENABLE: "true", JFROG_URL: "https://example.jfrog.io" }); if (!stdout.trim()) throw new Error("stdout was empty"); let payload; try { From 49dafd6e925698745dc9358e50593e2da2952c3e Mon Sep 17 00:00:00 2001 From: Matan Eden <57892946+MatanEden1@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:17:56 +0300 Subject: [PATCH 10/11] Remove optional chaining from JFROG_URL trailing slash check for improved validation --- plugin/scripts/inject-instructions.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/scripts/inject-instructions.mjs b/plugin/scripts/inject-instructions.mjs index 331bb1c..c9c16bc 100644 --- a/plugin/scripts/inject-instructions.mjs +++ b/plugin/scripts/inject-instructions.mjs @@ -126,7 +126,7 @@ if (!process.env.JFROG_URL) { }, })); process.exit(0); -} else if (process.env.JFROG_URL?.endsWith("/")) { +} else if (process.env.JFROG_URL.endsWith("/")) { const trailingSlashWarning = "JFROG_URL has a trailing slash. This produces a double-slash in the MCP URL and will silently fail — remove the trailing slash and restart."; log(trailingSlashWarning); process.stdout.write(JSON.stringify({ From d81882ee4801841dacd320beea35103bad5ede64 Mon Sep 17 00:00:00 2001 From: Matan Eden <57892946+MatanEden1@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:41:02 +0300 Subject: [PATCH 11/11] Remove optional chaining from JFROG_URL trailing slash check for improved validation --- plugin/scripts/inject-instructions.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/scripts/inject-instructions.mjs b/plugin/scripts/inject-instructions.mjs index c9c16bc..1539b52 100644 --- a/plugin/scripts/inject-instructions.mjs +++ b/plugin/scripts/inject-instructions.mjs @@ -117,7 +117,7 @@ if (forceDisabled) { // Validate JFROG_URL early to surface misconfigurations before the MCP server // attempts to connect and fails with a confusing DNS or double-slash error. if (!process.env.JFROG_URL) { - const missingUrlWarning = "JFROG_URL is not set. The JFrog MCP server will be unreachable — set JFROG_URL to your Artifactory base URL (e.g. https://mycompany.jfrog.io) and restart."; + const missingUrlWarning = "WARNING: JFROG_URL is not set. The JFrog MCP server will be unreachable — set JFROG_URL to your Artifactory base URL (e.g. https://mycompany.jfrog.io) and restart."; log(missingUrlWarning); process.stdout.write(JSON.stringify({ hookSpecificOutput: { @@ -127,7 +127,7 @@ if (!process.env.JFROG_URL) { })); process.exit(0); } else if (process.env.JFROG_URL.endsWith("/")) { - const trailingSlashWarning = "JFROG_URL has a trailing slash. This produces a double-slash in the MCP URL and will silently fail — remove the trailing slash and restart."; + const trailingSlashWarning = "WARNING: JFROG_URL has a trailing slash. This produces a double-slash in the MCP URL and will silently fail — remove the trailing slash and restart."; log(trailingSlashWarning); process.stdout.write(JSON.stringify({ hookSpecificOutput: {