<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Conor</title>
    <description>The latest articles on Forem by Conor (@conor_61d358cde152bb5800a).</description>
    <link>https://forem.com/conor_61d358cde152bb5800a</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3890612%2Fc2dd7522-9d3a-410f-b432-35c12fcd89ec.png</url>
      <title>Forem: Conor</title>
      <link>https://forem.com/conor_61d358cde152bb5800a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/conor_61d358cde152bb5800a"/>
    <language>en</language>
    <item>
      <title>Agent Script: Salesforce's Open Language for Deterministic Agent Orchestration</title>
      <dc:creator>Conor</dc:creator>
      <pubDate>Sun, 26 Apr 2026 20:39:35 +0000</pubDate>
      <link>https://forem.com/conor_61d358cde152bb5800a/agent-script-salesforces-open-language-for-deterministic-agent-orchestration-2h1o</link>
      <guid>https://forem.com/conor_61d358cde152bb5800a/agent-script-salesforces-open-language-for-deterministic-agent-orchestration-2h1o</guid>
      <description>&lt;p&gt;Salesforce open-sourced Agent Script at TDX 2026, and it solves one of the most frustrating problems in production Agentforce deployments: you can't tell an LLM "always do step A before step B, and only proceed to step C if the customer is verified." Prompt instructions don't enforce control flow. Agent Script does.&lt;/p&gt;

&lt;p&gt;This post walks through what Agent Script is, how the language works, mnd how to build a realistic support triage agent with hard routing logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem Agent Script Solves
&lt;/h2&gt;

&lt;p&gt;Agentforce topics let you describe &lt;em&gt;what&lt;/em&gt; an agent should do — but that description goes through an LLM at runtime.&lt;sup id="fnref1"&gt;1&lt;/sup&gt; The LLM interprets your instructions and decides how to act. Most of the time, it works. Sometimes it doesn't: it skips a verification step, invokes the wrong action, or transitions prematurely.&lt;/p&gt;

&lt;p&gt;The workaround most teams use is defensive prompt engineering — stacking &lt;code&gt;ALWAYS&lt;/code&gt;, &lt;code&gt;NEVER&lt;/code&gt;, and &lt;code&gt;IMPORTANT&lt;/code&gt; clauses into system instructions. This is fragile, untestable, and hard to audit.&lt;/p&gt;

&lt;p&gt;Agent Script approaches the problem differently: it gives you a structured specification language where control flow is deterministic by design. The LLM still handles reasoning, but &lt;em&gt;your code&lt;/em&gt; controls when reasoning happens and what happens after.&lt;/p&gt;

&lt;p&gt;From the spec: &lt;em&gt;"execution is decoupled from specification. Agent Script describes what the agent is — its state, its available actions, its instructions — not how the runtime executes it."&lt;/em&gt;&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Language Fundamentals
&lt;/h2&gt;

&lt;p&gt;Agent Script is block-based and indentation-sensitive (like Python or YAML). Every agent is composed of blocks. Blocks fall into two categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Configuration blocks&lt;/strong&gt; (&lt;code&gt;config&lt;/code&gt;, &lt;code&gt;system&lt;/code&gt;) — set the agent's identity and static behavior&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution blocks&lt;/strong&gt; (&lt;code&gt;topic&lt;/code&gt;, &lt;code&gt;start_agent&lt;/code&gt;) — define runtime behavior, state, and transitions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a minimal valid Agent Script file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;agent_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Support&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Bot"&lt;/span&gt;
    &lt;span class="na"&gt;default_locale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en_US"&lt;/span&gt;

&lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;You are a Salesforce support agent.&lt;/span&gt;
        &lt;span class="s"&gt;Your job is to triage cases and route them to the right team.&lt;/span&gt;
        &lt;span class="s"&gt;Never share internal case notes with the customer.&lt;/span&gt;

