Connect Claude to Salesforce via MCP: Step-by-Step Setup (2026)

Module 4 · Hands-On
Connect Claude to a
Salesforce Org via MCP
What you'll build: A working connection between Claude Desktop and a free Salesforce Developer Edition org, so Claude can query and act on real records using natural language. Takes about 30 minutes end to end.
Verified working as of July 2026. This is a genuinely new Salesforce feature, and the exact screens are still evolving. The underlying requirements below — global Apex visibility, the Agent Action wrapper, the exact callback URL — are the stable part and unlikely to change. The precise click-path through Salesforce's UI may shift as they continue shipping updates to this feature.

Prerequisites

  • A free Salesforce Developer Edition org — sign up at developer.salesforce.com
  • Claude Desktop installed (claude.com/download)
1

Create the Demo Object

In Setup → Object Manager → Create → Custom Object, create:

  • Label: Quote Demo, Plural: Quote Demos, Object Name: Quote_Demo
  • Record Name: Quote Demo Name, Data Type: Auto Number, Format: QD-{0000}

Then add these fields (Fields & Relationships → New):

Field LabelAPI NameType
StatusStatus__cPicklist (Pending Approval, Approved, Rejected)
AmountAmount__cCurrency
TerritoryTerritory__cText(255)
Rejection ReasonRejection_Reason__cLong Text Area

Seed 5-10 records with varied amounts and territories — for example, QD-0001 at $750,000 in the West territory — so a query later returns a meaningful subset instead of everything or nothing.

2

Deploy the Apex Class

Create this class in Setup → Apex Classes → New. Paste the code below and save.

Required: the outer class, both inner classes, and every @InvocableVariable field must be declared global, not public. A public class will not appear in the MCP tool picker in Step 5.
QuoteDemoMCPAction.cls
/**
 * QuoteDemoMCPAction.cls
 * -----------------------------------------------------------
 * Demo Apex Invocable Action for the "Headless 360 for Claude
 * Users" course — Module 4/5 hands-on project.
 *
 * Uses a standalone demo object (Quote_Demo__c) so this can be
 * deployed to any free Salesforce Developer Edition org, with
 * zero dependency on any real company's data model.
 *
 * v2: Changed to 'global' visibility on the class, inner
 * classes, and their variables — testing whether MCP tool
 * registration requires global scope to discover the action
 * in the Add Tools picker.
 *
 * Deploy this to a free Developer Edition org. Never point a
 * demo MCP connection at a production or company org.
 * -----------------------------------------------------------
 */
global with sharing class QuoteDemoMCPAction {

    global class QuoteDemoActionRequest {
        @InvocableVariable(required=true label='Quote Demo Id')
        global Id quoteDemoId;

        @InvocableVariable(required=true label='Action (Approve or Reject)')
        global String action;

        @InvocableVariable(label='Reason (required for Reject)')
        global String reason;
    }

    global class QuoteDemoActionResult {
        @InvocableVariable(label='Success')
        global Boolean success;

        @InvocableVariable(label='Message')
        global String message;

        @InvocableVariable(label='New Status')
        global String newStatus;
    }

    @InvocableMethod(
        label='Approve or Reject Demo Quote'
        description='Approves or rejects a pending Quote_Demo__c record by Id. Intended to be exposed as an MCP tool so agents like Claude can act on quote approvals directly.'
        category='Quote Demo Management'
    )
    global static List<QuoteDemoActionResult> approveOrRejectQuoteDemo(List<QuoteDemoActionRequest> requests) {
        List<QuoteDemoActionResult> results = new List<QuoteDemoActionResult>();

        List<Id> demoIds = new List<Id>();
        for (QuoteDemoActionRequest req : requests) {
            demoIds.add(req.quoteDemoId);
        }

        Map<Id, Quote_Demo__c> demoMap = new Map<Id, Quote_Demo__c>(
            [SELECT Id, Status__c, Amount__c, Territory__c
             FROM Quote_Demo__c
             WHERE Id IN :demoIds]
        );

        List<Quote_Demo__c> toUpdate = new List<Quote_Demo__c>();

        for (QuoteDemoActionRequest req : requests) {
            QuoteDemoActionResult result = new QuoteDemoActionResult();
            Quote_Demo__c q = demoMap.get(req.quoteDemoId);

            if (q == null) {
                result.success = false;
                result.message = 'Quote_Demo__c not found: ' + req.quoteDemoId;
                results.add(result);
                continue;
            }

            if (req.action != 'Approve' && req.action != 'Reject') {
                result.success = false;
                result.message = 'Action must be "Approve" or "Reject".';
                results.add(result);
                continue;
            }

            if (req.action == 'Reject' && String.isBlank(req.reason)) {
                result.success = false;
                result.message = 'A reason is required to reject a demo quote.';
                results.add(result);
                continue;
            }

            q.Status__c = (req.action == 'Approve') ? 'Approved' : 'Rejected';
            if (req.action == 'Reject') {
                q.Rejection_Reason__c = req.reason;
            }
            toUpdate.add(q);

            result.success = true;
            result.newStatus = q.Status__c;
            result.message = 'Quote_Demo__c ' + req.quoteDemoId + ' set to ' + q.Status__c + '.';
            results.add(result);
        }

        if (!toUpdate.isEmpty()) {
            update toUpdate;
        }

        return results;
    }
}
3

