Skip to main content
← Back to Blog
2026-10-09 · 18 min readSalesforceAI Agents

Day 6/15 — Connect an AI Client to Salesforce via MCP

Today Claude meets your org. You add a hosted MCP server to claude.ai as a custom connector with your External Client App, connect Claude Code on port 38000, and ask your first read-only questions about Acme Global Tech.

Avnish Yadav
Avnish Yadav
Developer & Automation Builder
Day 6/15 — Connect an AI Client to Salesforce via MCP

Neha has twenty minutes before her call with Priya Sharma at Acme Global Tech. Until now her prep has meant four Salesforce tabs and a notes file. Today she wants to type one question into Claude, "tell me some basic information about the Acme Global Tech account", and get an answer drawn from Salesforce, limited to what she is allowed to see.

Arjun has done his part: the servers are active, and yesterday's External Client App has had its 30 minutes to settle. What is left happens on the client side, and it has a few traps: Claude offers three ways to handle OAuth and Salesforce documents only one, Claude Code has two routes of its own, and a wrong callback fails without saying much.

By the end of today you will have Claude connected to your org's hosted Model Context Protocol (MCP) servers, part of Salesforce Headless 360 (now called AIforce), in claude.ai, Claude Desktop and Claude Code, and you will have run your first read-only prompts about Acme Global Tech.

Where we are: on Day 4 you activated the hosted servers and copied their URLs, and on Day 5 you created the Claude MCP Test External Client App with three callbacks, two scopes, PKCE and JWT. You need its consumer key and your server URLs now.

Three Claude surfaces, two ways to connect

Salesforce's "Configure Claude" page covers the web and desktop apps together: "These setup steps apply to Claude.ai and the Claude Desktop app. Claude Code inherits the same connection, so after you add the connector, it's also available to Claude Code." In practice there are two ways in.

Surface How it connects Callback it uses
claude.ai (web) A custom connector you add by URL https://claude.ai/api/mcp/auth_callback
Claude Desktop The same connector, through the same account the same
Claude Code, route A Inherits the claude.ai connector when you log in with a claude.ai account the same
Claude Code, route B A server you add with claude mcp add, which runs its own sign-in on your machine http://localhost:38000/callback

The difference matters for sign-in. Claude's documentation says the hosted apps ("claude.ai on the web, Desktop, mobile, and Cowork") share one OAuth client, while "Claude Code doesn't use it: it runs its own OAuth flow on the user's machine ... and redirects to a loopback callback URL". That is why yesterday's app has two Claude callbacks.

Custom connectors work in "Free, Pro, Max, Team, and Enterprise plans". "On the Free plan, you can add one custom connector," so pick the server you want most in claude.ai. On Team and Enterprise plans, "An Owner adds the connector for the organization", and members then connect with their own Salesforce login.

For Claude Code, Salesforce's blog suggests the direct route "if you only have an Anthropic API key provisioned for you by your enterprise. Otherwise, we recommend setting up connectors in your Claude.ai account, then using them in Claude Code". I use both today: the connector for sobject-all in claude.ai, and a direct sobject-reads server in Claude Code, because a coding tool that can only read is a good default.

Salesforce in Claude is a different product

Since September 15, 2026, Salesforce has also been rolling out "Salesforce in Claude", part of the Claudeforce partnership. Its release note says "This beta is read only" and "Requires Claude Enterprise", and its setup has the admin turn on the beta Headless360 (H360) MCP Server. This series uses custom connectors instead: they work on every Claude plan, with the generally available servers.

Why you choose "Use your own OAuth client"

When you add a custom connector, claude.ai asks how to sign in and how to identify itself to the server's login. On 2026-10-04 the Add custom connector dialog offered:

  • Authentication: "Sign in now" (badge "Detected", selected by default), "Sign in when needed" and "No sign-in".
  • OAuth client: "Use Claude's published identity" (a Client ID Metadata Document), "Register automatically" (Dynamic Client Registration, also badged "Detected") and "Use your own OAuth client", with the fields "OAuth client ID" and "OAuth client secret (optional)".
  • An optional Request headers section ("Add header", up to four). Salesforce needs none.

Claude's documentation describes the third option: "enter a client ID you registered with the server. Leave the secret blank unless your authorization server requires one."