&lt;span class="na"&gt;topic default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;General&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;support&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;entry&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;point"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pipe character (&lt;code&gt;|&lt;/code&gt;) denotes multiline strings — keep your &lt;code&gt;system&lt;/code&gt; instructions here rather than inline so they're readable and diffable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Variables: Typed State in Your Agent
&lt;/h2&gt;

&lt;p&gt;One of the more useful features is first-class variable support with explicit types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;case_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mutable string = ""&lt;/span&gt;
        &lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;support&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;case&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ID&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;collected&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user"&lt;/span&gt;
    &lt;span class="na"&gt;customer_verified&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mutable boolean = False&lt;/span&gt;
        &lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;True&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;once&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;identity&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;check&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;has&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;passed"&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mutable string = "standard"&lt;/span&gt;
        &lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Case&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;priority:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;standard,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;high,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;or&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;critical"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Variables use &lt;code&gt;@variables.name&lt;/code&gt; syntax throughout the rest of the script. Declaring them at the top of a topic forces you to think about what state the agent actually needs — and makes it visible during reviews and in the audit trail.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before and After Reasoning Hooks
&lt;/h2&gt;

&lt;p&gt;This is where Agent Script gets powerful. The &lt;code&gt;before_reasoning&lt;/code&gt; and &lt;code&gt;after_reasoning&lt;/code&gt; blocks let you inject deterministic logic around the LLM call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;topic billing_support&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Handle&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;billing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;disputes&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;payment&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;questions"&lt;/span&gt;

    &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;customer_verified&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mutable boolean = False&lt;/span&gt;
        &lt;span class="na"&gt;account_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mutable string = ""&lt;/span&gt;

    &lt;span class="na"&gt;before_reasoning&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s"&gt;run @actions.verify_customer_identity&lt;/span&gt;
            &lt;span class="s"&gt;with email=@variables.user_email&lt;/span&gt;
            &lt;span class="s"&gt;set @variables.customer_verified = @outputs.verified&lt;/span&gt;
            &lt;span class="s"&gt;set @variables.account_id = @outputs.account_id&lt;/span&gt;

        &lt;span class="s"&gt;if not @variables.customer_verified&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
            &lt;span class="s"&gt;transition to @subagent.identity_verification&lt;/span&gt;

    &lt;span class="na"&gt;reasoning&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;The customer is verified. Account ID is @variables.account_id.&lt;/span&gt;
            &lt;span class="s"&gt;Help them with their billing question. If the dispute exceeds $500,&lt;/span&gt;
            &lt;span class="s"&gt;collect the details and escalate — do not resolve it yourself.&lt;/span&gt;

    &lt;span class="na"&gt;after_reasoning&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;if @outputs.escalation_required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="s"&gt;run @actions.create_escalation_case&lt;/span&gt;
                &lt;span class="s"&gt;with account_id=@variables.account_id&lt;/span&gt;
                &lt;span class="s"&gt;with details=@outputs.dispute_details&lt;/span&gt;
            &lt;span class="s"&gt;transition to @topic.escalation_confirmation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key mechanics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;run @actions.action_name&lt;/code&gt; — invokes a named Agentforce action (Apex, Flow, MuleSoft, external API)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;with param=value&lt;/code&gt; — passes inputs to the action&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;set @variables.name = @outputs.field&lt;/code&gt; — captures outputs back into state&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transition to @topic.name&lt;/code&gt; or &lt;code&gt;@subagent.name&lt;/code&gt; — deterministic routing, no LLM involved&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  A Full Support Triage Example
&lt;/h2&gt;

&lt;p&gt;Here's a more complete agent that routes inbound support requests by product category and customer tier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;agent_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Case&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Triage&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Agent"&lt;/span&gt;
    &lt;span class="na"&gt;default_locale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en_US"&lt;/span&gt;

&lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;You are a Salesforce case triage agent.&lt;/span&gt;
        &lt;span class="s"&gt;Identify the product area and collect a clear description of the issue.&lt;/span&gt;
        &lt;span class="s"&gt;Do not attempt to solve technical problems directly — triage and route only.&lt;/span&gt;
        &lt;span class="s"&gt;If the customer is on a Premier Success Plan, acknowledge the SLA.&lt;/span&gt;

