afv-library/skills/agentforce-generate/references/mcp-management-reference.md

38 KiB

MCP Server Management Reference

Register, configure, and manage Model Context Protocol (MCP) servers in the Salesforce API Catalog using the sf agent mcp CLI commands. This reference backs the Manage MCP Servers task domain in SKILL.md.

MCP servers expose assets — tools, prompts, and resources — that become available as agent actions once whitelisted. This reference covers server registration, lifecycle management, and interactive asset whitelisting.

Requires: sf CLI with the agent mcp plugin installed. Verify with sf help agent mcp. If the command is missing, check sf version, run sf update, and confirm plugin availability with sf plugins.

Developer preview: Every sf agent mcp command is currently in developer preview. Each response includes a warnings array containing a preview notice ("This command is currently in developer preview..."). Parse result as usual and ignore the warning for automation, but be aware flag/output shapes may change.

ID formats (observed): Server IDs use the 0Le prefix (e.g. 0LeSB000000JoFd), and asset IDs use the 1XO prefix (e.g. 1XOSB0000008riJ). The 0XSxx…/0YSxx… placeholders in older examples are illustrative only.

Core Principles

  1. Always --json — Include --json on every sf agent mcp command to get structured output. (Consistent with Rule 1 in SKILL.md.)
  2. Verify target org — Before any operation, confirm a target org is set with sf config get target-org --json. If none, ask the user to run sf config set target-org <alias>. (Consistent with Rule 2.)
  3. Interactive approval — When whitelisting tools, display metadata for each tool individually and wait for user approval before activating.
  4. Security first — For OAuth servers, handle client secrets securely (stdin piping) and warn about credential exposure. Flag destructive or broadly-scoped tools before activation.

Task Workflows

1. Register a New MCP Server

When the user wants to register/create/add an MCP server:

Required Information

Gather from the user (ask if not provided):

  • Server name (-n, --name) — Unique identifier
  • Server URL (--server-url) — Endpoint URL
  • Target org (-o, --target-org) — Org alias or username
  • Label (optional, --label) — Human-readable display name
  • Description (optional, --description) — Server purpose
  • Authentication type (--auth-type) — NO_AUTH (default) or OAUTH

If --auth-type OAUTH, also gather:

  • Identity provider (--identity-provider)
  • Client ID (--client-id)
  • Client secret (--client-secret) — Handle securely via stdin
  • Scope (--scope)

Execution Steps

  1. Verify target org is set

    sf config get target-org --json
    

    If no target org, ask user to set one with sf config set target-org <alias>

  2. Gather required information — Ask for any missing required fields

  3. Create the server

    NO_AUTH example:

    sf agent mcp create -n MyServer --server-url https://mcp.example.com/mcp -o myOrg --json
    

    OAUTH example (secure client secret handling):

    echo "secret-value" | sf agent mcp create -n MyServer --server-url https://mcp.example.com/mcp --auth-type OAUTH --identity-provider MyIdp --client-id abc123 --client-secret - --scope "read write" -o myOrg --json
    
  4. Extract server ID — Parse the JSON response and extract result.server.id (format: 0LeSB000000Jp5F). Note the ID is under result.server, not result directly. This ID is required for all subsequent operations. The response also includes result.assets (discovered but not yet registered — they have id: null and status: "NOT_REGISTERED" until you activate them).

  5. Display confirmation — Show the user:

    • Server name
    • Server ID
    • Server URL
    • Connection status
  6. Offer next steps

    • "Would you like to fetch and whitelist tools from this server now?"
    • If yes, proceed to Fetch and Whitelist Assets workflow

2. List MCP Servers

When the user wants to see all registered MCP servers:

  1. Verify target org

    sf config get target-org --json
    
  2. List servers

    sf agent mcp list -o myOrg --json
    

    Optional filters:

    • By status: --status ACTIVE or --status DISCONNECTED
    • By type: --type EXTERNAL
    • By label: --label "My Server"
  3. Display results — The server array is under result.mcpServers. Show a table or list with: Server name, Server ID, Status (ACTIVE/DISCONNECTED), Server URL, Label. Auth type is under each server's authorization.authType.

  4. Offer actions — Ask if the user wants to get details on a specific server, fetch assets, or update/delete a server