claude.ai marks "Register automatically" as Detected for Salesforce's server, which is tempting. I didn't use it. Salesforce's security guide says "Dynamic client registration is not supported. Administrators must explicitly create and configure External Client Apps", and its wiki adds that "MCP clients that only support DCR are not compatible with Salesforce's hosted MCP servers." More important, your own client is the Claude MCP Test app from Day 5: an identity you created and control, with PKCE, no secret, your policies and one place to revoke Claude's access. Salesforce's own Claude steps choose Use your own OAuth client with the consumer key, and so does this series.

claude.ai Add custom connector: Authentication options, OAuth client options with Use your own OAuth client selected, and Request headers

The secret stays blank because of the settings you chose yesterday. You unchecked both "Require secret" boxes, and Claude's documentation explains what happens next: "If a user leaves an optional client secret blank, Claude uses the client ID as a public client." PKCE does the work a secret would do.

Here is the whole connection, from adding the connector to the first tool call:

You add the connector; Claude sends you to Salesforce's login with a PKCE challenge; after you allow access, Claude exchanges the code for a JWT access token and uses it to list and call the server's tools
Every call after the token exchange carries Neha's token, so Salesforce runs it as Neha.

Steps 2 to 6 are the OAuth flow with PKCE from Day 5, with the login host taken from the metadata you read on Day 1. Steps 7 to 10 are MCP: Claude lists the server's tools, and later calls one with arguments the model chose.

Step by step: claude.ai and Claude Desktop

These steps follow Salesforce's "Configure Claude" page. Use the sobject-all Server URL you copied on Day 4. For a Developer Edition or production org it has this shape; sandbox and scratch org URLs contain /sandbox/:

https://api.salesforce.com/platform/mcp/v1/platform/sobject-all
  1. In claude.ai, click Customize in the left sidebar, then Connectors, then Add, and select Add custom connector. I did this on a Pro or Max plan. On a Team or Enterprise plan, an Owner does this under Organization settings → Connectors instead: select Add, then Custom, and choose Web if Claude asks for the connector type.
  2. Enter a name, Salesforce sobject-all, and the server URL. Click Continue.
  3. Leave Authentication on Sign in now. Under OAuth client, select Use your own OAuth client. In OAuth client ID, paste the Claude MCP Test consumer key. Leave OAuth client secret (optional) blank and add no request headers.
  4. Finish the dialog. When Salesforce's login opens (if it doesn't, click Connect next to the connector), log in as your test user. Salesforce shows Allow Access? with an orange Security Warning box: "Claude MCP Test is asking to: Access the identity URL service · Access Salesforce hosted MCP servers · Perform requests at any time". You selected two scopes, not three: Salesforce itself adds access to the identity URL service (which tells a client who signed in) to OAuth logins. Click Allow.
  5. Back in Claude, click Configure on the connector. Salesforce's page says this lets you "configure the tools available in the MCP server you've chosen, allowing you to adjust permission settings." Claude shows display names, not tool ids, in two groups, Read-only tools (6) and Write/delete tools (5). Each group has its own dropdown, and each tool has three icons: allow, needs approval, block. On 2026-10-04 all 11 defaulted to Needs approval. Keep at least the write group there; Day 9 depends on it.
  6. Open Claude Desktop with the same account. In my test the connector was already there with no setup, and prompt 1 below worked.

Salesforce Allow Access? screen listing three permissions, including Access the identity URL service

claude.ai connector tool permissions: 6 read-only and 5 write/delete tools, all set to Needs approval

Configure and the approval cards use display names; the model and the logs use tool ids. The first six are the read-only group:

Display name in claude.ai Tool id
Query Records (SOQL) soqlQuery
Search Across Objects (SOSL) find
Get Object Schema (Enhanced) getObjectSchema
Get Related Records getRelatedRecords
Get Current User Info getUserInfo
Get Recently Viewed Records listRecentSobjectRecords
Create Record createSobjectRecord
Update Record updateSobjectRecord
Update Related Record updateRelatedRecord
Delete Record deleteSobjectRecord
Delete Related Record deleteRelatedRecord

Inside claude.ai each id also carries the connector's name, for example mcp__Salesforce_sobject-all__find, so pick a connector name you can recognise in a log.