Wrap It as an Agent Action

Go to Setup → Einstein → Agentforce Studio → Agentforce Asset Library → Actions tab → New Agent Action.

  • Reference Action Type: Apex
  • Reference Action Category: Invocable Method
  • Reference Action: select your method (Label and API Name auto-populate)
  • Fill in a Description for every input and output parameter
  • Enable "Require user confirmation" — this makes Claude pause and check with you before executing any write, confirmed working in Module 5
  • Click Finish
Required: this Agent Action wrapper is what makes the class discoverable as an MCP tool in Step 5 — a raw Apex class alone, even when global, will not appear there.
4

Create the External Client App

Setup → External Client App Manager → New External Client App.

  • Callback URL: https://claude.ai/api/mcp/auth_callback — use this exact URL
  • OAuth Flow: OAuth 2.0 with PKCE
  • Scopes: "Access Salesforce hosted MCP servers (mcp_api)" and "Perform requests at any time (refresh_token, offline_access)"
  • Check: Require Proof Key for Code Exchange (PKCE) Extension
  • Check: Issue JSON Web Token (JWT)-based access tokens for named users
OAuth scopes correctly selected: mcp_api and refresh_token
The two required scopes selected on the External Client App

Save, then copy the Consumer Key and Consumer Secret. Next, go to the Policies tab → OAuth Policies → Edit:

  • Permitted Users: All users may self-authorize
  • IP Relaxation: Relax IP restrictions
5

Create the Custom MCP Server

Setup → search "MCP Server" → open API Catalog → MCP Servers (not "Agentforce Registry → MCP Servers," which is a different feature).

  • Click Add MCP Server → Create Salesforce MCP Server, fill in Label/Name/Description, Create
  • While the server is still Inactive, click Add Server Assets → Add Tools
  • Switch the category dropdown to "Apex actions"
  • Select your action, click "+ Add Tool," confirm the sidebar counter updates, then click Save
The Approve or Reject Demo Quote tool showing full JSON input/output schema in Salesforce's Add Tools panel
The action successfully added, with its full input/output schema visible

Now click Activate on the server. Once active, the Details tab reveals the real Server URL, following this pattern:

https://api.salesforce.com/platform/mcp/v1/custom/{YourServerAPIName}
6

Connect Claude Desktop

In Claude Desktop, click the "+" in the message box → Connectors → Manage Connectors → Add → Add custom connector.

  • Remote MCP server URL: the Server URL from Step 5
  • Advanced settings → OAuth Client ID: your Consumer Key
  • Advanced settings → OAuth Client Secret: your Consumer Secret
  • Click Add, then log into Salesforce and authorize when prompted
Connected to Salesforce Quote Demo confirmation in Claude Desktop
The connection confirmed in Claude Desktop
Salesforce Quote Demo connector showing a working blue toggle
A working toggle switch — this is what confirms the tool is genuinely attached, not just the connector authenticated
7

Test It

Find a real record's Salesforce ID (format a0X..., not the display name). In a new chat, enable the connector and ask Claude to act on it.

Test prompt
"Approve quote demo [real record ID]." If Claude responds confirming the action, the connection works end to end. Full walkthrough of this test in Module 5.

Troubleshooting

Tool doesn't appear in "Add Tools → Apex actions"
Confirm the class is global (Step 2) and wrapped as an Agent Action (Step 3) — both are required.
Connector shows a ⚠️ warning icon instead of a toggle
The tool wasn't attached to the server, even if Salesforce shows "1 tool." Reopen Add Tools, re-select the action, click "+ Add Tool" before clicking Save — Save alone without that click registers nothing.
"Add Server Assets" is greyed out
The server is Active. Deactivate, add tools, then reactivate.

Key Points

  • Apex classes exposed as MCP tools must be global and wrapped as an Agent Action — both are required together
  • The callback URL must be exactly https://claude.ai/api/mcp/auth_callback
  • The real Server URL lives on api.salesforce.com, not your org's My Domain
  • Tools can only be added while the server is Inactive
  • A connector showing "Connected" doesn't guarantee its tools attached — check for the warning icon
Next Up
Module 5 walks through a complete workflow — querying, confirming, acting, and verifying — using the exact setup you just built.
SF
By SF Interview Pro
Salesforce Interview Prep Team
Practical Q&A by working Salesforce professionals · LWC, Apex, Data Cloud & AI
About Us ↗
☕ Enjoyed this article?
SF Interview Pro is 100% free and maintained by a Salesforce professional. No ads, no paywalls, and no signup required. If this guide helped you prepare for an interview, earn a certification, or grow your Salesforce career, consider buying me a coffee! ☕💜
🇮🇳 UPI (India)
UPI QR Code to support sfinterviewpro
Pay by QR
GPay · PhonePe · Paytm · BHIM
🌎 International
PayPal QR Code to support sfinterviewpro Pay via PayPal ↗
Scan or tap to pay