3. Get Server Details

When the user wants details on a specific server:

  1. Verify target org

    sf config get target-org --json
    
  2. Get server details

    sf agent mcp get -i 0XSxx0000000001 -o myOrg --json
    
  3. Display details — Name, label, description, server URL, status, authentication type (authorization.authType), and created/modified timestamps. Audit fields are IDs only (createdById/lastModifiedById) — there are no user-name objects. For OAUTH servers, authorization.scope and authorization.identityProvider (a token endpoint URL) are also present.

4. Fetch and Whitelist Assets (Interactive Tool Approval)

This is the core whitelisting workflow with interactive tool-by-tool approval.

  1. Verify target org

    sf config get target-org --json
    
  2. Fetch live assets from the server

    sf agent mcp fetch -i 0XSxx0000000001 -o myOrg --json
    
  3. Parse the response — Extract the list of assets from result.assets. Each asset includes: id, name (e.g., McpTool__getTickets), label, kind (MCP_TOOL/MCP_PROMPT/MCP_RESOURCE), active (boolean), availableAsAgentAction (boolean), description, and status (IN_SYNC/NOT_REGISTERED). Note: inputSchema, outputSchema, and annotations are NOT guaranteed to be present (the live server did not return them) — handle their absence gracefully.

  4. Interactive tool review — For EACH tool in the list:

    a. Display tool metadata clearly (only render schema/annotations fields if the server actually returned them — they are often absent):

    Tool: <name> (<label>)
    Kind: <kind>
    Description: <description>
    
    Input Schema:
    <formatted JSON inputSchema> (or "Not specified")
    
    Output Schema:
    <formatted JSON outputSchema> (or "Not specified")
    
    Annotations:
    <formatted JSON annotations> (or "None")
    
    Current Status: <active ? "ACTIVE" : "INACTIVE">
    

    b. Ask for approval:

    Do you want to ACTIVATE this tool? (yes/no/skip)
    - yes: Add to allowlist
    - no: Exclude from allowlist (deactivate if currently active)
    - skip: Keep current status unchanged
    

    c. Record the user's choice — Build an array of approved assets

  5. Build the asset allowlist — Create a JSON payload with the approved assets:

    {
      "assets": [
        { "name": "McpTool__add", "active": true },
        { "name": "McpTool__subtract", "active": false }
      ]
    }
    
  6. Replace the server's asset allowlist — Pass the payload inline via --assets, or pipe it through stdin with --assets -. No temp file needed.

    Inline (small payloads):

    sf agent mcp asset replace -i 0XSxx0000000001 \
      --assets '{"assets":[{"name":"McpTool__add","active":true},{"name":"McpTool__subtract","active":false}]}' \
      -o myOrg --json
    

    Via stdin (larger payloads):

    echo '<json payload>' | sf agent mcp asset replace -i 0XSxx0000000001 --assets - -o myOrg --json
    
  7. Confirm results — The replace response returns the full resulting asset set under result.assets (no assetsUpdated count field). Derive counts by inspecting each asset's active flag in the response, e.g.:

    Asset Allowlist Updated:
    - Active: <count of active:true> tools
    - Inactive: <count of active:false> tools
    

Notes on Asset Replacement

  • Full replacement semanticssf agent mcp asset replace is a FULL replacement, not a merge. Assets not in the payload are removed/deactivated.
  • Always include the full desired state — If a tool should remain active, include it in the payload with "active": true.
  • Read current state first — Use sf agent mcp fetch or sf agent mcp asset list to see current assets before replacement.

5. List Assets for a Server

When the user wants to see the current asset allowlist:

  1. Verify target org

    sf config get target-org --json
    
  2. List assets

    sf agent mcp asset list -i 0XSxx0000000001 -o myOrg --json
    
  3. Display results — Show each asset with: Name, Kind (MCP_TOOL, MCP_PROMPT, MCP_RESOURCE), Active status, Available as agent action

6. Update MCP Server

When the user wants to modify server configuration:

Updatable Fields

  • --label — New display label ⚠️ (observed not to persist — see command note)
  • --description — New description (persists)
  • --server-url — New endpoint URL ⚠️ (observed not to persist — see command note)
  • --auth-type — Change authentication (requires full OAuth params if switching to OAUTH)

⚠️ In live preview-CLI testing, only --description persisted; --label and --server-url returned success but were silently ignored. Always confirm with a follow-up get. See the sf agent mcp update command reference below for details.

Execution Steps

  1. Verify target org

    sf config get target-org --json
    
  2. Gather update fields — Ask which fields to change

  3. Update the server

    sf agent mcp update -i 0XSxx0000000001 --label "New Label" --description "Updated description" -o myOrg --json
    

    Switching to OAuth:

    echo "secret" | sf agent mcp update -i 0XSxx0000000001 --auth-type OAUTH --identity-provider MyIdp --client-id abc --client-secret - --scope "read write" -o myOrg --json
    
  4. Confirm results — Display updated server details

7. Delete MCP Server

When the user wants to remove a server registration:

  1. Verify target org

    sf config get target-org --json
    
  2. Get server details first — Show what will be deleted

    sf agent mcp get -i 0XSxx0000000001 -o myOrg --json
    
  3. Confirm deletion — Ask user:

    Are you sure you want to delete this MCP server?
    - Name: <name>
    - URL: <url>
    - This action is PERMANENT and cannot be undone.
    
    Confirm deletion? (yes/no)
    
  4. Delete the server

    sf agent mcp delete -i 0XSxx0000000001 -o myOrg --no-prompt --json
    
  5. Confirm deletion — Display success message

Command Reference

sf agent mcp create

Purpose: Register a new MCP server in the API Catalog

Required Parameters:

  • -n, --name <value> — Unique server name. It cannot contain spaces, has to start with a letter and can only contain alphanumeric characters.
  • -o, --target-org <value> — Target org alias/username
  • --server-url <value> — MCP server endpoint URL

Optional Parameters:

  • --label <value> — Human-readable display name
  • --description <value> — Server description
  • --auth-type <OAUTH|NO_AUTH> — Default: NO_AUTH
  • --identity-provider <value> — OAuth IdP (required with OAUTH)
  • --client-id <value> — OAuth client ID (required with OAUTH)
  • --client-secret <value> — OAuth secret (use - for stdin)
  • --scope <value> — OAuth scope (required with OAUTH)
  • --api-version <value> — API version override
  • --json — JSON output (ALWAYS use this)

Response Structure:

create returns BOTH the discovered assets and the newly created server object (result keys: assets, server). Each asset item has exactly these keys: active, availableAsAgentAction, description, id, kind, label, name, status. On creation the assets are discovered but not yet registered, so each asset's id is null and its status is NOT_REGISTERED (activate them with agent mcp asset replace). The server's audit fields (createdById, createdDate, lastModifiedById, lastModifiedDate) also come back null in the immediate create response.

{
  "status": 0,
  "result": {
    "assets": [
      {
        "active": false,
        "availableAsAgentAction": false,
        "description": "Gets all tickets for driver...",
        "id": null,
        "kind": "MCP_TOOL",
        "label": "getTickets",
        "name": "McpTool__getTickets",
        "status": "NOT_REGISTERED"
      }
    ],
    "server": {
      "authorization": {
        "authType": "NO_AUTH",
        "identityProvider": null,
        "scope": null
      },
      "createdById": null,
      "createdDate": null,
      "description": "temp server for output reconciliation",
      "id": "0LeSB000000Jp5F",
      "label": "Recon Test",
      "lastModifiedById": null,
      "lastModifiedDate": null,
      "name": "reconTestServer",
      "serverUrl": "https://mcp.example.com/mcp",
      "status": "ACTIVE",
      "type": "EXTERNAL"
    }
  },
  "warnings": ["This command is currently in developer preview..."]
}

To extract the server ID after create, read result.server.id (NOT result.id).

Error Response:

Errors are emitted with a non-zero status/exitCode (e.g. 4) and include name, message, context, stack, cause, code, and commandName fields:

