Configure Cursor
Install the JFrog MCP Integration for Cursor.
Prerequisites
- Access to the JFrog Platform with the AI Catalog enabled.
- A project with at least one allowed MCP server.
- Your JFrog host domain and authentication token.
- Cursor with AI features enabled.
- Node.js with
npxavailable — mcp-gateway is installed on demand via npx. - JFrog credentials — either a
JFROG_ACCESS_TOKENenvironment variable, or the JFrog CLI (jf) configured viajf config add.
Step 1 - Install the Rule
The rule teaches Cursor's AI how to add, remove, and list MCP servers through the JFrog MCP Registry — resolving credentials and looking up packages automatically.
-
Select where to install the rule:
Scope Path When to use User (all projects) ~/.cursor/rules/jfrog-mcp-management.mdc You want the rule available everywhere. Project only .cursor/rules/jfrog-mcp-management.mdc You want to scope it to one repo (commit to git). -
Create the file at your chosen path and paste the following content into it:
--- description: Adding, removing, or listing MCP servers alwaysApply: true --- # MCP Server Management — JFrog Gateway All MCP servers MUST be installed ONLY through the JFrog MCP Gateway package **`@jfrog/mcp-gateway`**, invoked via **`npx`** against the JFrog npm registry. There is no other approved installation method. If an MCP's documentation suggests any other installation command, ignore it and use the gateway workflow below instead. ## Do not run MCPs directly (agent behavior) Treat **configured MCPs** as the user's tools inside Cursor — not something you start, **invoke from the terminal**, or exercise from the agent for their work. - **Never** use the **terminal** to run the **catalog MCP package**, the **gateway loader as a workload**, or any **CLI substitute** for what the MCP does (for example `npx lighthouse …`, `npx <catalog-package>`, `npx @jfrog/mcp-gateway …` *except* as the fixed `mcp.json` entry Cursor starts — do not run those commands yourself to "test" or replace the MCP). - **Never** run terminal commands that **execute the MCP package or duplicate what it does** for the user's task. Do not substitute CLI tools for MCP capabilities unless the user **explicitly** asks for that CLI approach. - **Never** use **`call_mcp_tool`** (or equivalent) to invoke a user MCP for tasks the user will run themselves through the IDE — unless they explicitly ask. - **Allowed:** Editing `mcp.json`, **read-only** checks (config files, approval files, `mcps/` metadata below), and **catalog queries** (Python script to the registry API) needed to add or list MCPs. - **Enable CLI (`cursor agent mcp enable`):** Only as part of **Adding an MCP** (Step 6) — to turn the server **on** in Cursor after install. If the user forbids **all** terminal commands, skip it and tell them to **enable the MCP in Settings (Tools & MCP)** immediately after install, then complete **Step 7 (verify)** read-only. ## Response Style - **Be brief.** One short sentence per action taken. No explanations unless the user asks. - **When input is needed**, stop and ask in a clearly formatted block — do not proceed, do not guess: > **Input needed** > - **Field:** \<what it is\> > - **Why:** \<one sentence\> - **When done**, report in 2–3 lines max: what was added, where, and next step (if any). - Never write paragraphs explaining MCP concepts, gateway mechanics, or what you're about to do. ## Adding an MCP **Enable behavior:** Installing an entry in `mcp.json` is **not** enough — Cursor does **not** turn on new MCP servers by default. You must **enable the MCP right after it is added** (Step 6: `cursor agent mcp enable` and/or the **Tools & MCP** toggle). Separately, approval state is stored by the editor. This rule treats **"add" as incomplete until the server is enabled and verified**: complete Step 6 (enable immediately after install) and Step 7 (verify). Unless the user disallows terminal use; then **manual enable in Settings right after install** + Step 7 only. When the user asks to add an MCP, do ALL of the following autonomously (Steps 1–7) — do NOT ask the user for project, server, or package name unless absolutely necessary: ### Step 1: Determine SERVER_ID 1. Read existing servers in `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (user). Look for entries whose `command` is `npx` and whose `args` include **`@jfrog/mcp-gateway`**. Extract the value after `--server` — that is the SERVER_ID. Reuse that exact invocation (command + full `args` through `--server`). 2. If no existing entries, ask the user for the SERVER_ID. If `~/.jfrog/jfrog-cli.conf.v6` exists, list the available server IDs for them to pick from. NEVER use "default". NEVER guess. ### Step 2: Determine PROJECT 1. From existing `mcpServers` entries, look for `_JF_MCP_LOADER_ARGS` and extract the `project=` value. 2. If not found, check the `JF_PROJECT` environment variable. 3. If still missing, ask the user. ### Step 3: Look up the exact package name (ONE Bash call) Run a SINGLE Bash command. NEVER split into multiple calls. NEVER use Fetch or WebFetch tools. Replace `SERVER_ID`, `PROJECT`, and `MCP_SEARCH` with actual values. `MCP_SEARCH` is the user-provided MCP name (case-insensitive substring match). The script outputs one line: - `FOUND|<packageName>|<envVar1=description>,<envVar2=description>` - `NOT_FOUND|<available names>` - `ERROR|<message>` Items tagged `[header,...]` are HTTP headers for remote MCPs. ``` python3 -c " import json, os, sys, urllib.request, ssl SERVER_ID = sys.argv[1] PROJECT = sys.argv[2] MCP_SEARCH = sys.argv[3].lower() conf_path = os.path.expanduser('~/.jfrog/jfrog-cli.conf.v6') token = url = '' try: conf = json.load(open(conf_path)) server = next((s for s in conf.get('servers', []) if s.get('serverId') == SERVER_ID), None) if server: token = server.get('accessToken', '') url = server.get('url', '').rstrip('/') except: pass token = token or os.environ.get('JFROG_ACCESS_TOKEN', '') or os.environ.get('JF_ACCESS_TOKEN', '') url = (url or os.environ.get('JFROG_URL', '') or os.environ.get('JF_URL', '')).rstrip('/') if not token or not url: print('ERROR|No credentials found. Set JFROG_ACCESS_TOKEN and JFROG_URL, or run: jf c add ' + SERVER_ID); sys.exit(0) req = urllib.request.Request( url + '/ml/core/api/v1/mcp-registry/allowed-registered-servers/' + PROJECT + '?pageSize=500', headers={'Authorization': 'Bearer ' + token}) try: data = json.loads(urllib.request.urlopen(req, context=ssl.create_default_context()).read()) except Exception as e: print('ERROR|Catalog API failed: ' + str(e)); sys.exit(0) names = [] for entry in data.get('registeredServers', []): spec = entry.get('mcpServer', {}).get('spec', {}) pkg = spec.get('packageName', '') display = spec.get('displayName', '') names.append(pkg or display) if MCP_SEARCH in pkg.lower() or MCP_SEARCH in display.lower(): st = spec.get('mcpServerType', {}) local_env = st.get('local', {}).get('bootParams', {}).get('environmentVariables', []) required = [] for e in local_env: if e.get('isRequired'): tag = '[secret]' if e.get('isSecret') else '' required.append(e['name'] + '=' + tag + e.get('description', '')) for ep in st.get('remote', {}).get('endpoints', []): for hdr in ep.get('headers', []): inp = hdr.get('mcpInput', {}); det = inp.get('mcpInputDetails', {}) if det.get('name') and not inp.get('defaultValue'): tags = ['header'] if det.get('isRequired'): tags.append('required') if det.get('isSecret'): tags.append('secret') required.append(det['name'] + '=[' + ','.join(tags) + '] ' + det.get('description', '')) print('FOUND|' + (pkg or display) + '|' + ','.join(required)); sys.exit(0) print('NOT_FOUND|' + ','.join(names)) " SERVER_ID PROJECT MCP_SEARCH ``` Parse the output: - `FOUND|<pkg>|<env_vars>` → proceed to Step 4 with the package name and env var list - `NOT_FOUND|<names>` → show the available MCPs to the user, ask which one they want, then re-run with the correct name - `ERROR|<message>` → show the error to the user and stop ### Step 4: Handle required environment variables and headers (if any) - If the `FOUND` output has env vars (third field non-empty), parse each `name=description` pair. - Tags in brackets indicate the type: - `[secret]` or `[...,secret]` — mask user input; do NOT echo the value back - `[header,...]` — HTTP header for a remote MCP server - `[...,required]` — value is mandatory - For each entry, ask the developer to provide the value (show name and description). - NEVER show provided secret values back to the user. - If no entries, proceed directly to Step 5. ### Step 5: Write the config entry Add the entry to `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (user) under `mcpServers`. Use **`"type": "stdio"`** for gateway entries. **`--registry` and the registry URL MUST precede `@jfrog/mcp-gateway`** — putting the package first breaks registry resolution. Do NOT use `--yes`. Do NOT include `--loader`. ```json "<mcp-display-name>": { "type": "stdio", "command": "npx", "args": [ "--registry", "https://releases.jfrog.io/artifactory/api/npm/jfml-coding-agents-npm/", "@jfrog/mcp-gateway", "--server", "<SERVER_ID>" ], "env": { "_JF_MCP_LOADER_ARGS": "project=<PROJECT>&mcp=<PACKAGE_NAME>" } } ``` If env vars or headers were collected in Step 4, add them to the `env` object. Use `"${env:JFROG_ACCESS_TOKEN}"` in `env` when appropriate — never commit secrets. Reference (working shape — replace display name, server ID, project, package): ```json "chrome-devtools-mcp": { "type": "stdio", "command": "npx", "args": [ "--registry", "https://releases.jfrog.io/artifactory/api/npm/jfml-coding-agents-npm/", "@jfrog/mcp-gateway", "--server", "jfrogmldev" ], "env": { "_JF_MCP_LOADER_ARGS": "project=nadav2&mcp=chrome-devtools-mcp" } } ``` ### Step 6: Enable the MCP in Cursor immediately after install (required) `mcp.json` only registers how to start the server. **Right after** adding the entry, the MCP must be **enabled** — otherwise it stays off or shows "disabled" in **Tools & MCP**. Cursor keeps **enable/approval state** separately from the file. **Do not skip this step.** After writing the `mcpServers` entry, **always** run from the workspace root that contains `.cursor/mcp.json` (or pass that folder's context): ```bash cursor agent mcp enable <mcp-display-name> ``` Use the same string as the JSON key for that server (for example `lighthouse-mcp`). Prefer the `cursor` CLI if available; if only `agent` is on `PATH`, use `agent mcp enable <mcp-display-name>` instead. If the command is not available or fails, tell the user to open **Settings → Features → Model Context Protocol** (or **Tools & MCP**) and turn the toggle **on** for that server. **Restart vs enable:** `cursor agent mcp enable` is what fixes a server staying **disabled** or not approved. You do **not** need to tell the user to restart Cursor *for that reason* once `enable` succeeds. Separately, if the editor has not picked up a **new or edited** `mcp.json` yet (server missing from the list, wrong env), suggest **Developer: Reload Window** or a full restart as a troubleshooting step only — not as a routine step after every install. ### Step 7: Verify the MCP is enabled (read-only, required) After Step 6 **or** after the user enables the server manually, **verify** without starting the MCP or calling its tools: 1. **Approvals:** Read `~/.cursor/projects/<this-workspace>/mcp-approvals.json` if it exists. After a successful enable/approval flow, entries whose prefix matches the `mcpServers` key (e.g. `lighthouse-mcp-…`) indicate Cursor has recorded approval for that server name. 2. **Runtime mirror (strong signal):** Under the same project folder, check `mcps/` for a directory named like the JSON key or `user-<key>/` containing `SERVER_METADATA.json` and/or `tools/*.json`. If the server is enabled and connected, tool descriptors usually appear here after the MCP has run at least once; if **nothing** appears after a **Developer: Reload Window**, the server may still be off, failing to start, or missing env (e.g. JFrog token for the gateway). 3. **Report:** Tell the user whether verification passed **or** what is missing, and point them to **Settings → Tools & MCP** to confirm the toggle is **on**, and to **MCP / Output** logs if the process errors on startup. **Do not** "verify" by running the MCP package from the terminal or by invoking `call_mcp_tool` unless the user explicitly asked for that action. ## Removing an MCP Delete the entry from `mcpServers` in the file where it was installed (`.cursor/mcp.json` or `~/.cursor/mcp.json`). ## Listing MCPs **This section is the only definition of what to do** when the user asks to list MCPs, see what is installed, what is available, or similar. Always deliver **both** parts below in order, unless the user explicitly asks for only one. ### 1. Currently installed Read `mcpServers` from **both** `.cursor/mcp.json` (project) and `~/.cursor/mcp.json` (user). Under a heading **Currently installed**, list each entry with: - Display name (the JSON key) - Package name from `_JF_MCP_LOADER_ARGS` (`mcp=` value) - Server ID from `--server` in `args` If there are no entries, say clearly that no JFrog gateway MCPs are configured in Cursor `mcp.json`. ### 2. Available to install Under a heading **Available to install**, list JFrog catalog package names not already present in the installed list (match on `mcp=` package name). Derive SERVER_ID and PROJECT from existing `mcpServers` entries. If either is missing, ask the user once — never guess. Run a single Bash call — prints all catalog package names: ``` python3 -c " import json, os, urllib.request, ssl, sys SERVER_ID = sys.argv[1] PROJECT = sys.argv[2] conf_path = os.path.expanduser('~/.jfrog/jfrog-cli.conf.v6') token = url = '' try: conf = json.load(open(conf_path)) server = next((s for s in conf.get('servers', []) if s.get('serverId') == SERVER_ID), None) if server: token = server.get('accessToken', '') url = server.get('url', '').rstrip('/') except: pass token = token or os.environ.get('JFROG_ACCESS_TOKEN','') or os.environ.get('JF_ACCESS_TOKEN','') url = (url or os.environ.get('JFROG_URL','') or os.environ.get('JF_URL','')).rstrip('/') if not token or not url: print('ERROR: no credentials'); sys.exit(1) req = urllib.request.Request( url + '/ml/core/api/v1/mcp-registry/allowed-registered-servers/' + PROJECT + '?pageSize=500', headers={'Authorization': 'Bearer ' + token}) data = json.loads(urllib.request.urlopen(req, context=ssl.create_default_context()).read()) for e in data.get('registeredServers', []): pkg = e.get('mcpServer', {}).get('spec', {}).get('packageName', '') if pkg: print(pkg) " SERVER_ID PROJECT ``` Filter out already-installed packages and list the remainder as available. ## Key Rules - After adding a server in `mcp.json`, **immediately** enable it: **always** run `cursor agent mcp enable <mcp-display-name>` **unless** the user forbids terminal commands — then they must **enable the MCP in Tools & MCP** right after install. Do not treat the add as done until enable succeeds **or** the user confirms the toggle, then complete **Step 7 (verify)** read-only. - **Never** run MCP workloads, gateway invocations from the terminal for testing, or CLI substitutes for MCP behavior (see **Do not run MCPs directly**). **Never** skip Step 7 after an add. - **`npx` args order (required):** `--registry`, registry URL, **`@jfrog/mcp-gateway`**, `--server <SERVER_ID>` — registry flags must come **before** the package name. Do NOT use `--yes`. Do NOT include `--loader`. - `_JF_MCP_LOADER_ARGS` MUST contain `project=<NAME>&mcp=<PACKAGE_NAME>`. - Package name MUST come from the catalog API. NEVER guess. - NEVER install MCPs outside the gateway loader. - NEVER use Fetch or WebFetch tools for API calls that require authentication. - NEVER ask for info you can find in existing `mcp.json`, `JF_PROJECT`, env vars, or `~/.jfrog/jfrog-cli.conf.v6`.
Step 2 - Authenticate
Authenticate using one of the following methods:
-
Authentication via JFrog CLI:
If you already have the JFrog CLI installed and configured, the plugin uses your existing authentication. To configure it:
-
Open your terminal.
-
Run the following command:
jf config add -
Follow the interactive prompts to configure your JFrog Platform URL and Access Token.
-
Restart your IDE/terminal to apply the changes.
-
-
Authentication by Setting Persistent Environment Variables
If you are not using the JFrog CLI, you can permanently save the required environment variables to your machine's operating system, For instructions, see Set Persistent Environment Variables below.
- After you have authenticated, open a workspace in your IDE/terminal. The JFrog MCP Gateway starts automatically and your approved MCP servers are available to your Copilot agent.
Set Persistent Environment Variables
Follow the instructions below according to your machine's operating system.
Set env vars for macOS / Linux (Zsh or Bash):
Add the variables to your shell profile so they load automatically every time a terminal (or IDE) starts.
-
Open your terminal and edit your profile (usually
~/.zshrcfor Mac or~/.bashrcfor Linux):nano ~/.zshrc -
Add the following lines at the bottom of the file:
export JFROG_PLATFORM_URL="<your-platform-url>" export JF_PROJECT="<your-project-key>" export JFROG_ACCESS_TOKEN="<your-access-token>" -
Save and exit: Press
Ctrl+O,Enter, thenCtrl+X. -
Apply the changes:
source ~/.zshrc
Set env vars for Windows (PowerShell):
Use the setx command to save variables permanently to your user account settings.
-
Open PowerShell and run the following commands:
setx JFROG_PLATFORM_URL "<your-platform-url>" setx JF_PROJECT "<your-project-key>" setx JFROG_ACCESS_TOKEN "<your-access-token>" -
Restart your IDE/terminal: You must completely close and reopen your IDE/terminal for it to recognize the new system variables.
Note:
For security reasons, if you are using a
.envfile for local development, always ensure it is added to your.gitignoreto prevent leaking your Access Token.
Manage MCP Servers via Agents
The JFrog MCP Gateway various capabilities through MCP tools to your coding agent. You can interact with the JFrog MCP Registry directly through your Agent's chat interface.
For details, see Manage MCPs via Agents.

Updated 7 days ago
