Skip to content

Salesforce Headless 360 — surgical adoption, not wholesale replacement

ADR-013: Salesforce Headless 360 — surgical adoption, not wholesale replacement

Status: Blocked on tenant business decision (Kahuna Agentforce purchase) Date: 2026-04-20 (resolved 2026-04-22) Deciders: Mishaal Murawala

Resolution (2026-04-22)

Probe executed against Kahuna Workforce Solutions SFDC prod via V5 gateway:

License inventory — from SELECT Name, Status, UsedLicenses, TotalLicenses FROM UserLicense:

  • Salesforce: 23/23 (standard Enterprise/Unlimited edition seats)
  • Identity: 0/100
  • Chatter Free, Chatter External, Cloud Integration User, Analytics Cloud Integration User
  • NO Agentforce license
  • NO Einstein AI license
  • NO MCP-related license

Endpoint probeGET /services/mcp/v1, /.well-known/mcp-server-card.json: HTTP 404 (“URL No Longer Exists” — Salesforce’s standard 404 page).

Conclusion: Kahuna’s current SFDC edition does NOT include Hosted MCP Server access. To unblock salesforce_mcp pass-through, Kahuna must purchase Agentforce (Flex Credits, Conversations, or per-user plan) OR negotiate Hosted MCP Server beta enablement with their SFDC AE.

Engineering disposition: ADR-013 remains a valid technical design. Implementation is blocked pending Kahuna business decision to purchase Agentforce. No V5 work proceeds until that gate opens. If Kahuna declines, ADR-013 becomes “won’t fix” — we keep shipping salesforce_query + salesforce_crm as the SFDC integration surface.

Follow-up for Mishaal: raise this with Kahuna leadership when the Agentforce pricing conversation becomes relevant. Not a Q2 2026 priority at current scale. Relates to: existing salesforce_query + salesforce_crm tools; Kahuna tenant (live on SFDC prod v67.0, PKCE OAuth); docs/daily-ai-review/2026-04-20.md item #1

Context

At TDX 2026 (2026-04-15), Salesforce launched Headless 360. Core claim: “No browser required. Our API is the UI.” Concrete ship:

  • 60+ new MCP tools exposing Data 360, Customer 360, Agentforce, and Slack as first-class agent surface.
  • 30 preconfigured coding skills for Claude Code, Cursor, Codex, Windsurf.
  • Agentforce Vibes 2.0 (GA) — platform agent runtime.
  • DevOps Center MCP (GA) — natural-language deploys via CI/CD.
  • Session Tracing (GA) — per-agent observability.
  • Agentforce Experience Layer (GA) — one agent, renders natively across Slack + Voice without rebuild.
  • Custom Scoring Evals — early access. Testing Center — May. Salesforce Catalog — June.

Kahuna runs on SFDC prod and is our biggest SFDC integration surface. If V5’s salesforce_query and salesforce_crm are materially behind what Headless 360 exposes natively, we may be maintaining hand-rolled code with no edge.

Current V5 surface (as of 2026-04-20)

ToolPathCapabilitiesLOC
salesforce_queryGET /services/data/{v}/query?q=SOQLRead only, SOQL~55
salesforce_crmPOST/PATCH/GET /services/data/{v}/sobjects/{obj}insert, update, describe~78
  • Version pinned in KV at api_config:salesforce.version (currently v67.0).
  • Auth via per-tenant per-account OAuth bearer, DO-managed refresh.
  • Instance URL per account from tenant_config.providers.salesforce.accounts[].instance_url.
  • No DevOps, no metadata ops, no platform events, no Agentforce invocation, no Slack bridge.

What Headless 360 adds that V5 doesn’t have

  1. Agentforce invocation as MCP tool — triggering agents from Claude Code / Cursor / V5.
  2. DevOps Center MCP — metadata retrieves, deploys, validations via natural language.
  3. Agent Experience Layer — one agent appearing in both Slack and Voice without rebuild. This is the path to Kahuna-as-a-Slack-bot without us maintaining Slack surface code.
  4. Session Tracing — first-class observability.
  5. Salesforce Catalog (June) — discovery index of available APIs per org. Equivalent to a live discover_apis for SFDC-only.
  6. 60+ specific object/workflow tools covering edges our salesforce_crm doesn’t hit (Flow triggers, CDC events, Platform Events, Einstein predictions, etc.).

