Salesforce Cloud MCP Server
Provides tools to query and manage Salesforce Sales Cloud, Service Cloud, and Marketing Cloud data, including accounts, pipeline, cases, campaigns, journeys, Data Extensions, and more.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Salesforce Cloud MCP ServerShow me our top 5 open opportunities by amount this quarter"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Salesforce Cloud MCP Server
A Model Context Protocol (MCP) server that connects Claude directly to a live Salesforce org — Sales Cloud, Service Cloud, and (separately) Marketing Cloud — so you can query accounts, pipeline, cases, campaigns, and journeys in plain language, across Sales, PreSales, Marketing, and Customer Success: top of the funnel to bottom of the funnel, one server.
Each user runs this locally against their own org. Nothing is hosted centrally and no credentials ever leave your machine.
New to this repo? Start with GETTING_STARTED.md — the steps in
the order to actually do them in, sandbox through production.
docs/FUNCTIONALITY_GUIDE.md is the deeper reference once you're
underway: what Sales, PreSales, Marketing, and CS can each do once
it's live, what to edit for your org's specific schema before
rollout, and what you need in Claude to use it (short answer: not a
Project).
Two ways to run this
Local ( | Remote ( | |
Who it's for | One person, their own laptop | A team sharing one always-on connection |
Transport | stdio (Claude Desktop launches it as a subprocess) | Streamable HTTP (a normal web service) |
Where credentials live |
| A secret in your cloud provider's secret manager |
Setup |
| Same auth step once, then deploy the container — see "Deploying to the cloud" |
Needs your laptop running | Yes | No — it's just a URL |
Same tools, same tools/ modules, same sf_client.py/mc_client.py either
way. The only thing that changes between the two is the transport layer
and where the Salesforce session lives — nothing about what the server
can do.
Related MCP server: Salesforce MCP Server
Why two connections
Sales Cloud and Service Cloud share one core Salesforce REST API and one
OAuth login — that's sf_client.py. Marketing Cloud is a separate
Salesforce product with its own subdomain, its own API, and its own
server-to-server auth — that's mc_client.py. You can set up one, the
other, or both, and Claude will only see tools for the ones you configure.
Architecture
Tools are organized one file per function in tools/, all sharing the
same two API clients. Adding a tool — or a whole new domain — never
requires touching auth or the other domains; see CONTRIBUTING.md.
Claude Desktop (MCP Client) Any MCP-over-HTTP client
│ stdio, one subprocess │ HTTPS, one URL
▼ ▼
server.py server_remote.py
(runs tools/*, mcp.run()) (runs tools/*, Streamable HTTP +
│ bearer-token check + /health)
└──────────────┬─────────────────────────────┘
▼
├── tools/core.py ─┐
├── tools/sales.py │ all built on
├── tools/presales.py │ sf_client.py
├── tools/marketing.py │ (SOQL, describe,
├── tools/customer_success.py ─┘ any object)
│
└── tools/marketing_cloud.py ── mc_client.py
(Data Extensions, Journeys)
│ │
▼ ▼
Sales/Service Cloud Marketing Cloud
REST API, OAuth REST API, OAuth
(Authorization Code (Client Credentials —
+ PKCE — browser server-to-server,
login, per user) no browser)Try it without a live org first
demo_server.py exposes the same tool shapes against fictional local
data in data/demo_salesforce.json — no Salesforce credentials needed.
Point Claude Desktop's config at demo_server.py instead of server.py
to explore before connecting a real org.
Setup
1. Install dependencies
python3 -m pip install -r requirements.txt
cp .env.example .env2. Connect Sales Cloud / Service Cloud
Create a Connected App in your org: Setup → App Manager → New Connected App
Enable OAuth Settings
Callback URL:
http://localhost:8765/callbackSelected OAuth Scopes:
api,refresh_token,offline_accessCheck Require Proof Key for Code Exchange (PKCE)
Save, then copy the Consumer Key into
SF_CLIENT_IDin.env(leaveSF_CLIENT_SECRETblank if you enabled PKCE without a secret)
Then run:
python3 setup_salesforce_auth.pyThis opens a browser, you log in and approve access once, and a refresh
token is saved locally to .salesforce_token.json (gitignored — never
commit this). The server refreshes it silently after that.
3. Connect Marketing Cloud (optional)
Create an API Integration package: Setup → Apps → Installed Packages →
New, choose "API Integration" with a server-to-server grant. Copy the
Client ID, Client Secret, and your tenant subdomain into .env as
MC_CLIENT_ID, MC_CLIENT_SECRET, MC_SUBDOMAIN (and MC_ACCOUNT_ID if
you use Business Units).
Then run:
python3 setup_marketing_cloud_auth.py4. Point Claude Desktop at this server
Edit ~/Library/Application Support/Claude/claude_desktop_config.json
(macOS) or the equivalent on your OS:
{
"mcpServers": {
"salesforce-cloud": {
"command": "python3",
"args": ["/absolute/path/to/salesforce-mcp-server/server.py"]
}
}
}Restart Claude Desktop. You should see the tool count increase.
Deploying to the cloud (remote variant)
Before deploying anywhere, test server_remote.py locally first:
python3 server_remote.py
curl http://localhost:8080/health # should return "ok"If you see RuntimeError: Task group is not initialized on an actual
MCP request (not /health), that's a real, previously-confirmed SDK
gotcha with mounting streamable_http_app() — this repo already wires
the fix (an explicit lifespan that runs mcp.session_manager.run()
in server_remote.py), so seeing it would mean your installed mcp
package predates the session_manager attribute; run
pip install --upgrade mcp and retry.
Use this when you want a shared, always-on connection instead of something that only works while your laptop is running. All three clouds below follow the same shape:
Authenticate locally, once. Even for a cloud deployment, run
python3 setup_salesforce_auth.pyon your own machine first — it's the only step that needs a browser. Open the.salesforce_token.jsonit creates and copy therefresh_tokenvalue.Set secrets in the cloud, not in the image. You'll set four things as platform secrets/env vars on whichever service you pick:
SF_CLIENT_ID,SF_REFRESH_TOKEN(the value you just copied),MCP_SHARED_SECRET(any long random string — generate one withpython3 -c "import secrets; print(secrets.token_urlsafe(32))"), and, if you're using it, theMC_*Marketing Cloud variables.Build and push the container.
docker build -t salesforce-mcp-server .Deploy (provider-specific steps below).
Point your MCP client at
https://<your-service-url>/, sendingAuthorization: Bearer <your MCP_SHARED_SECRET>on every request. Claude.ai's custom connectors and Claude Desktop's remote server support both let you set a bearer token when adding an HTTP MCP server — checkdocs.claude.comfor the current steps in whichever client you're connecting from, since that UI does change.
Salesforce refresh tokens don't rotate on each use by default, so a
static secret is fine for the common case. If your org's Connected App
policy does rotate them, you'll need to re-run step 1 periodically and
update the secret — a fully self-refreshing setup would need a small
database to persist rotated tokens, which is a reasonable next step if
you outgrow this (see CONTRIBUTING.md).
On access control: MCP_SHARED_SECRET is a floor, not a ceiling.
It stops a stranger who finds the URL from calling your Salesforce
data, but it's one static string, not real per-user authentication.
For anything beyond a small trusted team, also restrict access at the
network/IAM layer using whichever mechanism your cloud offers (below),
and treat this deployment as reachable only by people you'd trust with
direct Salesforce API access.
AWS — App Runner
App Runner is the least infrastructure for a single always-on container: it builds TLS termination and a public HTTPS URL in for you.
Push the image to ECR:
aws ecr create-repository --repository-name salesforce-mcp-server aws ecr get-login-password | docker login --username AWS --password-stdin <account-id>.dkr.ecr.<region>.amazonaws.com docker tag salesforce-mcp-server:latest <account-id>.dkr.ecr.<region>.amazonaws.com/salesforce-mcp-server:latest docker push <account-id>.dkr.ecr.<region>.amazonaws.com/salesforce-mcp-server:latestStore the secrets in AWS Secrets Manager (
aws secretsmanager create-secret ...), one per variable, or one JSON secret with all of them.Create the App Runner service, either via the console (Source: this ECR image) or
aws apprunner create-service. Under Configuration → Environment variables, add non-secret vars (PORTis set for you) and reference each Secrets Manager secret forSF_CLIENT_ID,SF_REFRESH_TOKEN,MCP_SHARED_SECRET.App Runner gives you an
https://<random>.<region>.awsapprunner.comURL with TLS already handled.For network-layer restriction beyond the bearer token: put App Runner behind a VPC Ingress Connection restricted to a VPN/VPC, or front it with API Gateway and an API key/usage plan.
Already running ECS? The same image works fine on ECS Fargate behind an Application Load Balancer instead — same secrets, same env vars, more setup (task definition, service, ALB target group, security groups) in exchange for more control (VPC placement, existing CI/CD, etc.).
Google Cloud — Cloud Run
Cloud Run is the simplest of the three — one command, HTTPS and scale-to-zero included.
Build and push with Cloud Build (no local Docker needed):
gcloud builds submit --tag gcr.io/<project-id>/salesforce-mcp-serverStore secrets in Secret Manager:
echo -n "<value>" | gcloud secrets create SF_REFRESH_TOKEN --data-file=- # repeat for SF_CLIENT_ID, MCP_SHARED_SECRET, and any MC_* variablesDeploy:
gcloud run deploy salesforce-mcp-server \ --image gcr.io/<project-id>/salesforce-mcp-server \ --set-secrets SF_CLIENT_ID=SF_CLIENT_ID:latest,SF_REFRESH_TOKEN=SF_REFRESH_TOKEN:latest,MCP_SHARED_SECRET=MCP_SHARED_SECRET:latest \ --no-allow-unauthenticated--no-allow-unauthenticatedmeans Cloud Run's own IAM sits in front of the bearer-token check — callers also need a Google-signed identity token (gcloud auth print-identity-token) or aninvoker-role service account. If your MCP client can't send that, use--allow-unauthenticatedinstead and rely onMCP_SHARED_SECRETalone — the honest tradeoff between the two is convenience vs. a second layer of access control.
Azure — Container Apps
Container Apps is Azure's closest match to Cloud Run/App Runner: managed HTTPS, scale-to-zero, no cluster to run yourself.
Push the image to Azure Container Registry:
az acr build --registry <your-registry> --image salesforce-mcp-server:latest .Store secrets:
az containerapp secret set --name salesforce-mcp-server \ --resource-group <your-rg> \ --secrets sf-refresh-token=<value> mcp-shared-secret=<value>Create/update the app, wiring secrets to env vars:
az containerapp create \ --name salesforce-mcp-server --resource-group <your-rg> \ --image <your-registry>.azurecr.io/salesforce-mcp-server:latest \ --target-port 8080 --ingress external \ --secrets sf-client-id=<value> sf-refresh-token=<value> mcp-shared-secret=<value> \ --env-vars SF_CLIENT_ID=secretref:sf-client-id SF_REFRESH_TOKEN=secretref:sf-refresh-token MCP_SHARED_SECRET=secretref:mcp-shared-secretFor network-layer restriction: add an IP restriction under Networking, or put Easy Auth (Azure AD) in front for real per-user authentication instead of relying on the shared secret alone.
Tools exposed
Core (tools/core.py) — the foundation everything else is built on
Tool | Description |
| List every object this user can query |
| List fields and picklist values on an object |
| Run any SOQL query against any object |
| Open pipeline with stage, amount, close date |
Sales (tools/sales.py)
Tool | Description |
| Open deal count and total amount, grouped by stage |
| Largest open deals by amount |
| Open deals closing within N days |
| Leads filtered by status/source |
| MUTATING — logs a Task (call note, follow-up) on any record |
PreSales (tools/presales.py)
Tool | Description |
| Full deal context: stage, next steps, contact roles |
| Products/line items quoted on a deal |
| One-call full picture: account, opps, cases, contacts, recent activity |
Marketing (tools/marketing.py) — core Salesforce Campaigns
Tool | Description |
| Campaigns with lead/opportunity/revenue rollups |
| Cost-per-lead, cost-per-opportunity, ROI multiple for one campaign |
| Leads/Contacts on a campaign by member status |
| Lead volume and conversion, grouped by source |
Customer Success (tools/customer_success.py)
Tool | Description |
| Open support cases by priority |
| Open opportunities closing within N days |
| Best-effort risk view: low probability + open high-priority cases |
| Fast health snapshot: case load, last activity, open opps |
Marketing Cloud (tools/marketing_cloud.py) — separate product, separate connection
Tool | Description |
| List Data Extensions (subscriber/campaign tables) |
| Read rows from a Data Extension |
| List Journey Builder journeys |
A few of these (sf_get_at_risk_accounts, sf_get_renewals_due) only
know about standard Opportunity/Case fields. If your org tracks health
score, NPS, or renewal date on a custom field, use sf_describe_object
to find it and query it directly with sf_query — Claude can build
that SOQL for you. Want a tool this list doesn't have? See
CONTRIBUTING.md — it's a five-minute addition.
Example prompts
Sales: "Summarize my pipeline by stage, then show me the 10 biggest open deals."
PreSales: "Give me the full picture on the Acme Corp opportunity before my demo tomorrow — stage, contacts involved, and what products are on the quote."
Marketing: "Which campaigns from this quarter had the best ROI, and which lead sources are converting best in the last 90 days?"
Customer Success: "Pull all open opportunities closing in the next 60 days with less than 50% probability, cross-referenced with open high-priority cases. Then log a follow-up task on the riskiest one."
Cross-functional: "Give me the account 360 for Acme Corp — I want cases, open deals, contacts, and recent activity in one shot before the QBR."
Marketing Cloud: "List our Marketing Cloud journeys and cross-reference with accounts that have Opportunities in Negotiation."
Security notes
.env,.salesforce_token.json, and.mc_token.jsonare all gitignored — double check before committing that neither shows up ingit status. The.dockerignoreexcludes them from the container image too.Refresh tokens and MC client secrets are read only from environment variables or the local token cache — never hardcoded in source.
Revoke access anytime from Salesforce Setup → Connected Apps OAuth Usage, or Marketing Cloud → Installed Packages. Revoking also invalidates any
SF_REFRESH_TOKENyou've copied into a cloud secret.sf_log_activity_noteis the one mutating tool in this repo — it writes a Task back to Salesforce. Every other tool is read-only. If you add new tools (seeCONTRIBUTING.md), keep that same split visible: mutating tools should say so plainly in their docstring.The remote variant is a normal web service the moment you deploy it — anyone with the URL and the bearer token can call your Salesforce tools.
MCP_SHARED_SECRETis required before you deploy anywhere network-reachable (server_remote.pyprints a warning and still runs without it, which is only meant for local testing behind a firewall). Layer network/IAM restrictions on top per the cloud sections above for anything beyond a small trusted team.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Connect your team's living knowledge base — docs, data, issues, CRM — to Claude and ChatGPT.
GA4, Google Ads and Search Console in Claude. Read-only OAuth, multi-account for agencies.
Talk to your live-events CRM (campaigns, analytics, paid ads, segments) in Claude and ChatGPT.
Query 40 databases from Claude, ChatGPT, or Cursor — on any device. Read-only, encrypted, audited.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceIntegrates Claude with Salesforce to enable natural language querying, modification, and management of Salesforce records and metadata. It supports comprehensive operations including object/field management, SOSL searches, and Apex code execution.9951MIT
- AlicenseAqualityDmaintenanceIntegrates Claude with Salesforce for natural language interactions with Salesforce data and metadata, enabling querying, modifying, and managing objects and records.2018MIT
- AlicenseAqualityDmaintenanceEnables AI tools like Claude Desktop and Cline to interact with Salesforce, providing tools for SOQL queries, Apex execution, metadata management, and more.173343MIT
- FlicenseNot gradedqualityDmaintenanceEnables Claude to interact with Salesforce for querying, modifying, and managing objects and records, with automatic integration setup for external services like WhatsApp, Slack, email, and webhooks.-