A production-oriented Frappe v15+ application that gives each authorized Frappe user a web AI assistant backed by a configurable AI provider and Salesforce Hosted MCP. Salesforce OAuth tokens and AI API keys remain encrypted on the Frappe server; browser code calls only whitelisted Frappe methods.
Salesforce Headless 360 MCP is currently a Salesforce Beta service. Validate availability, limits, and terms for your org before production use.
Frappe browser page (/salesforce-ai)
↓ authenticated frappe.call
Frappe Python services
├── OpenAI / Claude / Gemini / Azure / local LLM (tool calling)
└── Salesforce Hosted MCP (Streamable HTTP + OAuth bearer token)
↓
Salesforce org
The MCP tool list is retrieved at runtime. In read-only mode the server permits only discover, describe, and dispatch_readonly; dispatch is removed from the model's tools and independently blocked in Python. When writes are enabled, dispatch is held in a ten-minute, user-bound confirmation record until the user explicitly confirms.
The app also supports Salesforce SObject servers. For platform/sobject-all, read-only mode exposes only tools marked read-only (plus Salesforce's known schema/query/search/identity/relationship read tools). When writes are enabled, discovered mutation tools are exposed and every create/update/delete call uses the same confirmation gate.
- Frappe Framework v15 or newer and a working Bench site
- Python 3.10+
- A Salesforce org with API v67.0+ and Headless 360 activated
- A Salesforce External Client App configured for OAuth Authorization Code + PKCE S256
- An OpenAI API key with access to the configured model
- HTTPS for the public Frappe site
Python dependencies (httpx and openai) are declared in pyproject.toml and install with the app.
cd ~/frappe-bench
bench get-app https://github.com/TechwithZakir/salesforce_mcp_ai
bench --site yoursite.example install-app salesforce_mcp_ai
bench --site yoursite.example migrate
bench build --app salesforce_mcp_ai
bench restartFor local development:
cd ~/frappe-bench
bench new-app salesforce_mcp_ai
# Replace the generated app with this repository, or clone it into apps/salesforce_mcp_ai.
bench --site development.localhost install-app salesforce_mcp_ai
bench --site development.localhost migrate
bench build --app salesforce_mcp_aiAssign Salesforce MCP Manager to administrators and Salesforce MCP User to workshop users. Open Salesforce MCP Settings as a manager and save the configuration, then visit /salesforce-ai.
After upgrading an existing installation, run bench --site yoursite.example migrate and bench --site yoursite.example clear-cache. The public Salesforce MCP AI workspace then appears in Desk for users assigned Salesforce MCP User, Salesforce MCP Manager, or System Manager.
- In Salesforce Setup, search for MCP Servers.
- Select MCP Servers, find headless-360, and activate it.
- Go to External Client App Manager and create an External Client App.
- Enable OAuth Authorization Code flow and require PKCE using S256.
- Add scopes
mcp_api,refresh_token, andoffline_access(use the labels/options exposed by your Salesforce release). - Set the callback URL exactly to:
https://YOUR-FRAPPE-DOMAIN/api/method/salesforce_mcp_ai.api.auth.salesforce_callback
- Copy the consumer key and, when required by the app policy, client secret into Salesforce MCP Settings.
Salesforce enforces the connected user's CRUD, field-level security, sharing, profiles, and permission sets for every MCP operation. Give workshop users only the Salesforce permissions they require.
Recommended production configuration:
Enabled: On
AI Provider: OpenAI
API Key: (encrypted)
Model: gpt-5.6
Temperature: 0.2
Max Tokens: 4000
Salesforce Login URL: https://login.salesforce.com
Salesforce MCP URL: https://api.salesforce.com/platform/mcp/v1/platform/headless-360
Allow Write Operations: Off
Require Write Confirmation: On
Enable MCP Trace: On
Enable Audit Logging: On
Maximum MCP Tool Calls: 6
Request Timeout: 60
The OpenAI API key and External Client App client secret are Frappe Password fields. Access and refresh tokens are also Password fields on the per-user Salesforce Connection document. They are read only by backend code using Frappe's encrypted-password API.
Switch without code changes:
Salesforce Login URL: https://test.salesforce.com
Salesforce MCP URL: https://api.salesforce.com/platform/mcp/v1/sandbox/platform/headless-360
Use a sandbox External Client App with the same callback and scopes.
Activate SObject All under Salesforce Setup → MCP Servers, then configure:
Production/Developer org: https://api.salesforce.com/platform/mcp/v1/platform/sobject-all
Sandbox/Scratch org: https://api.salesforce.com/platform/mcp/v1/sandbox/platform/sobject-all
Use read-only mode for querying Cases, Opportunities, Accounts, and other records. Turn writes on only when create/update/delete operations are required; confirmation should normally remain enabled.
Choose one provider in Salesforce MCP Settings:
- OpenAI: enter an OpenAI API key and model.
- Claude: enter an Anthropic API key and Claude model name.
- Gemini: enter a Gemini API key and model name.
- Azure OpenAI: enter the key, HTTPS resource endpoint, and deployment name. The current v1 endpoint is used.
- Local LLM (OpenAI-compatible): enter an OpenAI-compatible
/v1base URL and model name. The key may be blank for an unsecured loopback server.
Examples for local servers:
Ollama: http://127.0.0.1:11434/v1
LM Studio: http://127.0.0.1:1234/v1
LiteLLM: https://llm.example.com/v1
vLLM: https://vllm.example.com/v1
The selected model must support tool/function calling. Local HTTP is accepted only for a loopback hostname or address; remote endpoints require HTTPS. The agent sends fixed safety instructions and only dynamically returned, policy-filtered MCP schemas. The maximum is counted across individual tool calls, not merely iterations.
- Keep Allow Write Operations off unless mutations are required. Leave confirmation enabled when writes are on.
- OAuth state and PKCE verifier are server-cache entries, expire after ten minutes, and are consumed once.
- Pending writes are user-bound, single-use, and expire after ten minutes.
- The configured MCP host is restricted to HTTPS on
api.salesforce.comto reduce SSRF risk. - Authorization errors trigger exactly one refresh attempt. Failed refreshes disconnect the account.
- Audit payloads are redacted and truncated. Do not add secret fields to traces or custom logs.
- Serve Frappe only over HTTPS, secure Redis and the encryption key, rotate secrets, use restrictive roles, and configure backups.
- Review Salesforce Beta terms and your organization's data-handling policy before sending Salesforce data to an LLM.
- Normal chat is synchronous for workshop clarity. Service classes are isolated so a later endpoint can invoke them through
frappe.enqueue.
- Salesforce MCP User: use the assistant, connect/disconnect their own Salesforce account, and view only their own logs.
- Salesforce MCP Manager: configure settings and view all audit logs/connections. Secret values are never returned by an API.
Ownership is enforced by DocType permission hooks as well as filters in each whitelisted method.
Tests use mocks and do not require a live Salesforce org or OpenAI call:
bench --site development.localhost run-tests --app salesforce_mcp_ai
bench --site development.localhost migrate
bench build --app salesforce_mcp_aiCoverage includes PKCE, one-time OAuth state, token refresh, read-only tool filtering and blocking, connection/log ownership, and the tool-call limit setting. For a release, also perform a browser smoke test of /salesforce-ai, OAuth callback, tool discovery, and one read-only prompt against a dedicated Salesforce test user.
- Sign in as a user with the
Salesforce MCP Userrole. - Open
/salesforce-ai, click Connect Salesforce, and complete OAuth. - Confirm that the badge is green, mode says Read Only, and the MCP tools appear.
- Ask: “Find Acme Corporation.” Expand the trace to show
discover,describe, anddispatch_readonly. - Ask: “Show its open opportunities,” then “Which opportunity should I prioritize?”
- Optionally enable writes as a manager. Ask to create a follow-up task, review the proposed
dispatcharguments, and click Confirm & Execute. - Open Salesforce MCP Log to show the truncated audit trail.
- OAuth state invalid or expired: restart Connect Salesforce and finish within ten minutes; verify Redis/cache health and that the callback returns to the same Frappe deployment.
- redirect_uri mismatch: copy the callback shown above exactly, including scheme and hostname.
- invalid scope / MCP access denied: activate Headless 360, confirm API v67.0+, the
mcp_apiscope, and the user's Salesforce permissions. - 401 after connection: reconnect if refresh failed; verify the External Client App refresh-token policy and client secret requirement.
- No MCP tools: confirm the configured production/sandbox endpoint and server activation.
- OpenAI error: verify the API key, model access, quota, outbound network access, and timeout.
- Maximum tool calls reached: make the prompt more specific or cautiously raise the limit (maximum accepted by this app is 20).
- Page redirects to login / permission denied: sign in and assign one of the Salesforce MCP roles.
Technical failures are recorded with frappe.log_error; browser responses do not include stack traces or secrets.
salesforce_mcp_ai/
├── api/ # whitelisted auth, MCP, and agent methods
├── services/ # OAuth, token, MCP transport, OpenAI orchestration
├── utils/ # PKCE, validation, redaction
├── salesforce_mcp_ai/doctype/
├── tests/
└── www/salesforce-ai/
MIT