Connect a Salesforce Hosted MCP Server
Salesforce can host an MCP server for an org, exposing tools such as SOQL queries directly from Salesforce data. This guide covers the Arcade-side setup for connecting a Salesforce Hosted Server as a remote MCP server, plus the handful of Salesforce settings that most commonly trip people up.
This guide is about connecting to a Salesforce Hosted Server. If you’re looking to call Salesforce APIs from your own instead, see the Arcade Salesforce toolkit.
Outcomes
Connect a Salesforce Hosted Server to Arcade and use its in gateways and SDKs.
You will Learn
- Which Salesforce External Client App settings matter for Arcade specifically, and why
- Configure the remote server’s OAuth 2.0 settings in Arcade
- Diagnose the most common setup mistakes from their error messages
Prerequisites
- An Arcade
- A Salesforce Hosted MCP Server , activated
- A Salesforce External Client App for the integration
Set up Salesforce
Follow Salesforce’s own guides to create your Hosted MCP Server , activate it , and create an External Client App (ECA) for it. A few settings on the ECA matter specifically for connecting to Arcade:
-
OAuth Scopes: select exactly two scopes.
mcp_api(“Access Salesforce hosted servers”). Salesforce’s guide lists this without explaining why it’s required. Without it, authorization succeeds, but every call fails with a 401.refresh_token/offline_access(“Perform requests at any time”). Salesforce combines these into one scope, so there’s no way to grant just one.
Don’t also select
api. It can trigger the same opaque-token failure as skipping the JWT setting below, even though authorization still looks successful. -
Issue JSON Web Token (JWT)-based access tokens for named (under Security). Salesforce’s guide doesn’t explain why this is needed.
Without it, Salesforce issues an opaque session token instead of a JWT, and the Hosted Server’s endpoint only validates JWTs. Every call fails with a bare
{"errors":[{"message":"Invalid token"}]}401, even though authorization otherwise looks successful. -
Require PKCE: leave this enabled (it’s on by default). Salesforce’s ECA guide doesn’t mention PKCE, but Arcade always uses it (RFC 7636, S256) when authorizing against a remote server.
-
Callback URL: set this once you have the redirect URI Arcade generates (see Add the redirect URI to your ECA below). A placeholder works for now.
Configure the remote server in Arcade
Register the server
Go to the MCP servers dashboard , click Add server, and enter a server ID and the Hosted Server’s URL (it looks like https://api.salesforce.com/platform/mcp/v1/custom/YourServerName).
Configure OAuth2 authorization
Open Advanced settings → OAuth2 authorization and enter:
-
Client ID / Client Secret: your ECA’s Consumer Key and Consumer Secret.
-
Authorization URL: leave this empty. Arcade discovers your org’s real authorization server automatically from the Hosted Server’s own metadata, and only requests the scopes that server actually needs (
mcp_api,refresh_token) — no manual scope deselection required later.Only set this manually if authorization still fails after ruling out the propagation delay in Add the redirect URI to your ECA below. If you do:
- Use the full OpenID Connect discovery URL for your org, not just the bare domain — your My Domain URL (Salesforce Setup → My Domain) with
/.well-known/openid-configurationappended. For example:https://acme-inc.my.salesforce.com/.well-known/openid-configuration. - Don’t use the ECA’s
/authorizepath orapi.salesforce.com. Neither serves that discovery document. - Expect the authorization prompt’s scope picker to list every scope your org supports, not just what this server needs. You’ll need to manually deselect everything except what your ECA grants.
- Use the full OpenID Connect discovery URL for your org, not just the bare domain — your My Domain URL (Salesforce Setup → My Domain) with
Salesforce Hosted Servers don’t support Dynamic Client Registration, so you must supply the Client ID and Secret manually. If you leave these blank, Arcade attempts Dynamic Client Registration and Salesforce rejects it.
Add the redirect URI to your ECA
Copy the redirect URI Arcade generated and set it as the ECA’s Callback URL. A new server registration gets its own unique redirect URI, so update the Callback URL again if you ever re-register the server under a new ID.
Salesforce takes a few minutes to propagate a Callback URL change. If
authorization fails with redirect_uri_mismatch right after saving it,
wait about 10 minutes and try again before troubleshooting further.
Authorize and confirm
Save the server to open the authorization prompt. Confirm mcp_api and refresh_token are checked, then complete the prompt.
Troubleshooting
- A 401 with
{"errors":[{"message":"Invalid token"}]}and no error code: your ECA isn’t issuing JWT-based access tokens. See Set up Salesforce. redirect_uri_mismatchright after updating the Callback URL: Salesforce hasn’t propagated the change yet. Wait about 10 minutes and retry before assuming a misconfiguration.- Authorization fails outright, and Authorization URL is set manually: a scope was selected on the authorization prompt that your ECA doesn’t actually grant. See Configure OAuth2 authorization.
- Authorization succeeds, but calls 401: the
mcp_apiscope is missing from either the ECA’s Selected Scopes or the scopes you approved during authorization, orapiis also selected on the ECA (see Set up Salesforce). - list is empty or every call fails: confirm the Hosted Server is activated .
- A setting change doesn’t seem to take effect: existing tokens don’t retroactively pick up new ECA settings. In Salesforce Setup, go to the affected ’s OAuth Apps list and revoke the existing grant, then re-authorize to get a fresh token.
Next steps
- Create an MCP Gateway to expose this server’s .
- Connect to MCP clients.