Skip to content
Closed
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.3.5",
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.

Better to change to 0.4.0 I think

"pluginRoot": "plugins"
},
"plugins": [
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ JFrog Platform integration for [Cursor](https://cursor.com) — artifact managem
| **Skills** | `plugins/jfrog/skills/` | 11 AI skills covering Artifactory, Security, Access, CLI, Curation, Distribution, AppTrust, Runtime, Mission Control, Workers, and Patterns |
| **Rule** | `plugins/jfrog/rules/jfrog-security.mdc` | Supply-chain security practices for dependency files |
| **Agent** | `plugins/jfrog/agents/supply-chain-security.md` | Dependency audit for CVEs, licenses, and curation |
| **Hook** | `plugins/jfrog/hooks/hooks.json` + `plugins/jfrog/scripts/inject-instructions.mjs` | `sessionStart` hook gated by the `JF_MCP_GATEWAY_FORCE_ENABLE` env var: when set to `"true"` it injects `templates/jfrog-mcp-management.md` as `additional_context`; otherwise it emits `{}` and stays silent |
| **Template** | `plugins/jfrog/templates/jfrog-mcp-management.md` | Gateway governance rule body — loaded by the hook above (not auto-discovered as a Cursor rule) only when `JFROG_MCP_GATEWAY_FORCE_ENABLE=true` or when the administration AI/ML settings are enabled via the platform. Teaches the agent how to add, remove, and list MCP servers exclusively through `npx @jfrog/mcp-gateway`. |
| **Hook** | `plugins/jfrog/hooks/hooks.json` + `plugins/jfrog/scripts/inject-instructions.mjs` | `sessionStart` hook gated by the `JF_AGENT_GUARD_FORCE_ENABLE` env var: when set to `"true"` it injects `templates/jfrog-mcp-management.md` as `additional_context`; otherwise it emits `{}` and stays silent |
| **Template** | `plugins/jfrog/templates/jfrog-mcp-management.md` | Agent Guard governance rule body — loaded by the hook above (not auto-discovered as a Cursor rule) only when `JFROG_AGENT_GUARD_FORCE_ENABLE=true` or when the administration AI/ML settings are enabled via the platform. Teaches the agent how to add, remove, and list MCP servers exclusively through `npx @jfrog/agent-guard`. |

## Prerequisites

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.3.5",
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.

same

"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
10 changes: 5 additions & 5 deletions plugins/jfrog/scripts/inject-instructions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const forceDisabled =
const forceEnabled =
env("JF_AGENT_GUARD_FORCE_ENABLE", "JF_MCP_GATEWAY_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
72 changes: 36 additions & 36 deletions plugins/jfrog/templates/jfrog-mcp-management.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# MCP Server Management — JFrog Gateway
# MCP Server Management — JFrog Agent Guard

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


Expand All @@ -11,11 +11,11 @@ the value of the `JFROG_MCP_GATEWAY_REPO` environment variable if it
is set. Otherwise use
`https://releases.jfrog.io/artifactory/api/npm/coding-agents-npm/`.

**Pre-flight (applies to every gateway command —
**Pre-flight (applies to every agent guard command —
`--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` →
Comment thread
yanivt-jfrog marked this conversation as resolved.
`project=`) → `JF_PROJECT` env var → ASK the user. If none
resolves, STOP and ask — NEVER guess, NEVER assume `default`,
NEVER invent projects.
Expand All @@ -24,11 +24,11 @@ is set. Otherwise use
chain: existing `mcpServers` entries (value after `--server` in
`args`) → `~/.jfrog/jfrog-cli.conf.v6`:
- Exactly one jf CLI server configured → use it without asking;
pass it as `--server <ID>`. The gateway would auto-resolve to the same
pass it as `--server <ID>`. The agent guard would auto-resolve to the same
value if `--server` were omitted, but we pass it explicitly for
clarity and forward-compatibility.
- `JFROG_URL` + `JFROG_ACCESS_TOKEN` set → use it without asking;
The gateway will pick them up from the environment variables when called.
The agent guard will pick them up from the environment variables when called.
- Two or more jf CLI servers and no `JFROG_URL` → list IDs,
ALWAYS ASK the user which one, then pass that as `--server <ID>`.
ALWAYS prefer environment variables when set over asking.
Expand Down Expand Up @@ -77,8 +77,8 @@ unless absolutely necessary:
or `~/.cursor/mcp.json` (user) — take the value after `--server`
in `args`.
2. Else `JFROG_URL` env var set (with `JFROG_ACCESS_TOKEN`) — the
gateway can resolve credentials from these directly;
DO NOT pass `--server` as that would make the gateway try to
agent guard can resolve credentials from these directly;
DO NOT pass `--server` as that would make the agent guard try to
parse the server details from the jf cli configuration.
3. Else read `~/.jfrog/jfrog-cli.conf.v6`
(`%USERPROFILE%\.jfrog\jfrog-cli.conf.v6` on Windows) via a
Expand All @@ -93,13 +93,13 @@ unless absolutely necessary:

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 gateway invocation.
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>`

**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,10 +178,10 @@ 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).
(those bypass the agent guard).

```json
{
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 All @@ -208,7 +208,7 @@ registry (404) and may block on a no-TTY prompt. Use

Notes:

- If a required `${env:VAR}` is unset, the gateway fails at startup.
- If a required `${env:VAR}` is unset, the agent guard fails at startup.
Confirm the user exported it before they restart.
If any env vars are missing, ASK the user to export them and restart Cursor.
- For `Bearer`-prefixed headers, either include the prefix in the env
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 @@ -312,8 +312,8 @@ elsewhere.

1. Determine **server** and **project** per the Pre-flight rule at
the top of this document. `--list-available` does NOT require
any existing `mcpServers` entry or pre-installed gateway
`npx --yes` fetches the gateway on demand, so this works on a
any existing `mcpServers` entry or pre-installed agent guard
`npx --yes` fetches the agent guard on demand, so this works on a
fresh machine too.
2. Run EXACTLY this command — `--project` is passed as a CLI flag
To configure the server, either use the serverId from a jf cli
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 agent guard 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`,
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
- **Always `"type": "stdio"`** pointing at `npx @jfrog/agent-guard`,
even for remote-only catalog MCPs (the agent guard proxies them).
`"http"`, `"sse"`, or a top-level `"url"` bypass the agent guard.
- `_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 All @@ -357,33 +357,33 @@ Output is a JSON array; each element has `name`, `packageName`,
NEVER invent or guess projects or server IDs.
- Package name MUST come from the catalog (`--inspect` /
`--list-available`). NEVER guess. NEVER install MCPs outside the
gateway. NEVER use Fetch/WebFetch for catalog calls.
agent guard. NEVER use Fetch/WebFetch for catalog calls.
- NEVER write a raw secret into `mcp.json` — always use
`${env:VAR_NAME}`. NEVER show tokens / API keys.
- NEVER try multiple servers — ask the user to pick one.

## Troubleshooting

- **`ready` but 0 tools (empty `mcps/<key>/tools/` after a
Command Palette `Developer: Reload Window`)** — gateway proxy
Command Palette `Developer: Reload Window`)** — agent guard proxy
started, upstream MCP did not. The top-level `ready` label is
misleading here. NEVER report success when there are 0 tools.
1. Open Cursor's MCP / Output panel for the
gateway stderr; diagnose by MCP type:
agent guard stderr; diagnose by MCP type:
- **OAuth (remote)** — re-run Step 5 (`--login`); refresh token
likely expired.
- **Static-token (remote)** — confirm every `${env:VAR}` in `env`
is exported in the shell that launched Cursor and the token is
still valid.
- **Local (stdio)** — check that the bundled binary actually
launched (gateway stderr will show the spawn error).
launched (agent guard stderr will show the spawn error).
2. Verify that the mcp server is still allowed.
See "Listing MCPs > Available to install".
- **`mcp.json` server missing from `cursor agent mcp list` /
Tools & MCP** — never enabled. Re-run Step 4a
(`cursor agent mcp enable <name>`); if the entry is brand-new,
also `Developer: Reload Window` so Cursor picks up the file.
- **Gateway: `multiple/no JFrog server configured`** (the gateway
- **Agent Guard: `multiple/no JFrog server configured`** (the agent guard
cannot pick a JFrog server) — pass `--server <ID>` (after
`jf c add <SERVER_ID>`) OR export both `JFROG_URL` and
`JFROG_ACCESS_TOKEN` in the launching shell, then relaunch Cursor.
Expand Down
Loading