What V5 has that Headless 360 doesn’t

  1. Multi-tenant isolation — V5 serves many tenants with distinct SFDC orgs. Headless 360 is per-org.
  2. Cross-provider unificationbatch_execute spans SFDC + HubSpot + Google Ads + GA4 + Gmail in one call. Headless 360 is SFDC-only.
  3. Our auth, rate-limit, routing, error-categorization, kv_audit layer — transparent to callers, provider-independent.
  4. Fail-fast contract + Slack alerting via waitUntil — our operational posture.
  5. Hand-curated schemas for the actions we actually use — ergonomic for common paths.

Decision

Adopt Headless 360 surgically, not wholesale. Three concrete changes:

Change 1 (required): Add salesforce_mcp pass-through tool

A single new MCP tool in V5 that forwards calls to Salesforce’s Headless 360 MCP endpoint, layering our tenant auth + rate limit + error categorization on top.

src/tools/salesforce-mcp.ts
// Accepts: {tool, args, account_id?}
// Resolves Salesforce Headless 360 MCP endpoint from tenant_config
// (provider.salesforce.accounts[].headless360_endpoint)
// Calls through with our OAuth bearer; returns the MCP tool response.

Why: gives Kahuna access to all 60 Headless 360 tools without us re-implementing each. We still own the tenant dimension, rate limits, and observability. Pattern is the same as our existing call_api generic proxy, but specialized for SFDC MCP’s schema.

Change 2 (required): Keep salesforce_query and salesforce_crm

Do NOT retire them. They’re ergonomically cleaner than an MCP-over-MCP pass-through for the 80% case (a SOQL query, a contact insert). They’re tested, they work on Kahuna, and they’re an artifact of our cross-provider uniformity — callers can script HubSpot + SFDC with identical mental models.

Change 3 (optional, H2): Add 3 curated wrappers for specific Headless 360 capabilities

Pick capabilities that genuinely expand V5 beyond what pass-through gives:

  • salesforce_devops — wrap DevOps Center MCP. Natural-language deploys are a V5-native workflow for multi-tenant SFDC config mgmt.
  • salesforce_agent_invoke — trigger Agentforce agents from V5 calls. Bridges our batch_execute to Agentforce’s agent runtime.
  • salesforce_platform_events — subscribe/publish to SFDC platform events. Pairs naturally with our DO-based token model.

Defer these until Change 1 is live and we see real Kahuna demand.

Non-goals (explicit no’s)

  • Do not mirror all 60 MCP tools. Maintenance burden outweighs ergonomic gain. Pass-through wins.
  • Do not adopt the Agentforce Experience Layer for Slack yet. It replaces our current Slack approach but bakes Kahuna into Salesforce’s agent pricing model. Evaluate pricing first (see risks).
  • Do not rebuild V5 on Headless 360’s agent runtime. V5’s orchestration lives on CF Workers for good reasons (edge latency, cost, multi-tenant). Headless 360 is a provider surface, not a platform substitute.

Open questions before implementation

  1. Edition tier required. Is Headless 360 MCP available on Kahuna’s current SFDC edition, or does it require an Agentforce Enterprise add-on? Action: verify with SFDC before writing code. Blocker if paywalled.
  2. Pricing model. Agentforce bills per conversation/action. Does invoking a Headless 360 MCP tool count as a billable agent action, or is it closer to a free API call? Batch workloads could get expensive fast. Action: get pricing in writing before production.
  3. Authentication. Existing V5 SFDC OAuth should work for Headless 360 MCP (same org, same scopes) — but SFDC may require additional agent_write / mcp_tools scopes. Action: verify scope inventory before migration.
  4. Versioning. Headless 360 MCP tools may version independently of REST Data API v66. Our api_config:salesforce.version may need a second field (mcp_version). Minor schema change.