If your org has no test data yet, the companion repository creates the running example for you. From its salesforce/ folder, run sf apex run --file scripts/apex/seed-demo-data.apex --target-org <YOUR_ORG_ALIAS>. It adds Acme Global Tech with two contacts, three opportunities and two cases, plus a second account, Globex (Demo), and it skips accounts that already exist.

Want reads only?

Salesforce suggests sobject-reads as the first server to try: "It's read-only, risk-free, and immediately useful." If you don't want write tools in claude.ai at all, add the sobject-reads URL here instead. I use sobject-all because Day 9 writes data, with an approval on every write.

Step by step: Claude Code

Route A: the inherited connector. If you log in to Claude Code with your claude.ai account, "MCP servers you've added in claude.ai, known as connectors, are automatically available in Claude Code". Check with:

claude mcp list

Look for the connector and its status. Claude Code prints one of three: ✔ Connected, ! Needs authentication or ✘ Failed to connect. In my test it printed claude.ai Salesforce sobject-all: https://api.salesforce.com/platform/mcp/v1/platform/sobject-all - ✔ Connected. In Claude Code, the inherited connector's tool ids start with mcp__claude_ai_Salesforce_sobject-all__.

Route B: add a server directly. This route doesn't depend on a claude.ai connector, and it is how you will add more servers later in the series. Salesforce's blog names these servers "salesforce-" followed by the server's API name. Run this from your project folder; read -s keeps the consumer key out of your screen and shell history:

printf "Consumer key: "; read -rs SF_CLIENT_ID; echo
claude mcp add --transport http salesforce-sobject-reads \
  "<SOBJECT_READS_SERVER_URL>" \
  --callback-port 38000 --client-id "$SF_CLIENT_ID"
claude mcp list        # expect "! Needs authentication"
claude                 # then type /mcp, pick salesforce-sobject-reads, choose Authenticate

Without a scope flag, claude mcp add stores a local server: it lives in ~/.claude.json and only appears when you start Claude Code in this project folder. In another folder, or in claude.ai, you won't see it. Add -s user after add to make it available in all your projects.

--callback-port exists for exactly this case: Claude Code's docs say to use it "to fix the port so it matches a pre-registered redirect URI of the form http://localhost:PORT/callback", and yesterday you registered http://localhost:38000/callback.

Before authentication, claude mcp list showed salesforce-sobject-reads: https://api.salesforce.com/platform/mcp/v1/platform/sobject-reads (HTTP) - ! Needs authentication. Authenticate opens Salesforce's login with response_type=code, PKCE (code_challenge_method=S256), redirect_uri=http://localhost:38000/callback, scope=mcp_api refresh_token offline_access, prompt=consent and resource set to the server URL. After the same allow screen as above, Claude Code v2.1.289 said "Authentication successful. Connected to salesforce-sobject-reads.", and /mcp listed it under Local MCPs as ✔ salesforce-sobject-reads 6 tools, next to ✔ claude.ai Salesforce sobject-all 11 tools under claude.ai. This is another approval of Claude MCP Test; remember Day 5's limit of five.

Claude Code /mcp: Authentication successful, salesforce-sobject-reads under Local MCPs with 6 tools and the inherited claude.ai connector with 11 tools

The command leaves out --client-secret on purpose, and the secret-less route worked in my test. Claude Code's documentation says: "If the server uses a public OAuth client with no secret, use only --client-id without --client-secret". (Salesforce's blog includes the flag. You need it only if your app requires a secret; it "prompts for the secret with masked input".)

Once connected, ask Claude Code: Using salesforce-sobject-reads, list the exact names of your tools. Expect six: getObjectSchema, soqlQuery, find, getUserInfo, listRecentSobjectRecords and getRelatedRecords. There is no create, update or delete tool on this server, so the model can't change data through it, whatever you ask.

Your first prompts (read-only)

Start a new chat in claude.ai with the connector switched on and run these one at a time. For each answer, expand the tool-call block to see which tool Claude picked and what it sent. The model chooses its tools, so a different read tool is fine as long as the answer is right. The tool column shows what Claude chose on 2026-10-04.

Before the first call you will see a Loaded tools step, where Claude searches its tool list and loads the Salesforce tools it needs. Then comes the approval card, for example "Claude wants to use Get Current User Info from Salesforce sobject-all", with Deny, Always allow and Allow once. I clicked Allow once every time, and Claude asked again before every tool call.

Claude's approval card: Claude wants to use Get Current User Info from Salesforce sobject-all, with Deny, Always allow and Allow once