&lt;span class="na"&gt;topic case_intake&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Initial&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;contact&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;—&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;collect&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;case&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;details&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;route"&lt;/span&gt;

    &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;product_area&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mutable string = ""&lt;/span&gt;
            &lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Detected&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;product:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Sales&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Cloud,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Service&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Cloud,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Data&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Cloud,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;MuleSoft"&lt;/span&gt;
        &lt;span class="na"&gt;customer_tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mutable string = ""&lt;/span&gt;
            &lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Success&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;plan&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tier:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;standard,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;premier,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;signature"&lt;/span&gt;
        &lt;span class="na"&gt;case_description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mutable string = ""&lt;/span&gt;

    &lt;span class="na"&gt;before_reasoning&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s"&gt;run @actions.lookup_account_tier&lt;/span&gt;
            &lt;span class="s"&gt;with contact_id=@variables.contact_id&lt;/span&gt;
            &lt;span class="s"&gt;set @variables.customer_tier = @outputs.tier&lt;/span&gt;

    &lt;span class="na"&gt;reasoning&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;Greet the customer. Ask which Salesforce product they need help with&lt;/span&gt;
            &lt;span class="s"&gt;and collect a clear description of the issue.&lt;/span&gt;
            &lt;span class="s"&gt;Customer tier: @variables.customer_tier&lt;/span&gt;

    &lt;span class="na"&gt;after_reasoning&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s"&gt;set @variables.product_area = @outputs.detected_product&lt;/span&gt;
        &lt;span class="s"&gt;set @variables.case_description = @outputs.issue_summary&lt;/span&gt;

        &lt;span class="s"&gt;if @variables.product_area == "MuleSoft"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
            &lt;span class="s"&gt;transition to @subagent.mulesoft_triage&lt;/span&gt;

        &lt;span class="s"&gt;if @variables.product_area == "Data Cloud"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
            &lt;span class="s"&gt;transition to @subagent.data_cloud_triage&lt;/span&gt;

        &lt;span class="s"&gt;if @variables.customer_tier == "signature"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
            &lt;span class="s"&gt;run @actions.notify_tam&lt;/span&gt;
                &lt;span class="s"&gt;with case_summary=@variables.case_description&lt;/span&gt;
            &lt;span class="s"&gt;transition to @topic.premium_intake&lt;/span&gt;

        &lt;span class="s"&gt;transition to @topic.standard_routing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that the LLM does the qualitative work — understanding what product the customer is describing, extracting a clean issue summary — but the routing decisions are code. You can unit-test that transition logic. You can audit it. You can change it without touching a prompt.&lt;/p&gt;




&lt;h2&gt;
  
  
  Salesforce Actions as First-Class Citizens
&lt;/h2&gt;

&lt;p&gt;Agent Script's &lt;code&gt;@actions&lt;/code&gt; namespace maps directly to your Agentforce action library: Apex classes, Flows, MuleSoft API calls, external services. This means all the action tooling you already have — invocable Apex, autolaunched Flows — plugs in without changes.&lt;sup id="fnref3"&gt;3&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Example invocable Apex action that Agent Script can call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apex"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LookupAccountTier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@InvocableMethod(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;Lookup Account Tier'&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;Returns the Success Plan tier for a contact'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Contact&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Success_Plan__c&lt;/span&gt;
                &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Contact&lt;/span&gt;
                &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;contactId&lt;/span&gt;
                &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="n"&gt;Result&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;tier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Success_Plan__c&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
                &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Success_Plan__c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;standard'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@InvocableVariable(&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="n"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@InvocableVariable&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The action name in Agent Script (&lt;code&gt;@actions.lookup_account_tier&lt;/code&gt;) maps to the invocable method's API name in your org.&lt;sup id="fnref4"&gt;4&lt;/sup&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Tooling: Parser, LSP, VS Code Extension
