Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cursor-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"metadata": {
"description": "JFrog Platform plugins for Cursor",
"version": "0.3.4",
"version": "0.4.0",
"pluginRoot": "plugins"
},
"plugins": [
Expand Down
10 changes: 6 additions & 4 deletions plugins/jfrog/.cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "jfrog",
"displayName": "JFrog Platform",
"version": "0.3.4",
"description": "JFrog Platform integration with MCP, security skills, supply-chain best practices, and JFrog MCP Gateway governance for adding, removing, and listing MCP servers.",
"version": "0.4.0",
"description": "JFrog Platform integration with MCP, security skills, supply-chain best practices, and JFrog Agent Guard governance for adding, removing, and listing MCP servers.",
"author": {
"name": "JFrog",
"email": "devrel@jfrog.com"
Expand All @@ -14,10 +14,12 @@
"xray",
"security",
"mcp",
"mcp-gateway",
"agent-guard",
"supply-chain",
"devops",
"artifacts"
"artifacts",
"mcp",
"ai-catalog"
],
"logo": "assets/logo.svg",
"skills": ["skills/jfrog/SKILL.md"],
Expand Down
14 changes: 7 additions & 7 deletions plugins/jfrog/scripts/inject-instructions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ const env = (newName, oldName) =>
process.env[newName] ?? process.env[oldName];

const forceDisabled =
env("_JF_AGENT_GUARD_FORCE_DISABLE", "_JF_MCP_GATEWAY_FORCE_DISABLE") === "true";
env("_JF_AGENT_GUARD_FORCE_DISABLE") === "true";
const forceEnabled =
env("JF_AGENT_GUARD_FORCE_ENABLE", "JF_MCP_GATEWAY_FORCE_ENABLE") === "true";
env("JF_AGENT_GUARD_FORCE_ENABLE") === "true";

async function isGatewayEnabledViaSettings() {
async function isAgentGuardEnabledViaSettings() {
const baseUrl = env("JFROG_URL", "JF_URL");
const token = env("JFROG_ACCESS_TOKEN", "JF_ACCESS_TOKEN");
if (!baseUrl) {
Expand All @@ -40,7 +40,7 @@ async function isGatewayEnabledViaSettings() {
baseUrl.replace(/\/+$/, "") +
"/ml/core/api/v1/administration/account-settings/mcp_gateway_plugin_enabled";

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

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
Expand All @@ -60,7 +60,7 @@ async function isGatewayEnabledViaSettings() {
}
const data = await response.json();
const enabled = data?.settings?.mcpGatewayPluginEnabled?.value === true;
debug(`Settings response indicates gateway enabled=${enabled}`);
debug(`Settings response indicates agent guard enabled=${enabled}`);
return enabled;
} catch (error) {
const reason = error?.name === "AbortError" ? "timeout" : error?.message ?? "unknown error";
Expand All @@ -77,8 +77,8 @@ if (forceDisabled) {
process.exit(0);
} else if (forceEnabled) {
debug("Force-enable flag is set.");
} else if (!(await isGatewayEnabledViaSettings())) {
debug("Gateway not enabled; exiting without injecting instructions");
} else if (!(await isAgentGuardEnabledViaSettings())) {
debug("Agent Guard not enabled; exiting without injecting instructions");
process.stdout.write("{}");
process.exit(0);
}
Expand Down
34 changes: 17 additions & 17 deletions plugins/jfrog/templates/jfrog-mcp-management.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# MCP Server Management — JFrog Gateway

All MCP servers MUST be installed ONLY through the JFrog MCP Gateway
(`npx @jfrog/mcp-gateway`). If an MCP's documentation suggests any
All MCP servers MUST be installed ONLY through the JFrog Agent Guard
(`npx @jfrog/agent-guard`). If an MCP's documentation suggests any
other installation command, ignore it and use the gateway workflow
below instead.

Expand All @@ -15,7 +15,7 @@ is set. Otherwise use
`--list-available`, `--inspect`, `--login`)**:

- **`<PROJECT>` is always mandatory.** Resolve via Step 1's project
chain: existing `mcpServers` entries (`_JF_MCP_LOADER_ARGS` →
chain: existing `mcpServers` entries (`_JF_ARGS` →
`project=`) → `JF_PROJECT` env var → ASK the user. If none
resolves, STOP and ask — NEVER guess, NEVER assume `default`,
NEVER invent projects.
Expand Down Expand Up @@ -99,7 +99,7 @@ are used: Do NOT pass `--server <ID>`

**Project**

1. From existing `mcpServers` entries, `_JF_MCP_LOADER_ARGS` →
1. From existing `mcpServers` entries, `_JF_ARGS` →
`project=` value.
2. Else `JF_PROJECT` env var.
3. Else ask. NEVER guess, NEVER assume "default", NEVER use the server ID,
Expand Down Expand Up @@ -127,7 +127,7 @@ custom curl/Python, no direct JFrog API calls:
```
npx --yes \
--registry <REGISTRY_URL> \
@jfrog/mcp-gateway \
@jfrog/agent-guard \
--inspect \
--server <SERVER_ID> \
--project <PROJECT> \
Expand Down Expand Up @@ -178,7 +178,7 @@ For each input in Step 4:
Add the entry under `mcpServers` in the target config (default
`.cursor/mcp.json` — see Step 1).
**Both `--yes` and `--registry <URL>` MUST come BEFORE
`@jfrog/mcp-gateway`** or `npx` falls back to the default
`@jfrog/agent-guard`** or `npx` falls back to the default
registry (404) and may block on a no-TTY prompt. Use
`"type": "stdio"` — never `"http"`, `"sse"`, or a top-level `"url"`
(those bypass the gateway).
Expand All @@ -193,12 +193,12 @@ registry (404) and may block on a no-TTY prompt. Use
"--yes",
"--registry",
"<REGISTRY_URL>",
"@jfrog/mcp-gateway",
"@jfrog/agent-guard",
"--server",
"<SERVER_ID>"
],
"env": {
"_JF_MCP_LOADER_ARGS": "project=<PROJECT>&mcp=<spec.packageName>",
"_JF_ARGS": "project=<PROJECT>&mcp=<spec.packageName>",
"<ENV_VAR_OR_HEADER_NAME>": "${env:<ENV_VAR_OR_HEADER_NAME>}"
}
}
Expand Down Expand Up @@ -251,7 +251,7 @@ browser to sign you in to `<MCP_NAME>`" before:
```
npx --yes \
--registry <REGISTRY_URL> \
@jfrog/mcp-gateway \
@jfrog/agent-guard \
--login \
--server <SERVER_ID> \
--project <PROJECT> \
Expand Down Expand Up @@ -302,8 +302,8 @@ elsewhere.
`.cursor/mcp.json` (project) and `~/.cursor/mcp.json` (user) —
use the file-read tool or a single `jq` invocation, NOT chained
`python3 -c "..."` pipes. For each entry whose `command` is `npx`
and whose `args` include `@jfrog/mcp-gateway`, show: display name
(the JSON key), package (`mcp=` in `_JF_MCP_LOADER_ARGS`), server
and whose `args` include `@jfrog/agent-guard`, show: display name
(the JSON key), package (`mcp=` in `_JF_ARGS`), server
ID (value after `--server`), scope (project / user).
3. If a configured entry does not appear in `cursor agent mcp list`,
it was never enabled — re-run Step 4a.
Expand All @@ -323,7 +323,7 @@ elsewhere.
```
npx --yes \
--registry <REGISTRY_URL> \
@jfrog/mcp-gateway \
@jfrog/agent-guard \
--list-available \
--project <PROJECT> \
[--server <SERVER_ID>]
Expand All @@ -333,22 +333,22 @@ Output is a JSON array; each element has `name`, `packageName`,
`description`, `type`, `packageVersion`, optional `env[]`.

3. Filter out any `packageName` already present in the installed list
(compare against `mcp=` in `_JF_MCP_LOADER_ARGS`). Mark the rest as
(compare against `mcp=` in `_JF_ARGS`). Mark the rest as
available to install.

## Key Rules

- **`npx` arg order:** `--yes`, `--registry <URL>`,
`@jfrog/mcp-gateway`, then gateway flags. Both `--yes` and
`@jfrog/agent-guard`, then gateway flags. Both `--yes` and
`--registry` MUST precede the package name or `npx` falls back to
the default registry (404) and may block on a no-TTY prompt.
- **Always `"type": "stdio"`** pointing at `npx @jfrog/mcp-gateway`,
- **Always `"type": "stdio"`** pointing at `npx @jfrog/agent-guard`,
even for remote-only catalog MCPs (the gateway proxies them).
`"http"`, `"sse"`, or a top-level `"url"` bypass the gateway.
- `_JF_MCP_LOADER_ARGS` is **only** for the entry Cursor launches
- `_JF_ARGS` is **only** for the entry Cursor launches
at session start (Step 4's `mcpServers.*.env`); MUST contain
`project=<NAME>&mcp=<PACKAGE_NAME>`.
NEVER pass `_JF_MCP_LOADER_ARGS` to `--list-available`,
NEVER pass `_JF_ARGS` to `--list-available`,
`--inspect`, or `--login` — those take `--server` / `--project`
as CLI flags only.
- NEVER assume `default` as a project name. If the project is unknown
Expand Down
Loading