Risks

  • Pricing cliff. If Agentforce conversation pricing makes batch workflows unaffordable, Change 1 becomes a liability, not a win.
  • Availability skew. Headless 360 GA’d 2026-04-15 but Testing Center and Salesforce Catalog don’t land until May/June. We’d be building against a moving target.
  • Salesforce can turn off generous free-tier access at any time. Hand-rolled tools keep us insulated.

Consequences

If we do Change 1 only

  • Minimal engineering. One new tool (~100 LOC). Kahuna gets expanded SFDC surface without us maintaining it.
  • Still locked into SFDC’s pricing and availability.

If we do Changes 1 + 3

  • Deeper but more brittle. DevOps Center MCP in particular has real ops value for Kahuna and is stable enough.

If we do nothing

  • V5 stays where it is. Kahuna keeps running on salesforce_query + salesforce_crm. We’re not worse off — but we’re not benefiting from 60+ tools that Salesforce is maintaining for us.

Recommendation

Ship Change 1 (salesforce_mcp pass-through) in the next build sprint, pending the 3 pre-implementation answers (edition, pricing, scopes). Defer Change 3 until Kahuna has a concrete use case that the pass-through can’t cleanly serve. Do not touch Changes marked non-goals.

References


Research Addendum (2026-04-20) — wire-level validation + refinement

The original recommendation (salesforce_mcp pass-through, keep existing curated tools, defer broader federation) is still correct. Deep research against MCP spec + Cloudflare constraints + MCP-gateway state-of-art confirms the direction but sharpens the implementation.

Wire-level facts (MCP Streamable HTTP spec, 2025-06-18)

Headless 360 MCP, by virtue of interop with Claude Code / Cursor / Codex / Windsurf, is standard MCP over Streamable HTTP. The protocol is:

  • Single endpoint (POST + GET).
  • POST carries client→server JSON-RPC. Server responds either Content-Type: application/json (single response) or text/event-stream (SSE stream terminating with the JSON-RPC response).
  • GET opens a server→client SSE channel for server-initiated messages (important — this means not purely request/response; the server can push notifications, progress events, and sampling requests back).
  • Mcp-Session-Id header established at InitializeResult, required on all subsequent requests in the session.
  • MCP-Protocol-Version header required after initialize.
  • Resumability via Last-Event-ID.

Implication for our proxy:

  • Dumb HTTP reverse proxy is NOT sufficient for full MCP semantics (bidirectional server-push and sampling break it).
  • BUT for the 95% case (single tool call → single response), a single POST forward with SSE passthrough is perfectly adequate.
  • Durable Objects are the right home for session state if/when we need long-lived sessions.

State-of-art MCP gateway patterns (Gravitee / IBM ContextForge / AgentGateway / Arcade / Composio)

Across production MCP gateways shipped Q1–Q2 2026, the dominant pattern is federation: one gateway endpoint aggregates many upstream MCP servers, with three levels of sophistication:

LevelPatternWhen to adopt
A. Single-tool pass-throughOne gateway tool salesforce_mcp(tool, args) forwards explicit tool calls to the upstream MCP endpoint.Starting point. ≤100 LOC. No session state.
B. Full tool federationGateway calls upstream tools/list at init, prefixes tool names (salesforce.query, salesforce.devops.deploy), merges into the gateway’s own tools/list response. Clients see one unified tool catalog.Once 2+ upstream MCPs matter AND total tool count stays under client caps (~40 on Cursor).
C. Retrieval-first federationGateway exposes a meta-tool find_tools(query) that BM25-searches upstream tool descriptions, returns top-K. Keeps context small even at 200+ tools.When total tool count exceeds client caps. Premature for us.

Cloudflare Workers as MCP gateway — constraint check

  • Worker request CPU limit: default 30s; our invariant #11 (30s outbound fetch) already aligns.
  • Worker bundle size: current 2,052 KiB / 397 KiB gzipped. Adding a mcp_federate primitive + salesforce_mcp wrapper estimated <50 KiB delta. Fits comfortably.
  • Native fetch supports SSE passthrough (streaming body). No proxy issue.
  • Durable Objects already in use for token management — extends naturally to MCP session state if we ever need Level B/C.
  • CF’s managed “AI Gateway” product has documented MCP buffering limitations. We are not using AI Gateway — V5 is custom Worker code, so those limitations don’t apply to us.