{
  "name": "GetMcpServerFailed",
  "message": "Failed to get MCP server: MCP server not found",
  "exitCode": 4,
  "context": "ApiCatalogMcpServerGet",
  "code": "GetMcpServerFailed",
  "status": 4,
  "commandName": "ApiCatalogMcpServerGet",
  "warnings": ["This command is currently in developer preview..."]
}

sf agent mcp list

Purpose: List all registered MCP servers

Required Parameters:

  • -o, --target-org <value> — Target org

Optional Parameters:

  • --label <value> — Filter by label
  • --type <EXTERNAL> — Filter by type
  • --status <ACTIVE|DISCONNECTED> — Filter by status
  • --json — JSON output

Response Structure:

The server array is nested under result.mcpServers (NOT directly under result). Each server carries a nested authorization object and bare createdById/lastModifiedById string IDs.

{
  "status": 0,
  "result": {
    "mcpServers": [
      {
        "authorization": {
          "authType": "NO_AUTH",
          "identityProvider": null,
          "scope": null
        },
        "createdById": "005SB00000iwVrhYAE",
        "createdDate": "2026-07-22T21:07:55Z",
        "description": null,
        "id": "0LeSB000000JoFd",
        "label": "ticketsMCP",
        "lastModifiedById": "005SB00000iwVrhYAE",
        "lastModifiedDate": "2026-07-22T21:09:22Z",
        "name": "ticketsMCP",
        "serverUrl": "https://mcp.example.com/tickets/mcp",
        "status": "ACTIVE",
        "type": "EXTERNAL"
      }
    ]
  },
  "warnings": ["This command is currently in developer preview..."]
}

sf agent mcp get

Purpose: Get details on a specific MCP server

Required Parameters:

  • -i, --mcp-server-id <value> — Server ID
  • -o, --target-org <value> — Target org

Optional Parameters:

  • --json — JSON output

Response Structure:

Auth details are nested under authorization (authType, identityProvider, scope). For OAUTH servers identityProvider holds the token endpoint URL. There is NO clientId field in the response, and audit info is exposed as bare createdById/lastModifiedById string IDs (not createdBy objects with names).

{
  "status": 0,
  "result": {
    "authorization": {
      "authType": "OAUTH",
      "identityProvider": "https://mcp.example.com/auth/token",
      "scope": "read"
    },
    "createdById": "005SB00000iwVrhYAE",
    "createdDate": "2026-07-15T23:38:04Z",
    "description": null,
    "id": "0LeSB000000Jk0j",
    "label": "TestHKWithAuth",
    "lastModifiedById": "005SB00000iwVrhYAE",
    "lastModifiedDate": "2026-07-15T23:40:43Z",
    "name": "TestHKWithAuth",
    "serverUrl": "https://mcp.example.com/test/mcp",
    "status": "ACTIVE",
    "type": "EXTERNAL"
  },
  "warnings": ["This command is currently in developer preview..."]
}

sf agent mcp update

Purpose: Update an existing MCP server

Required Parameters:

  • -i, --mcp-server-id <value> — Server ID
  • -o, --target-org <value> — Target org
  • At least one of --label, --description, --server-url, or --auth-type. Supplying none errors with NoFields (exit code 1): "No fields to update. Provide at least one of --label, --description, --server-url, or --auth-type."

Optional Parameters:

  • --label <value> — New label
  • --description <value> — New description
  • --server-url <value> — New URL
  • --auth-type <OAUTH|NO_AUTH> — New auth type
  • --identity-provider <value> — OAuth IdP
  • --client-id <value> — OAuth client ID
  • --client-secret <value> — OAuth secret (use -)
  • --scope <value> — OAuth scope
  • --json — JSON output

Response Structure:

update returns the FULL server object (same shape as get), not a partial subset.

⚠️ Observed preview-stage bug — not all updatable fields persist: In live testing against the preview CLI (sf 2.144.6, plugin-agent), only --description actually persisted. --label and --server-url updates returned status: 0 (apparent success) but the value was silently ignored — a follow-up get showed the old value unchanged, and the label in the update response echoed the server name rather than the requested label. Always verify update results with a follow-up get, and do not rely on --label or --server-url taking effect until this is fixed. (--auth-type was not re-verified in this pass.)

