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.
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:
1{
2 "name": "AcmePaymentsMcp",
3 "label": "Acme Payments MCP Server",
4 "description": "Connects to Acme Payments MCP server for payment processing tools.",
5 "serverUrl": "https://mcp.acmepayments.example.com/http",
6 "type": "EXTERNAL",
7 "authorization": {
8 "authType": "OAUTH",
9 "identityProvider": "https://auth.acmepayments.example.com/oauth2/token",
10 "scope": "payments:write payments:refund",
11 "clientId": "<your-client-id>",
12 "clientSecret": "<your-client-secret>"
13 }
14}Response:
1{
2 "server": {
3 "id": "0MxB000000000001AAA",
4 "name": "AcmePaymentsMcp",
5 "label": "Acme Payments MCP Server",
6 "description": "Connects to Acme Payments MCP server for payment processing tools.",
7 "serverUrl": "https://mcp.acmepayments.example.com/http",
8 "type": "EXTERNAL",
9 "status": "ACTIVE",
10 "authorization": {
11 "authType": "OAUTH",
12 "identityProvider": "https://auth.acmepayments.example.com/oauth2/token",
13 "scope": "payments:write payments:refund"
14 },
15 "createdById": "005000000000001AAA",
16 "createdDate": "2026-08-03T12:00:00Z",
17 "lastModifiedById": "005000000000001AAA",
18 "lastModifiedDate": "2026-08-03T12:00:00Z"
19 },
20 "assets": [
21 {
22 "name": "create_order",
23 "label": "Create Order",
24 "description": "Creates an Acme Payments order for a payment transaction.",
25 "kind": "MCP_TOOL",
26 "status": "NOT_REGISTERED",
27 "active": false,
28 "availableAsAgentAction": false
29 },
30 {
31 "name": "capture_payment",
32 "label": "Capture Payment",
33 "description": "Captures an authorized payment for an order.",
34 "kind": "MCP_TOOL",
35 "status": "NOT_REGISTERED",
36 "active": false,
37 "availableAsAgentAction": false
38 },
39 {
40 "name": "refund_payment",
41 "label": "Refund Payment",
42 "description": "Issues a full or partial refund for a captured payment.",
43 "kind": "MCP_TOOL",
44 "status": "NOT_REGISTERED",
45 "active": false,
46 "availableAsAgentAction": false,
47 "securityWarning": "Tool description contains characters that may indicate a tool poisoning risk. Review before adding to the allowlist."
48 }
49 ]
50}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:
1{
2 "assets": [
3 {
4 "name": "create_order",
5 "active": true
6 },
7 {
8 "name": "capture_payment",
9 "active": true
10 },
11 {
12 "name": "refund_payment",
13 "active": true
14 }
15 ]
16}Response:
1{
2 "assets": [
3 {
4 "id": "0TlB000000000001AAA",
5 "name": "create_order",
6 "label": "Create Order",
7 "description": "Creates an Acme Payments order for a payment transaction.",
8 "kind": "MCP_TOOL",
9 "active": true,
10 "availableAsAgentAction": false
11 },
12 {
13 "id": "0TlB000000000002AAA",
14 "name": "capture_payment",
15 "label": "Capture Payment",
16 "description": "Captures an authorized payment for an order.",
17 "kind": "MCP_TOOL",
18 "active": true,
19 "availableAsAgentAction": false
20 },
21 {
22 "id": "0TlB000000000003AAA",
23 "name": "refund_payment",
24 "label": "Refund Payment",
25 "description": "Issues a full or partial refund for a captured payment.",
26 "kind": "MCP_TOOL",
27 "active": true,
28 "availableAsAgentAction": false
29 }
30 ]
31}4. View the Allowlisted Tools
GET /api-catalog/mcp-servers/0MxB000000000001AAA/assets
Retrieve the current allowlist for the server.
Response:
1{
2 "assets": [
3 {
4 "id": "0TlB000000000001AAA",
5 "name": "create_order",
6 "label": "Create Order",
7 "description": "Creates an Acme Payments order for a payment transaction.",
8 "kind": "MCP_TOOL",
9 "active": true,
10 "availableAsAgentAction": false
11 },
12 {
13 "id": "0TlB000000000002AAA",
14 "name": "capture_payment",
15 "label": "Capture Payment",
16 "description": "Captures an authorized payment for an order.",
17 "kind": "MCP_TOOL",
18 "active": true,
19 "availableAsAgentAction": false
20 },
21 {
22 "id": "0TlB000000000003AAA",
23 "name": "refund_payment",
24 "label": "Refund Payment",
25 "description": "Issues a full or partial refund for a captured payment.",
26 "kind": "MCP_TOOL",
27 "active": true,
28 "availableAsAgentAction": false
29 }
30 ]
31}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. Thedescriptionfield 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:
1{
2 "assets": [
3 {
4 "name": "create_order",
5 "label": "Create Order",
6 "description": "Creates an Acme Payments order for a payment transaction.",
7 "kind": "MCP_TOOL",
8 "status": "IN_SYNC",
9 "active": true,
10 "availableAsAgentAction": false
11 },
12 {
13 "name": "capture_payment",
14 "label": "Capture Payment",
15 "description": "Captures an authorized payment for an order.",
16 "kind": "MCP_TOOL",
17 "status": "IN_SYNC",
18 "active": true,
19 "availableAsAgentAction": false
20 },
21 {
22 "name": "refund_payment",
23 "label": "Refund Payment",
24 "description": "Issues a full or partial refund. Accepts partial amounts.",
25 "kind": "MCP_TOOL",
26 "status": "OUT_OF_SYNC",
27 "active": true,
28 "availableAsAgentAction": false
29 },
30 {
31 "name": "list_transactions",
32 "label": "List Transactions",
33 "description": "Lists recent payment transactions for an account.",
34 "kind": "MCP_TOOL",
35 "status": "NOT_REGISTERED",
36 "active": false,
37 "availableAsAgentAction": false
38 }
39 ]
40}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:
1{
2 "assets": [
3 {
4 "name": "create_order",
5 "active": true
6 },
7 {
8 "name": "capture_payment",
9 "active": true
10 },
11 {
12 "name": "list_transactions",
13 "active": true
14 }
15 ]
16}Response:
1{
2 "assets": [
3 {
4 "id": "0TlB000000000001AAA",
5 "name": "create_order",
6 "label": "Create Order",
7 "description": "Creates an Acme Payments order for a payment transaction.",
8 "kind": "MCP_TOOL",
9 "active": true,
10 "availableAsAgentAction": false
11 },
12 {
13 "id": "0TlB000000000002AAA",
14 "name": "capture_payment",
15 "label": "Capture Payment",
16 "description": "Captures an authorized payment for an order.",
17 "kind": "MCP_TOOL",
18 "active": true,
19 "availableAsAgentAction": false
20 },
21 {
22 "id": "0TlB000000000004AAA",
23 "name": "list_transactions",
24 "label": "List Transactions",
25 "description": "Lists recent payment transactions for an account.",
26 "kind": "MCP_TOOL",
27 "active": true,
28 "availableAsAgentAction": false
29 }
30 ]
31}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:
1{
2 "label": "Acme Payments MCP Server (Production)",
3 "description": "Connects to Acme Payments production MCP server for payment processing.",
4 "serverUrl": "https://mcp.acmepayments.example.com/http",
5 "authorization": {
6 "authType": "OAUTH",
7 "identityProvider": "https://auth.acmepayments.example.com/oauth2/token",
8 "scope": "payments:write payments:refund",
9 "clientId": "<your-production-client-id>",
10 "clientSecret": "<your-production-client-secret>"
11 }
12}Response:
1{
2 "id": "0MxB000000000001AAA",
3 "name": "AcmePaymentsMcp",
4 "label": "Acme Payments MCP Server (Production)",
5 "description": "Connects to Acme Payments production MCP server for payment processing.",
6 "serverUrl": "https://mcp.acmepayments.example.com/http",
7 "type": "EXTERNAL",
8 "status": "ACTIVE",
9 "authorization": {
10 "authType": "OAUTH",
11 "identityProvider": "https://auth.acmepayments.example.com/oauth2/token",
12 "scope": "payments:write payments:refund"
13 },
14 "createdById": "005000000000001AAA",
15 "createdDate": "2026-08-03T12:00:00Z",
16 "lastModifiedById": "005000000000001AAA",
17 "lastModifiedDate": "2026-08-03T14:00:00Z"
18}