---
schema_version: "1"
id: eaf6bb19787ca36e222105d8e310f33dbccb4e344ed9f249d6fcfc0d8dca38d4
title: "Example: Register and Manage an External MCP Server"
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/api-catalog/api-catalog-connectapi/guides/manage-external-mcp-servers.md
canonical_url: https://developer.salesforce.com/docs/platform/api-catalog-connectapi/guide/manage-external-mcp-servers.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: 4790e8f68fa4df7d359f8d79e2a314e563cb54f7f27528a75364e81ec2cf65ee
products:
  - API Catalog Connect REST API
---
# Example: Register and Manage an External MCP Server

This example registers an Acme Payments MCP server in API Catalog, reviews its discovered tools, adds tools to the allowlist, refreshes the list when the remote server changes, and updates the server's credentials. Use these steps to automate external MCP server management through the API Catalog Connect REST API.

For background on the UI workflow, see [Register External MCP Servers in API Catalog](https://help.salesforce.com/s/articleView?id=platform.api_catalog_manage_manual_external_mcp_servers.htm&type=5).

## 1. Register the MCP Server

`POST /api-catalog/mcp-servers`

Register the server by providing its name, URL, and credentials. Salesforce connects to the remote endpoint, performs an initial fetch of available tools and returns the discovered assets in the response so you can review them before adding any to the allowlist.

Set `type` to `EXTERNAL`. For OAuth 2.0 authentication, include the `authorization` block with `authType`, `identityProvider`, `clientId`, `clientSecret`, and `scope`. For servers that require no authentication, set `authType` to `NO_AUTH` and omit the other authorization fields.

Request body:

```json
{
  "name": "AcmePaymentsMcp",
  "label": "Acme Payments MCP Server",
  "description": "Connects to Acme Payments MCP server for payment processing tools.",
  "serverUrl": "https://mcp.acmepayments.example.com/http",
  "type": "EXTERNAL",
  "authorization": {
    "authType": "OAUTH",
    "identityProvider": "https://auth.acmepayments.example.com/oauth2/token",
    "scope": "payments:write payments:refund",
    "clientId": "<your-client-id>",
    "clientSecret": "<your-client-secret>"
  }
}
```

Response:

```json
{
  "server": {
    "id": "0MxB000000000001AAA",
    "name": "AcmePaymentsMcp",
    "label": "Acme Payments MCP Server",
    "description": "Connects to Acme Payments MCP server for payment processing tools.",
    "serverUrl": "https://mcp.acmepayments.example.com/http",
    "type": "EXTERNAL",
    "status": "ACTIVE",
    "authorization": {
      "authType": "OAUTH",
      "identityProvider": "https://auth.acmepayments.example.com/oauth2/token",
      "scope": "payments:write payments:refund"
    },
    "createdById": "005000000000001AAA",
    "createdDate": "2026-08-03T12:00:00Z",
    "lastModifiedById": "005000000000001AAA",
    "lastModifiedDate": "2026-08-03T12:00:00Z"
  },
  "assets": [
    {
      "name": "create_order",
      "label": "Create Order",
      "description": "Creates an Acme Payments order for a payment transaction.",
      "kind": "MCP_TOOL",
      "status": "NOT_REGISTERED",
      "active": false,
      "availableAsAgentAction": false
    },
    {
      "name": "capture_payment",
      "label": "Capture Payment",
      "description": "Captures an authorized payment for an order.",
      "kind": "MCP_TOOL",
      "status": "NOT_REGISTERED",
      "active": false,
      "availableAsAgentAction": false
    },
    {
      "name": "refund_payment",
      "label": "Refund Payment",
      "description": "Issues a full or partial refund for a captured payment.",
      "kind": "MCP_TOOL",
      "status": "NOT_REGISTERED",
      "active": false,
      "availableAsAgentAction": false,
      "securityWarning": "Tool description contains characters that may indicate a tool poisoning risk. Review before adding to the allowlist."
    }
  ]
}
```

Grab the `id` value from `server.id` in the response. Use it in all subsequent requests.

## 2. Review Discovered Tools

This step requires no new request. Review the `assets` array in the Step 1 response.

Each asset has a `status` of `NOT_REGISTERED`, meaning Salesforce found the tool on the remote server but hasn't yet added it to the allowlist.

When an asset includes a `securityWarning` field, review the tool description carefully before proceeding. The warning indicates that the description contains characters that can signal a tool poisoning risk—for example, invisible characters or mixed scripts that manipulate an Agentforce agent into unexpected behavior. This corresponds to the Risk Assessment panel shown during registration in the UI.

In this example, `refund_payment` includes a security warning. Review the tool description and confirm that you accept the risk before adding it to the allowlist in the next step.

## 3. Add Tools to the Allowlist

`PUT /api-catalog/mcp-servers/0MxB000000000001AAA/assets`

Submit the tools you want to add, with `active` set to `true`. This endpoint uses replace semantics: The assets you include become the full allowlist. Assets currently on the allowlist that are omitted from the request body are removed.

Because assets discovered at registration time haven't been assigned local record IDs yet, identify them by `name`. In this example, all three tools are added to the allowlist.

Request body:

```json
{
  "assets": [
    {
      "name": "create_order",
      "active": true
    },
    {
      "name": "capture_payment",
      "active": true
    },
    {
      "name": "refund_payment",
      "active": true
    }
  ]
}
```

Response:

```json
{
  "assets": [
    {
      "id": "0TlB000000000001AAA",
      "name": "create_order",
      "label": "Create Order",
      "description": "Creates an Acme Payments order for a payment transaction.",
      "kind": "MCP_TOOL",
      "active": true,
      "availableAsAgentAction": false
    },
    {
      "id": "0TlB000000000002AAA",
      "name": "capture_payment",
      "label": "Capture Payment",
      "description": "Captures an authorized payment for an order.",
      "kind": "MCP_TOOL",
      "active": true,
      "availableAsAgentAction": false
    },
    {
      "id": "0TlB000000000003AAA",
      "name": "refund_payment",
      "label": "Refund Payment",
      "description": "Issues a full or partial refund for a captured payment.",
      "kind": "MCP_TOOL",
      "active": true,
      "availableAsAgentAction": false
    }
  ]
}
```

## 4. View the Allowlisted Tools

`GET /api-catalog/mcp-servers/0MxB000000000001AAA/assets`

Retrieve the current allowlist for the server.

Response:

```json
{
  "assets": [
    {
      "id": "0TlB000000000001AAA",
      "name": "create_order",
      "label": "Create Order",
      "description": "Creates an Acme Payments order for a payment transaction.",
      "kind": "MCP_TOOL",
      "active": true,
      "availableAsAgentAction": false
    },
    {
      "id": "0TlB000000000002AAA",
      "name": "capture_payment",
      "label": "Capture Payment",
      "description": "Captures an authorized payment for an order.",
      "kind": "MCP_TOOL",
      "active": true,
      "availableAsAgentAction": false
    },
    {
      "id": "0TlB000000000003AAA",
      "name": "refund_payment",
      "label": "Refund Payment",
      "description": "Issues a full or partial refund for a captured payment.",
      "kind": "MCP_TOOL",
      "active": true,
      "availableAsAgentAction": false
    }
  ]
}
```

## 5. Fetch Current Tools from the Server

`POST /api-catalog/mcp-servers/0MxB000000000001AAA/fetch`

Contact the remote MCP server to retrieve its latest asset manifest. This request is stateless: It returns a merged view of remote assets and locally stored overrides but doesn't change the allowlist. Use the response to identify drift before deciding which tools to add or remove.

The `status` field on each asset describes its sync state:

- `IN_SYNC` — on the allowlist and matches the remote server's current definition.
- `OUT_OF_SYNC` — on the allowlist, but the remote server's definition has changed. The `description` field reflects the newer remote value.
- `NOT_REGISTERED` — the remote server advertises this asset, but it hasn't been added to the allowlist yet.
- `ORPHANED` — on the allowlist, but the remote server no longer advertises it.

Response:

```json
{
  "assets": [
    {
      "name": "create_order",
      "label": "Create Order",
      "description": "Creates an Acme Payments order for a payment transaction.",
      "kind": "MCP_TOOL",
      "status": "IN_SYNC",
      "active": true,
      "availableAsAgentAction": false
    },
    {
      "name": "capture_payment",
      "label": "Capture Payment",
      "description": "Captures an authorized payment for an order.",
      "kind": "MCP_TOOL",
      "status": "IN_SYNC",
      "active": true,
      "availableAsAgentAction": false
    },
    {
      "name": "refund_payment",
      "label": "Refund Payment",
      "description": "Issues a full or partial refund. Accepts partial amounts.",
      "kind": "MCP_TOOL",
      "status": "OUT_OF_SYNC",
      "active": true,
      "availableAsAgentAction": false
    },
    {
      "name": "list_transactions",
      "label": "List Transactions",
      "description": "Lists recent payment transactions for an account.",
      "kind": "MCP_TOOL",
      "status": "NOT_REGISTERED",
      "active": false,
      "availableAsAgentAction": false
    }
  ]
}
```

In this example, `refund_payment` is `OUT_OF_SYNC` because its description changed on the remote server, and `list_transactions` is a new tool not yet on the allowlist. The next step updates the allowlist to reflect these changes.

## 6. Remove a Tool from the Allowlist

`PUT /api-catalog/mcp-servers/0MxB000000000001AAA/assets`

To remove a tool, send a `PUT` request that includes every tool you want to keep. Assets omitted from the request body are removed from the allowlist.

In this example, the request removes `refund_payment` and adds the new `list_transactions` tool from Step 5. `create_order` and `capture_payment` are included to keep them on the allowlist.

Request body:

```json
{
  "assets": [
    {
      "name": "create_order",
      "active": true
    },
    {
      "name": "capture_payment",
      "active": true
    },
    {
      "name": "list_transactions",
      "active": true
    }
  ]
}
```

Response:

```json
{
  "assets": [
    {
      "id": "0TlB000000000001AAA",
      "name": "create_order",
      "label": "Create Order",
      "description": "Creates an Acme Payments order for a payment transaction.",
      "kind": "MCP_TOOL",
      "active": true,
      "availableAsAgentAction": false
    },
    {
      "id": "0TlB000000000002AAA",
      "name": "capture_payment",
      "label": "Capture Payment",
      "description": "Captures an authorized payment for an order.",
      "kind": "MCP_TOOL",
      "active": true,
      "availableAsAgentAction": false
    },
    {
      "id": "0TlB000000000004AAA",
      "name": "list_transactions",
      "label": "List Transactions",
      "description": "Lists recent payment transactions for an account.",
      "kind": "MCP_TOOL",
      "active": true,
      "availableAsAgentAction": false
    }
  ]
}
```

## 7. Update Server Settings

`PUT /api-catalog/mcp-servers/0MxB000000000001AAA`

Update the server's label, description, URL, or credentials. Top-level fields (`label`, `description`, `serverUrl`) use PATCH semantics: Only fields you include are updated. The `authorization` block uses replace semantics: Including it replaces the entire block. The `name` and `type` fields are immutable after registration.

In this example, the server is updated from sandbox to production credentials.

Request body:

```json
{
  "label": "Acme Payments MCP Server (Production)",
  "description": "Connects to Acme Payments production MCP server for payment processing.",
  "serverUrl": "https://mcp.acmepayments.example.com/http",
  "authorization": {
    "authType": "OAUTH",
    "identityProvider": "https://auth.acmepayments.example.com/oauth2/token",
    "scope": "payments:write payments:refund",
    "clientId": "<your-production-client-id>",
    "clientSecret": "<your-production-client-secret>"
  }
}
```

Response:

```json
{
  "id": "0MxB000000000001AAA",
  "name": "AcmePaymentsMcp",
  "label": "Acme Payments MCP Server (Production)",
  "description": "Connects to Acme Payments production MCP server for payment processing.",
  "serverUrl": "https://mcp.acmepayments.example.com/http",
  "type": "EXTERNAL",
  "status": "ACTIVE",
  "authorization": {
    "authType": "OAUTH",
    "identityProvider": "https://auth.acmepayments.example.com/oauth2/token",
    "scope": "payments:write payments:refund"
  },
  "createdById": "005000000000001AAA",
  "createdDate": "2026-08-03T12:00:00Z",
  "lastModifiedById": "005000000000001AAA",
  "lastModifiedDate": "2026-08-03T14:00:00Z"
}
```