# Prompt Expected tool What a correct answer contains
1 Who am I signed in as in Salesforce? getUserInfo Your test user's name, username, email, profile and status
2 tell me some basic information about the Acme Global Tech account One soqlQuery with contact and opportunity subqueries Industry Technology, country India, two contacts, three opportunities, and whatever else your user can see
3 List the open opportunities for Acme Global Tech with amount and close date, biggest first. soqlQuery Acme Expansion (125,000) and Acme Renewal 2027, but not the closed Acme Pilot
4 Search Salesforce for "Sync errors" and tell me which records mention it. find, then soqlQuery The High priority case "Sync errors after upgrade"
5 Show the cases related to Acme Global Tech. soqlQuery (getRelatedRecords possible) Two cases, including "Sync errors after upgrade"
6 List the exact names of the Salesforce tools you can use. none The 11 sobject-all tool names

Prompt 4 surprised me: the search (find) returned nothing for records created minutes earlier, probably because Salesforce's search index hadn't caught up (Claude's explanation). Claude fell back to a SOQL query on Subject and found the case. Prompt 2 is Salesforce's own test prompt, "tell me some basic information about the {ACCOUNT NAME HERE} account", with our account's name filled in. It is a good first check because it gives the model room to choose its own tools.

Claude's answer about Acme Global Tech: 2 contacts, 3 opportunities and a note on blank fields

Prompt 1 deserves a second look. getUserInfo returns an "Identity object with user ID, full name, email, username, profile, role, manager, local time, and timezone." If that user is not the one you expected, stop here and read "Wrong org or wrong user" below before you trust anything else.

Now ask something the test user shouldn't see, for example a record owned by another user under a private sharing model. Claude should come back empty-handed or report an access error. That is the security model working, not a bug.

What just happened

Behind a chat that looks like one step, a lot of structure ran:

  1. Claude listed the tools. Each hosted server publishes its tools with a name, a description and an input schema, and Claude read that list over MCP (the tools/list request from Day 3). Salesforce doesn't document which MCP protocol revision its servers speak; on 2026-10-04 sobject-reads negotiated 2025-06-18 (Day 3), which can change.
  2. The model picked a tool and wrote the arguments. For prompt 3 it chose soqlQuery and wrote the SOQL itself. The server doesn't interpret your question: Salesforce's FAQ says its processing "is completely deterministic", and "The LLM is entirely on the client side".
  3. Claude called the tool with your token (tools/call), and Salesforce ran it as you. "Every MCP tool call runs with the same permissions as the user who authorized the connection": object permissions, field-level security and sharing rules all apply. If Claude updates a record later, Salesforce's wiki says "the authenticated user's name appears in the audit trail as the editor."
  4. The result came back as data and the model wrote the answer from it.

Two consequences follow. Salesforce says "MCP tool calls consume API calls against your org's daily API quota". And the approval settings in Configure are part of your safety net: the MCP specification says "Hosts must obtain explicit user consent before invoking any tool."

Salesforce's FAQ says sobject-all also carries MCP prompt templates, "currently usable in Claude and Cursor". On 2026-10-04 none appeared anywhere in claude.ai, including the + menu, so don't plan on them.

What can go wrong

Symptom Likely cause Fix
Salesforce's login page says the app or client ID is invalid The External Client App hasn't propagated yet, or the wrong key was pasted Wait the full 30 minutes after creating the app, then paste the consumer key again
Claude Code's callback shows error=invalid_client_id&error_description=client%20identifier%20invalid The --client-id isn't the app's Consumer Key: the placeholder was left in, an extra space or quote crept in, or it is another app's key claude mcp remove salesforce-sobject-reads, then add it again with the key read by read -s
A connection that worked may fail or ask you to sign in again You approved Claude MCP Test a sixth time, which revokes your oldest approval Revoke approvals you don't use, then sign in again: Connect in claude.ai, /mcp → Authenticate in Claude Code (Day 5)
salesforce-sobject-reads is missing in Claude Code It is a local server and you started Claude Code in another folder Start in the project folder, or add it again with -s user
A redirect URI error instead of the login page The callback doesn't match: claude.ai needs https://claude.ai/api/mcp/auth_callback, Claude Code needs http://localhost:38000/callback Fix the app's callback list, or the --callback-port value; localhost is not 127.0.0.1
The connector loops back to the login, or every call returns 401 JWT or PKCE off, wrong scopes, or a beta-era app Recheck Day 5's scopes: exactly mcp_api and refresh_token, with JWT and PKCE on, then reconnect
No tools, a 404, or "server not found" The server isn't active yet, or the URL is wrong Wait 2 minutes after activating; copy the URL from Setup; Salesforce's troubleshooting advice is to try sobject-all first
Claude Code shows ✘ Failed to connect Wrong URL or callback port claude mcp remove <name>, then add it again with --callback-port 38000
Answers come from a different org, or show another user The browser was already logged in to another org when you clicked Connect Disconnect, log out of Salesforce, reconnect in a private window; the My Domain form of the server URL sends the sign-in to your own org's login page

Security note: whose access is this?

Once connected, Claude acts as the Salesforce user who clicked Allow, for as long as the tokens last. Anyone who uses your Claude account can read what you can read in Salesforce. Keep a few habits:

  • Connect as a test user with test data while you learn, never as a System Administrator in a real org.
  • Keep write tools on "ask first" in Configure, and give Claude Code the read-only sobject-reads server.
  • Give Claude its own External Client App, so you can revoke its tokens in Setup → External Client Apps → OAuth Usage without touching other clients.
  • If you add IP restrictions to the app later, remember the claude.ai connector signs in through Anthropic's side, and Claude's docs ask that login hosts be reachable from Anthropic's published egress range.

Today's checklist

  • The Salesforce sobject-all connector shows as connected in claude.ai, using Use your own OAuth client with a blank secret.
  • Configure lists Read-only tools (6) and Write/delete tools (5), and the write tools are on Needs approval.
  • The connector appears in Claude Desktop without extra setup.
  • claude mcp list shows salesforce-sobject-reads as connected, and it reports six tools.
  • Prompt 1 named the user I expected.
  • Prompts 2 to 5 returned Acme Global Tech data, and I checked which tool each one used.

Frequently asked questions

Why not "Register automatically", when claude.ai marks it Detected?

That option uses Dynamic Client Registration, which Salesforce documents as not supported for hosted MCP. Your own External Client App also gives you PKCE without a secret, your own policies and a clean way to revoke Claude. Salesforce's documented steps choose "Use your own OAuth client".

Do I need to enter the consumer secret in Claude?

No, if you unchecked both "Require secret" boxes on the External Client App. Claude then connects as a public client and PKCE protects the sign-in. Salesforce's page says to leave the secret blank unless your authorization server requires one.

Which Claude plan do I need?

Any plan can add custom connectors; Free allows one. I tested on Pro or Max, under Customize → Connectors. On Team and Enterprise an Owner adds them for the organization.

Can Claude see Salesforce records that I can't?

No. Every hosted MCP tool call runs with the signed-in user's object permissions, field-level security and sharing rules, and the audit trail names that user.

What's next

Claude can now reach your org, and you have seen it pick tools on its own. Tomorrow, on Day 7, we open the toolbox: what each of the 11 sobject-all tools does, how to read a tool definition the way the model does, how the smaller servers compare, and how the beta Headless 360 MCP Server takes a different approach with just five tools.

Sources

Verified against the sources below on September 30, 2026. Salesforce ships Headless 360 changes often: check the linked docs if a screen looks different.

  1. Configure Claude (Salesforce Hosted MCP Servers) — custom connector steps and server URL format
  2. Connect Claude with Salesforce Hosted MCP Servers — Salesforce Developers blog, May 26, 2026: Claude Code command
  3. Security Best Practices (Salesforce Hosted MCP Servers)
  4. Test Your MCP Client (Salesforce Hosted MCP Servers)
  5. Add a connector that isn't in the directory (Claude)
  6. Authentication for connectors (Claude)
  7. Connect Claude Code to tools via MCP
Day 06 · Cheat sheet

Everything from today on one page. Tap to zoom, or download it for later.

Download PNG
Day 6 cheat sheet: Connect an AI Client to Salesforce via MCPOpen PNG
Day 6 cheat sheet: Connect an AI Client to Salesforce via MCP
Day 6 cheat sheet: Connect an AI Client to Salesforce via MCP
All 15 days in this series
Share
Discussion

Comments

Loading comments...

Add a comment

Comments are reviewed before they appear.