{
  "status": 0,
  "result": {
    "authorization": {
      "authType": "NO_AUTH",
      "identityProvider": null,
      "scope": null
    },
    "createdById": "005SB00000iwVrhYAE",
    "createdDate": "2026-07-23T21:16:03Z",
    "description": "updated desc",
    "id": "0LeSB000000Jp5F",
    "label": "reconTestServer",
    "lastModifiedById": "005SB00000iwVrhYAE",
    "lastModifiedDate": "2026-07-23T21:16:17Z",
    "name": "reconTestServer",
    "serverUrl": "https://mcp.example.com/tickets/mcp",
    "status": "ACTIVE",
    "type": "EXTERNAL"
  },
  "warnings": ["This command is currently in developer preview..."]
}

sf agent mcp delete

Purpose: Delete an MCP server

Required Parameters:

  • -i, --mcp-server-id <value> — Server ID
  • -o, --target-org <value> — Target org

Optional Parameters:

  • --no-prompt — Skip confirmation
  • --json — JSON output

Response Structure:

Returns only id and deleted — there is NO name field.

{
  "status": 0,
  "result": { "id": "0LeSB000000Jp5F", "deleted": true },
  "warnings": ["This command is currently in developer preview..."]
}

sf agent mcp fetch

Purpose: Fetch live assets from an MCP server

Required Parameters:

  • -i, --mcp-server-id <value> — Server ID
  • -o, --target-org <value> — Target org

Optional Parameters:

  • --json — JSON output

Response Structure:

Assets are returned directly under result.assets — there is NO serverId or serverName field. Each asset carries active, availableAsAgentAction, description, id, kind, label, name, and a status field (IN_SYNC for registered assets, NOT_REGISTERED for freshly discovered ones).

