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 probe — GET /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)
| Tool | Path | Capabilities | LOC |
|---|---|---|---|
salesforce_query | GET /services/data/{v}/query?q=SOQL | Read only, SOQL | ~55 |
salesforce_crm | POST/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
- Agentforce invocation as MCP tool — triggering agents from Claude Code / Cursor / V5.
- DevOps Center MCP — metadata retrieves, deploys, validations via natural language.
- 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.
- Session Tracing — first-class observability.
- Salesforce Catalog (June) — discovery index of available APIs per org. Equivalent to a live
discover_apisfor SFDC-only. - 60+ specific object/workflow tools covering edges our
salesforce_crmdoesn’t hit (Flow triggers, CDC events, Platform Events, Einstein predictions, etc.).
What V5 has that Headless 360 doesn’t
- Multi-tenant isolation — V5 serves many tenants with distinct SFDC orgs. Headless 360 is per-org.
- Cross-provider unification —
batch_executespans SFDC + HubSpot + Google Ads + GA4 + Gmail in one call. Headless 360 is SFDC-only. - Our auth, rate-limit, routing, error-categorization, kv_audit layer — transparent to callers, provider-independent.
- Fail-fast contract + Slack alerting via
waitUntil— our operational posture. - 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.
// 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
- 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.
- 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.
- Authentication. Existing V5 SFDC OAuth should work for Headless 360 MCP (same org, same scopes) — but SFDC may require additional
agent_write/mcp_toolsscopes. Action: verify scope inventory before migration. - Versioning. Headless 360 MCP tools may version independently of REST Data API v66. Our
api_config:salesforce.versionmay 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
- TDX 2026 launch: https://www.salesforce.com/news/stories/salesforce-headless-360-announcement/
- SalesforceBen breakdown: https://www.salesforceben.com/salesforce-headless-360-and-agentforce-vibes-2-0-revealed-at-tdx-2026/
- SaaStr commentary (“we’ve been living it for 6 months”): https://www.saastr.com/salesforce-just-launched-headless-for-ai-agents-weve-already-been-living-it-for-6-months/
- The Register technical summary: https://www.theregister.com/2026/04/15/salesforce_headless_360/
- V5 current impl:
src/tools/salesforce.ts,src/tools/salesforce-crm.ts
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) ortext/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-Idheader established atInitializeResult, required on all subsequent requests in the session.MCP-Protocol-Versionheader 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:
| Level | Pattern | When to adopt |
|---|---|---|
| A. Single-tool pass-through | One 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 federation | Gateway 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 federation | Gateway 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.”
-
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, forwardstools/callrequests, streams SSE responses back. Stateless per request (no session across requests). Session state lives in a Durable Object if/when needed. -
Tool:
src/tools/salesforce_mcp.ts— thin binding that usesmcp-proxywith the upstreamheadless360_endpointfromtenant_config.providers.salesforce.accounts[]. Accepts{tool, args, account_id?}. ~40 LOC. -
Meta-tool:
salesforce_mcp_list_tools— cached proxy of SFDC’stools/list. Cache in KV atmcp_tools:salesforce:{account_id}with 1-hour TTL. Gives agents discoverability of 60+ tools without forcing V5’s top-level tool count to balloon. -
KV schema extension —
tenant_config.providers.salesforce.accounts[].headless360_endpoint(string, e.g.,https://kahuna.my.salesforce.com/services/mcp/v1) and.headless360_version(string, tracked separately from RESTapi_config:salesforce.version). -
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
- 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-proxyprimitive, detectsampling/createMessagein the response stream and returnMETHOD_NOT_SUPPORTEDfor now (or route back through an explicit client-capability check). Defer full sampling support to a later change. - 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.
- OAuth scope drift. Headless 360 likely wants
agent_tools/mcp_invokescopes. 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.