Revised implementation direction

Keep the ADR-013 recommendation in shape but upgrade the abstraction from “one SFDC wrapper” to “generic MCP federation primitive, first consumer = SFDC.”

  1. Core primitive: src/core/mcp-proxy.ts (~200 LOC, not a provider-specific wrapper). Accepts a registered upstream MCP endpoint from KV config, handles JSON-RPC envelope, forwards tools/call requests, streams SSE responses back. Stateless per request (no session across requests). Session state lives in a Durable Object if/when needed.

  2. Tool: src/tools/salesforce_mcp.ts — thin binding that uses mcp-proxy with the upstream headless360_endpoint from tenant_config.providers.salesforce.accounts[]. Accepts {tool, args, account_id?}. ~40 LOC.

  3. Meta-tool: salesforce_mcp_list_tools — cached proxy of SFDC’s tools/list. Cache in KV at mcp_tools:salesforce:{account_id} with 1-hour TTL. Gives agents discoverability of 60+ tools without forcing V5’s top-level tool count to balloon.

  4. KV schema extensiontenant_config.providers.salesforce.accounts[].headless360_endpoint (string, e.g., https://kahuna.my.salesforce.com/services/mcp/v1) and .headless360_version (string, tracked separately from REST api_config:salesforce.version).

  5. DO NOT prefix-federate 60 SFDC tools into V5’s top-level tools/list. Level B is premature — it inflates the client’s context and we have no proven multi-upstream use case yet.

Why this remains “lite and powerful”

  • Lite: one generic primitive (mcp-proxy) serves any future upstream MCP server (Notion, HubSpot when they ship, anything). No per-provider mirror code. Bundle impact <50 KiB.
  • Powerful: Kahuna gets all 60 Headless 360 tools via one MCP tool call, with our tenant auth + rate limit + error contract intact. Adding a second upstream MCP in H2 is a KV config change, not an engineering project.
  • Cutting-edge without being naïve: we’re adopting the pattern Gravitee / IBM ContextForge / AgentGateway validated in Q1 2026 at the simplest tier (Level A), with a documented upgrade path (Level B → C) and no premature complexity.

New risks surfaced by the research

  1. MCP sampling semantics. Some MCP tools invoke client-LLM “sampling” callbacks mid-execution. A stateless POST-forward proxy breaks this case. Mitigation: in the mcp-proxy primitive, detect sampling/createMessage in the response stream and return METHOD_NOT_SUPPORTED for now (or route back through an explicit client-capability check). Defer full sampling support to a later change.
  2. Session ID lifecycle. If Salesforce’s MCP server assigns a session ID on initialize, our proxy needs to track it across multiple client calls. For the initial Level-A pass-through used as a single tool call, we can initialize-then-close per invocation (stateless). Extra round trip per call (~80–150ms to SFDC) but no session bookkeeping. Acceptable tradeoff for v1.
  3. OAuth scope drift. Headless 360 likely wants agent_tools/mcp_invoke scopes. Existing Kahuna SFDC OAuth refresh will fail if the token was issued under old scopes. Pre-implementation blocker: re-issue Kahuna’s SFDC OAuth under the expanded scope set before shipping.

Answer to the user’s question

Is the salesforce_mcp pass-through the best thing to do?

Yes — but implemented as a generic mcp-proxy primitive with SFDC as the first consumer, not as a one-off SFDC wrapper. This keeps V5 lite (one primitive serves N upstreams), powerful (full Headless 360 surface accessible from one V5 tool), and cutting-edge (matches 2026 MCP-gateway state-of-art without the premature Level B/C complexity). Ship Level A, document the upgrade path, revisit when usage data demands it.

Non-negotiables before any code lands:

  • Verify Kahuna SFDC edition includes Headless 360 MCP access (not just Enterprise-gated).
  • Get Agentforce pricing-per-MCP-tool-call in writing.
  • Confirm the OAuth scopes needed, re-issue Kahuna’s token under expanded scopes.