Observed assets do NOT include inputSchema, outputSchema, or annotations — those fields were not returned by the live server. Do not rely on them being present. Descriptions may contain HTML entities (e.g. &#39; for ').

{
  "status": 0,
  "result": {
    "assets": [
      {
        "active": true,
        "availableAsAgentAction": true,
        "description": "Gets all tickets for driver using their driver&#39;s license id...",
        "id": "1XOSB0000008riJ",
        "kind": "MCP_TOOL",
        "label": "getTickets",
        "name": "McpTool__getTickets",
        "status": "IN_SYNC"
      },
      {
        "active": true,
        "availableAsAgentAction": true,
        "description": "Evaluates whether a ticket should be waived based on a reason...",
        "id": "1XOSB0000008riI",
        "kind": "MCP_TOOL",
        "label": "disputeTicket",
        "name": "McpTool__disputeTicket",
        "status": "IN_SYNC"
      }
    ]
  },
  "warnings": ["This command is currently in developer preview..."]
}

sf agent mcp asset list

Purpose: List the current asset allowlist for a server

Required Parameters:

  • -i, --mcp-server-id <value> — Server ID
  • -o, --target-org <value> — Target org

Optional Parameters:

  • --json — JSON output

Response Structure:

Assets are returned directly under result.assets — there is NO serverId field. Each asset has exactly these keys: active, availableAsAgentAction, description, id, kind, label, name. Note: unlike fetch, asset list does NOT include a status field on each asset.

Important: asset list reflects only registered assets. Immediately after create, before any asset replace, this returns an empty set ("assets": []) even though the server advertises assets — because the assets are discovered but not yet registered. Use fetch to see advertised (but unregistered) assets, and asset replace to register/activate them.

{
  "status": 0,
  "result": {
    "assets": [
      {
        "active": true,
        "availableAsAgentAction": true,
        "description": "Evaluates whether a ticket should be waived...",
        "id": "1XOSB0000008riI",
        "kind": "MCP_TOOL",
        "label": "disputeTicket",
        "name": "McpTool__disputeTicket"
      },
      {
        "active": true,
        "availableAsAgentAction": true,
        "description": "Gets all tickets for driver...",
        "id": "1XOSB0000008riJ",
        "kind": "MCP_TOOL",
        "label": "getTickets",
        "name": "McpTool__getTickets"
      }
    ]
  },
  "warnings": ["This command is currently in developer preview..."]
}

sf agent mcp asset replace

Purpose: Replace the full asset allowlist for a server

Required Parameters:

  • -i, --mcp-server-id <value> — Server ID
  • -o, --target-org <value> — Target org
  • Either --assets <value> OR --assets-file <value>

Optional Parameters:

  • --assets <value> — JSON string or - for stdin. Mutually exclusive with --assets-file (supplying both errors with exit code 2).
  • --assets-file <value> — Path to JSON file. Mutually exclusive with --assets. A missing file path errors with exit code 2 before any API call.
  • --json — JSON output

Asset Payload Format:

Each asset item may include id, name, label, description, active, and kind (per the command help). In practice name + active is sufficient to set the allowlist; the other fields are optional. The payload accepts either an array or an object with an assets key, supplied inline via --assets, from stdin via --assets -, or from a file via --assets-file.

Array format:

[
  { "name": "McpTool__add", "active": true },
  { "name": "McpTool__subtract", "active": false }
]

Object format:

{
  "assets": [{ "name": "McpTool__add", "active": true }]
}

Response Structure:

Returns the full resulting asset set under result.assets (same shape as asset list) — there is NO serverId or assetsUpdated field. Each asset in the response is a full asset object (active, availableAsAgentAction, description, id, kind, label, name), not just the {name, active} pairs sent in the request payload.

The response lists ALL of the server's assets, not only those in your payload. Any advertised asset omitted from the payload is returned with active: false (this is the "full replacement" semantics — omission = deactivation). For example, sending a payload with just getTickets: true against a 3-asset server returns all three assets: getTickets active, and the two omitted ones as active: false. After a replace, previously-unregistered assets now have real (non-null) ids.

{
  "status": 0,
  "result": {
    "assets": [
      {
        "active": false,
        "availableAsAgentAction": false,
        "description": "Evaluates whether a ticket should be waived...",
        "id": "1XOSB0000008rok",
        "kind": "MCP_TOOL",
        "label": "disputeTicket",
        "name": "McpTool__disputeTicket"
      },
      {
        "active": true,
        "availableAsAgentAction": true,
        "description": "Gets all tickets for driver...",
        "id": "1XOSB0000008rol",
        "kind": "MCP_TOOL",
        "label": "getTickets",
        "name": "McpTool__getTickets"
      }
    ]
  },
  "warnings": ["This command is currently in developer preview..."]
}

Concepts

Asset Kinds

Kind Description Use Case
MCP_TOOL Executable function/action Agent can invoke tools to perform operations
MCP_PROMPT Reusable prompt template Agent can use prompts for structured generation
MCP_RESOURCE Data source or endpoint Agent can read resources for context

Server Status

Status Meaning Action
ACTIVE Server is reachable and responding Normal operation
DISCONNECTED Server is unreachable or not responding Check URL, auth, network

Asset Activation States

State Meaning Visibility
active: true Asset is whitelisted and available Available to agents
active: false Asset is fetched but not whitelisted Not available to agents
Not in allowlist Asset exists on server but not tracked Not available to agents

The availableAsAgentAction boolean mirrors whether an active asset is exposed as an agent action.

Asset Sync Status (fetch only)

The fetch command returns a status field on each asset (the asset list command does NOT):

Status Meaning
IN_SYNC Asset is registered in the catalog and matches the live server
NOT_REGISTERED Asset was discovered on the server but is not yet registered (its id is null) — e.g. immediately after create before an asset replace

Authentication Types

NO_AUTH — No authentication required. The MCP server is publicly accessible or uses a different auth mechanism (e.g., IP allowlisting, API gateway).

sf agent mcp create -n PublicServer --server-url https://public.mcp.example.com/mcp --auth-type NO_AUTH -o myOrg --json

OAUTH — OAuth 2.0 client credentials flow. Requires identity provider, client ID, client secret, and scope.

echo "my-secret" | sf agent mcp create \
  -n SecureServer \
  --server-url https://secure.mcp.example.com/mcp \
  --auth-type OAUTH \
  --identity-provider MyIdentityProvider \
  --client-id abc123xyz \
  --client-secret - \
  --scope "read write execute" \
  -o myOrg \
  --json

OAuth parameters: --identity-provider (named credential or external IdP), --client-id, --client-secret (use - for stdin), --scope (space-separated).

Tool Metadata Fields

Required: name (e.g., McpTool__add), kind, description.

Optional: inputSchema (JSON Schema for inputs), outputSchema (JSON Schema for outputs), annotations (custom metadata). Common annotations: category, rateLimit, cost, latency, destructive, requiresAuth.

Security Best Practices

Client Secret Handling

  • NEVER pass --client-secret directly on the command line (visible in shell history):
    # ❌ NEVER
    sf agent mcp create -n Server --server-url https://mcp.example.com --auth-type OAUTH --client-secret "my-secret" -o myOrg
    
  • ALWAYS use stdin piping:
    # ✅ stdin
    echo "my-secret" | sf agent mcp create -n Server --server-url https://mcp.example.com --auth-type OAUTH --client-secret - -o myOrg --json
    # ✅ file piping
    cat /secure/location/secret.txt | sf agent mcp create -n Server --server-url https://mcp.example.com --auth-type OAUTH --client-secret - -o myOrg --json
    

Credential Storage

  • Warn users that credentials are stored in the Salesforce org.
  • Recommend org-specific service accounts, not personal credentials.

Server URL Validation

  • Verify HTTPS for production servers.
  • Warn if using HTTP for non-local development.

Tool Review Checklist

Before activating a tool, review:

  1. Destructive operations — Does it delete, update, or modify data? Execute code/commands? Have file system access?
  2. Data exposure — Does it access sensitive data (PII, credentials)? Query databases directly? Have broad read permissions?
  3. Rate limits — Are there rate limit annotations? Could it cause DoS if overused? Cost implications?
  4. Authentication — Does it require additional auth? Impersonate users? Have elevated privileges?
  5. Scope — Is the tool's purpose clear? Narrowly scoped or overly broad? Does it align with agent use cases?

Production org deployment:

⚠️  WARNING: You are deploying to a PRODUCTION org.
    This will activate MCP tools in a live environment.
    Ensure all tools have been reviewed and tested.

    Continue? (yes/no)

Destructive tool activation:

⚠️  CAUTION: This tool has destructive capabilities.
    Tool: McpTool__deleteRecord
    Description: Delete records from the database
    Annotations: {"destructive": true, "scope": "all_records"}

    Are you sure you want to activate this tool? (yes/no)

Broad permissions:

⚠️  NOTICE: This tool has broad data access.
    Tool: McpResource__customerData
    Description: Access to all customer records

    Consider limiting scope or using field-level security.
    Activate anyway? (yes/no)

Error Handling

Error Likely message Resolution
No target org set No default org found Ask user to run sf config set target-org <alias>
Server not found MCP server not found Verify server ID with sf agent mcp list
Connection refused Failed to connect to <url>: Connection refused Verify URL, network connectivity, ensure server is running
Invalid OAuth credentials OAuth authentication failed: Invalid client credentials Verify client ID, secret, identity provider, scope
Duplicate name Failed to create MCP server: API Catalog External service registration with name: <name> already exists. Use a new name or edit the existing one (name CreateMcpServerFailed, exit code 4) Use a unique name or update the existing server
Unparseable asset JSON The assets input does not contain valid JSON. (name InvalidJson, exit code 1) Fix the JSON syntax of the --assets/stdin payload
Wrong asset JSON shape The assets input must be a JSON array of asset items or an object with an "assets" array. (name InvalidShape, exit code 1) Use an array of asset items or { "assets": [...] }
Asset not found Failed to replace MCP server assets: API Catalog DataSource MCP DataSource Asset <name> not found on server <id> (name ReplaceMcpServerAssetsFailed, exit code 4) Fetch fresh assets with sf agent mcp fetch
Server disconnected Cannot update assets: Server is DISCONNECTED Check server status, verify URL and auth
Deactivating an exposed Agent Action Failed to replace MCP server assets: Cannot deactivate asset(s) [<name>]: each is currently exposed as an Agent Action and must remain active for the lifetime of the server. Delete the Agent Action first, or delete the server with DELETE /mcp-servers/{id}. (name ReplaceMcpServerAssetsFailed, exit code 4) Delete the Agent Action referencing the tool first, or delete the server

Edge Cases

Empty asset list ("assets": []) — The server exposes nothing, is newly registered and not yet indexed, or fetch errored. Offer to check server status, retry fetch, or update server config.

All tools declined/skipped — No assets will be activated. Offer to review the tools again, fetch fresh assets, or cancel and keep current state.

Partial OAuth configuration — If some but not all OAuth params are provided, list the required set (--identity-provider, --client-id, --client-secret, --scope) and which are missing.

Server ID ambiguity — If the user refers to a server by name, resolve to an ID via sf agent mcp list. If multiple names match, present the matches and ask which ID to use.

Windows Compatibility

  • Python command: Use python instead of python3.
  • Stdin piping (PowerShell): "secret" | sf agent mcp create ... --client-secret -

PowerShell — pass assets inline or via stdin:

$assets = @{
  assets = @(
    @{ name = "McpTool__add"; active = $true },
    @{ name = "McpTool__subtract"; active = $false }
  )
} | ConvertTo-Json -Depth 10 -Compress

$assets | sf agent mcp asset replace -i 0XSxx0000000001 --assets - -o myOrg --json

cmd — create server (no auth):

sf agent mcp create ^
  -n MyServer ^
  --server-url https://mcp.example.com/mcp ^
  -o myOrg ^
  --json

For OAuth with a client secret, use PowerShell or Git Bash for stdin piping.

Complete Workflow Example

Scenario: Register and whitelist a weather MCP server

# 1. Verify target org
sf config get target-org --json

# 2. Create MCP server (no auth)
sf agent mcp create \
  -n WeatherServer \
  --server-url https://weather.mcp.example.com/mcp \
  --label "Weather MCP Server" \
  --description "Provides current weather and forecasts" \
  -o myOrg \
  --json
# Extract server ID from response: 0XSxx0000000123

# 3. Fetch available tools
sf agent mcp fetch -i 0XSxx0000000123 -o myOrg --json

# 4. Review each tool interactively (handled by Claude — see Workflow 4)
#    Tool getCurrentWeather → yes, Tool getForecast → yes

# 5. Build allowlist and replace it (pipe payload via stdin — no temp file)
echo '{
  "assets": [
    {"name": "McpTool__getCurrentWeather", "active": true},
    {"name": "McpTool__getForecast", "active": true}
  ]
}' | sf agent mcp asset replace -i 0XSxx0000000123 --assets - -o myOrg --json