&lt;/h2&gt;

&lt;p&gt;The full Agent Script toolchain is available at &lt;a href="https://github.com/salesforce/agentscript" rel="noopener noreferrer"&gt;github.com/salesforce/agentscript&lt;/a&gt;:&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Parser&lt;/strong&gt; — validates syntax, resolves namespaces&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linter&lt;/strong&gt; — catches common mistakes (undefined variables, unreachable transitions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LSP&lt;/strong&gt; — Language Server Protocol implementation for editor support&lt;sup id="fnref5"&gt;5&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VS Code extension&lt;/strong&gt; — syntax highlighting, autocomplete, inline validation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monaco playground&lt;/strong&gt; — browser-based editor for prototyping without an org&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The VS Code extension is the practical starting point. Install it, open a &lt;code&gt;.ascript&lt;/code&gt; file, and you get full IntelliSense for block types, namespace references, and action parameters.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Start
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install the VS Code extension&lt;/strong&gt; from the Agent Script GitHub repo.[2] It takes 2 minutes and gives you a working local environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open the playground&lt;/strong&gt; at the repo's web UI. The preloaded examples cover the most common patterns: verification gates, multi-topic routing, subagent delegation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit your existing Agentforce topics&lt;/strong&gt;:&lt;sup id="fnref1"&gt;1&lt;/sup&gt; identify the transitions and verification steps you're currently enforcing through prompt instructions. Those are your first candidates for Agent Script refactoring.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Map your invocable Apex to actions&lt;/strong&gt;:&lt;sup id="fnref3"&gt;3&lt;/sup&gt; any &lt;code&gt;@InvocableMethod&lt;/code&gt; in your org can be wired as an &lt;code&gt;@actions&lt;/code&gt; reference. Start with the actions your most critical agents already call.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agent Script is in active development — the spec is open, the tooling is moving fast, and the TDX 2026 announcement included it as a pillar of the Headless 360 initiative. Now is the time to get ahead of it before it becomes the expected pattern for any production Agentforce deployment.&lt;/p&gt;







&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://developer.salesforce.com/docs/einstein/genai/guide/agent-topics.html" rel="noopener noreferrer"&gt;Agentforce Agent Topics&lt;/a&gt; — Salesforce Developer docs. Covers topic definition, instructions, and action assignment within Agentforce. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://github.com/salesforce/agentscript" rel="noopener noreferrer"&gt;Agent Script GitHub repository&lt;/a&gt; — Salesforce open-source repo. Contains the language specification, parser, linter, LSP implementation, VS Code extension, and Monaco playground. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://developer.salesforce.com/docs/einstein/genai/guide/agent-actions.html" rel="noopener noreferrer"&gt;Invocable Actions in Agentforce&lt;/a&gt; — Salesforce Developer docs. Covers how Apex, Flow, and external actions are registered and invoked within Agentforce agents. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;&lt;a href="https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_InvocableMethod.htm" rel="noopener noreferrer"&gt;&lt;code&gt;@InvocableMethod&lt;/code&gt; annotation reference&lt;/a&gt; — Salesforce Apex Developer Guide. Full reference for declaring Apex methods as invocable actions, including input/output variable typing. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;&lt;a href="https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/" rel="noopener noreferrer"&gt;Language Server Protocol specification&lt;/a&gt; — Microsoft. The open protocol that Agent Script's LSP implements for editor tooling integration. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>salesforce</category>
      <category>agentforce</category>
      <category>mulesoft</category>
    </item>
    <item>
      <title>Salesforce Headless! All agents, all access.</title>
      <dc:creator>Conor</dc:creator>
      <pubDate>Tue, 21 Apr 2026 22:30:34 +0000</pubDate>
      <link>https://forem.com/conor_61d358cde152bb5800a/salesforce-headless-all-agents-all-access-19ka</link>
      <guid>https://forem.com/conor_61d358cde152bb5800a/salesforce-headless-all-agents-all-access-19ka</guid>
      <description>&lt;p&gt;Salesforce just flipped a switch at TDX 2026 that matters more than most announcements in recent memory: your Salesforce org is now an MCP server. Every Developer Edition org ships with Salesforce Hosted MCP Servers at no cost, and any MCP-compatible AI agent — Claude, Claude Code, Cursor, Codex, Windsurf — can now read data, trigger flows, run SOQL, and invoke Apex directly, with no browser involved.&lt;/p&gt;

&lt;p&gt;This post walks through exactly how to wire that up: OAuth config, MCP connection, and what you can actually do once you're in.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Headless 360 Actually Changes
&lt;/h2&gt;

&lt;p&gt;Before Headless 360, connecting an external agent to Salesforce meant either writing your own connected app + REST adapter or cobbling together a third-party library. The platform wasn't designed to be consumed by agents; it was designed for humans clicking through tabs.&lt;/p&gt;

&lt;p&gt;Headless 360 reframes the whole stack. Salesforce now exposes 60+ MCP tools covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data operations&lt;/strong&gt;: query records, create, update, upsert, delete (any standard or custom object)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation&lt;/strong&gt;: invoke named Flows, trigger Process Builder actions, run Apex methods via REST&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reporting&lt;/strong&gt;: execute saved reports and return structured data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agentforce&lt;/strong&gt;: start and resume Agentforce sessions, pass context, read session traces&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata&lt;/strong&gt;: describe objects, list picklist values, read field metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The underlying transport is &lt;a href="https://spec.modelcontextprotocol.io/specification/" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; — JSON-RPC 2.0 over SSE or HTTP.&lt;sup id="fnref1"&gt;1&lt;/sup&gt; Your agent calls a tool (&lt;code&gt;salesforce_query&lt;/code&gt;, &lt;code&gt;salesforce_run_flow&lt;/code&gt;, etc.) and Salesforce executes it under the user's OAuth token.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Create an External Client App in Salesforce Setup
&lt;/h2&gt;

&lt;p&gt;Navigate to &lt;strong&gt;Setup → External Client Apps → New&lt;/strong&gt;.&lt;sup id="fnref2"&gt;2&lt;/sup&gt; You're creating an OAuth 2.0 client that your AI agent will use (claude for example).&lt;/p&gt;

&lt;p&gt;Key settings:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;App Name&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;MCP Agent&lt;/code&gt; (or whatever labels your use case)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MCP_Agent&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OAuth Flow&lt;/td&gt;
&lt;td&gt;Authorization Code and Credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Callback URL&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;https://claude.ai/oauth/callback&lt;/code&gt; (for Claude Desktop) or &lt;code&gt;http://localhost:7878/callback&lt;/code&gt; (for Claude Code / local agents)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selected OAuth Scopes&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;api&lt;/code&gt;, &lt;code&gt;refresh_token&lt;/code&gt;, &lt;code&gt;sfap_api&lt;/code&gt;, &lt;code&gt;einstein_gpt_api&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;sfap_api&lt;/code&gt; scope unlocks Salesforce API Platform — required for Agentforce features.&lt;sup id="fnref3"&gt;3&lt;/sup&gt; Without it, the hosted MCP server returns 403s on agent-related tools. The &lt;code&gt;einstein_gpt_api&lt;/code&gt; scope is needed if you're routing through Einstein or hitting Prompt Builder endpoints.&lt;/p&gt;

&lt;p&gt;Save and copy the &lt;strong&gt;Consumer Key&lt;/strong&gt;. You'll need it in the next step.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Locate Your Org's MCP Server URL
&lt;/h2&gt;

&lt;p&gt;Every org's hosted MCP server endpoint follows this pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://&amp;lt;my-domain&amp;gt;.my.salesforce.com/mcp/v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;&amp;lt;my-domain&amp;gt;&lt;/code&gt; is your org's My Domain name.&lt;sup id="fnref4"&gt;4&lt;/sup&gt; You can confirm it under &lt;strong&gt;Setup → My Domain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For a scratch org or Developer Edition org, it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://myorgname-dev-ed.develop.my.salesforce.com/mcp/v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3: Configure Your AI Client
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Claude Desktop
&lt;/h3&gt;

&lt;p&gt;Add this block to &lt;code&gt;~/Library/Application Support/Claude/claude_desktop_config.json&lt;/code&gt; (macOS) or &lt;code&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/code&gt; (Windows):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"salesforce"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"oauth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://myorgname-dev-ed.develop.my.salesforce.com/mcp/v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"oauth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"clientId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_CONSUMER_KEY_HERE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"authorizationUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://login.salesforce.com/services/oauth2/authorize"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tokenUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://login.salesforce.com/services/oauth2/token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"scopes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"refresh_token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sfap_api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"einstein_gpt_api"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Claude Desktop, click the plug icon, and you'll be prompted to authorize against your org. After that, the &lt;code&gt;salesforce&lt;/code&gt; server appears in the tools panel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude Code (CLI)
&lt;/h3&gt;

&lt;p&gt;In your project root, create or update &lt;code&gt;.mcp.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"salesforce"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"oauth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://myorgname-dev-ed.develop.my.salesforce.com/mcp/v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"oauth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"clientId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_CONSUMER_KEY_HERE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"authorizationUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://login.salesforce.com/services/oauth2/authorize"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tokenUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://login.salesforce.com/services/oauth2/token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"scopes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"refresh_token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sfap_api"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp auth salesforce
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code opens a browser tab, you authenticate, and the token is stored locally. Subsequent runs reuse the refresh token.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor / Windsurf / Other MCP Clients
&lt;/h3&gt;

&lt;p&gt;These clients follow the same JSON format — they read a config file (usually &lt;code&gt;mcp.json&lt;/code&gt; or similar) and handle the OAuth flow on first connect. Consult your client's docs for the exact config file location.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: What You Can Do With It
&lt;/h2&gt;

&lt;p&gt;Once connected, here's a taste of what's now available to your agent without writing any integration code:&lt;/p&gt;

&lt;h3&gt;
  
  
  SOQL Query
&lt;/h3&gt;

&lt;p&gt;The agent can call &lt;code&gt;salesforce_query&lt;/code&gt; with a SOQL string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StageName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CloseDate&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Opportunity&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;StageName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Negotiation/Review'&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;CloseDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;THIS_QUARTER&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;Amount&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Results come back as structured JSON. Your agent can reason over them, generate follow-up queries, or feed them into another tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trigger a Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"salesforce_run_flow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"flowApiName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Case_Escalation_Auto_Assign"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"caseId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5001R00000EXAMPLE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"escalationReason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SLA breach detected by monitoring agent"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP server runs the Flow in the context of the authenticated user and returns output variables.&lt;sup id="fnref5"&gt;5&lt;/sup&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Invoke Apex via REST
&lt;/h3&gt;

&lt;p&gt;If you've exposed an Apex class as a REST resource, the agent can call it directly:&lt;sup id="fnref6"&gt;6&lt;/sup&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apex"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestResource(&lt;/span&gt;&lt;span class="n"&gt;urlMapping&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;/agent/summarize-account/*'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;global&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AccountSummaryResource&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@HttpGet&lt;/span&gt;
    &lt;span class="kd"&gt;global&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;summarize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;accountId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RestContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;requestURI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substringAfterLast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;/'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Account&lt;/span&gt; &lt;span class="n"&gt;acct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Industry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AnnualRevenue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Cases&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;CreatedDate&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;accountId&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;accountName'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;industry'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Industry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;annualRevenue'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;AnnualRevenue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;recentCases'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Cases&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent calls this via &lt;code&gt;salesforce_apexRest&lt;/code&gt; with the endpoint path and method. Your Apex runs server-side with full platform access.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scope Gotchas and Common Issues
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;sfap_api&lt;/code&gt; scope isn't showing in your External Client App?&lt;/strong&gt; It's only available if Agentforce is provisioned in your org.&lt;sup id="fnref3"&gt;3&lt;/sup&gt; Developer Edition orgs now include this by default post-TDX; sandbox orgs tied to Enterprise Edition may need Agentforce licensing enabled first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token expiry&lt;/strong&gt;: Salesforce access tokens expire after the session timeout configured in your org (default 2 hours).&lt;sup id="fnref7"&gt;7&lt;/sup&gt; The &lt;code&gt;refresh_token&lt;/code&gt; scope handles silent renewal, but if you've set a stricter session policy, agents will hit 401s mid-session. Check &lt;strong&gt;Setup → Session Settings → Force relogin after&lt;/strong&gt; and set it to &lt;code&gt;None&lt;/code&gt; for agent-facing External Client Apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IP restrictions&lt;/strong&gt;: If your org uses Login IP Ranges on the profile, agent requests coming from cloud-hosted AI services will fail. Either relax IP restrictions on the profile assigned to the External Client App, or use a dedicated Integration profile with no IP range restrictions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read-only vs. read-write&lt;/strong&gt;: You control what the MCP server can do by scoping the connected user's profile and permission sets. Run agents as a dedicated integration user with only the object-level permissions they need.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Start
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Spin up a Developer Edition org&lt;/strong&gt; — post-TDX, every new DE org comes with Hosted MCP Servers pre-enabled at no cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create your External Client App&lt;/strong&gt; with the scopes above and wire it to Claude Desktop or Claude Code using the config shown here.[2]&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start with read-only queries&lt;/strong&gt; — verify the connection works by asking your agent to pull 10 open Opportunities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layer in Flow invocation&lt;/strong&gt; — pick a simple, well-tested Flow and let the agent trigger it from a natural language request.&lt;sup id="fnref5"&gt;5&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add custom Apex REST endpoints&lt;/strong&gt; for anything the 60+ built-in MCP tools don't cover — your business logic, your custom objects, your integration patterns.&lt;sup id="fnref6"&gt;6&lt;/sup&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Headless 360 is the most architecturally significant thing Salesforce has shipped for developers in years. The platform is finally designed to be consumed by code — and agents — and not just browsers.&lt;/p&gt;







&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://spec.modelcontextprotocol.io/specification/" rel="noopener noreferrer"&gt;Model Context Protocol specification&lt;/a&gt; — Official MCP spec. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://help.salesforce.com/s/articleView?id=sf.external_client_apps_overview.htm&amp;amp;type=5" rel="noopener noreferrer"&gt;External Client Apps overview&lt;/a&gt; — Salesforce Help. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_scopes.htm&amp;amp;type=5" rel="noopener noreferrer"&gt;OAuth scopes reference&lt;/a&gt; — Salesforce Help. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;&lt;a href="https://help.salesforce.com/s/articleView?id=sf.domain_name_overview.htm&amp;amp;type=5" rel="noopener noreferrer"&gt;My Domain overview&lt;/a&gt; — Salesforce Help. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;&lt;a href="https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_process_rules.htm" rel="noopener noreferrer"&gt;Invoke a Flow via REST&lt;/a&gt; — Salesforce REST API Dev Guide. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn6"&gt;
&lt;p&gt;&lt;a href="https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_rest.htm" rel="noopener noreferrer"&gt;Apex REST web services&lt;/a&gt; — Salesforce Apex Dev Guide. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn7"&gt;
&lt;p&gt;&lt;a href="https://help.salesforce.com/s/articleView?id=sf.security_networkaccess.htm&amp;amp;type=5" rel="noopener noreferrer"&gt;Session security settings&lt;/a&gt; - Salesforce Help. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>salesforce</category>
      <category>agentforce</category>
      <category>ai</category>
      <category>mcp</category>
    </item>
  </channel>
</rss>