# 6. Verify activation
sf agent mcp asset list -i 0XSxx0000000123 -o myOrg --json

Scenario: Register an OAuth-authenticated server

# Store client secret securely, then pipe via stdin
echo "my-oauth-secret" | sf agent mcp create \
  -n OAuthServer \
  --server-url https://secure.mcp.example.com/mcp \
  --auth-type OAUTH \
  --identity-provider MyIdentityProvider \
  --client-id abc123xyz \
  --client-secret - \
  --scope "read write execute" \
  -o myOrg \
  --json

Quick Reference

Command Purpose
sf agent mcp create Register a new MCP server
sf agent mcp list List all registered servers
sf agent mcp get Get details on a specific server
sf agent mcp update Update server configuration
sf agent mcp delete Remove server registration
sf agent mcp fetch Fetch live assets from server
sf agent mcp asset list List current asset allowlist
sf agent mcp asset replace Update asset allowlist (full replacement)

Troubleshooting

Server shows DISCONNECTED status

  1. Check server URL is accessible: curl -v <server-url>
  2. Verify authentication credentials (if OAuth)
  3. Check server logs for connection errors
  4. Try updating the server URL: sf agent mcp update -i <id> --server-url <new-url>

Tools not appearing after whitelisting

  1. Verify asset activation: sf agent mcp asset list -i <id>
  2. Check tools are marked active: true
  3. Fetch fresh assets: sf agent mcp fetch -i <id>
  4. Verify server is ACTIVE: sf agent mcp get -i <id>

"Command not found: agent mcp"

  • The sf agent mcp plugin may not be installed
  • Check SF CLI version: sf version; update with sf update
  • Verify plugin availability: sf plugins