Salesforce MCP Server
A custom-built, self-hosted MCP server that lets AI agents (Claude Desktop, Claude Code, the MCP Inspector, or any other MCP client) connect to Salesforce — to query, search, and modify data in an org.
Not a Salesforce product. This is an independent, personal learning project — not affiliated with, endorsed by, or supported by Salesforce, Inc. Full explanation: docs/ARCHITECTURE.md.
New to MCP? If "server," "client," and "tool call" aren't already familiar terms, read docs/MCP_PRIMER.md first — five minutes, and everything else here will make more sense.
Quickstart
You'll need: a Salesforce org with an External Client App set up — a free Developer Edition org works fine — and its Consumer Key in hand. docs/SETUP.md walks through creating that (10–15 min); do it first, then come back here.
Three ways to get a running server — pick whichever fits:
Option A — uvx (fastest; no clone, no venv; requires uv):
export SF_LOGIN_URL=https://your-domain.my.salesforce.com
export SF_CLIENT_ID=your-client-id
uvx --from sf-mcp-server sf-mcp-login # one-time interactive login — opens your browser
uvx sf-mcp-server
(sf-mcp-login needs the explicit --from sf-mcp-server — uv only infers
the package name from a bare command when they match, and this package
provides two commands. sf-mcp-server matches its own package name, so it
doesn't need --from.)
Or drop straight into an MCP client's config (Claude Desktop's
claude_desktop_config.json, Claude Code's .mcp.json) with "command": "uvx", "args": ["sf-mcp-server"] and the same env vars, plus
SF_PKCE_TOKEN_CACHE set to an absolute path (the client launches the
server from its own working directory, not wherever you ran
sf-mcp-login, so the default relative cache path won't be found
otherwise) — see docs/USAGE.md for the full config
example. That login step is only needed once — see
docs/AUTHENTICATION.md for what it does and why,
and for the alternative Client Credentials Flow (SF_CLIENT_SECRET, no
login step) if you'd rather use a fixed service identity instead.
Option B — Python from source (for contributing, or if you'd rather not
use uv):
git clone <this-repo-url> && cd salesforce-mcp-server
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env # fill in SF_LOGIN_URL / SF_CLIENT_ID
python -m salesforce_mcp.login # one-time interactive login — opens your browser
python -m salesforce_mcp.server
Option C — Docker (no Python setup needed; requires Docker installed
and running — check with docker info):
git clone <this-repo-url> && cd salesforce-mcp-server
docker build -t salesforce-mcp-server .
docker run --rm -i \
-e SF_LOGIN_URL=https://your-domain.my.salesforce.com \
-e SF_CLIENT_ID=your-client-id \
-e SF_CLIENT_SECRET=your-client-secret \
-e SF_AUTH_FLOW=client_credentials \
-e MCP_TRANSPORT=stdio \
salesforce-mcp-server
Docker explicitly pins SF_AUTH_FLOW=client_credentials here rather than
using the default interactive login — there's no browser or display inside
a container for that flow to use. See
docs/AUTHENTICATION.md if you actually want PKCE
in a container anyway (mount a pre-existing .salesforce_pkce_token.json
from the host).
Whichever you pick, that's it running. Next: point the MCP Inspector or Claude Desktop at it and actually try a tool — see docs/USAGE.md.
Quick note on that -e MCP_TRANSPORT=stdio flag in Option C: Python vs.
Docker and stdio vs. HTTP are two separate choices, not tied together —
Python defaults to stdio and Docker's image defaults to HTTP purely for
convenience, but all four combinations actually work. See
docs/MCP_PRIMER.md#the-two-transports-stdio-and-streamable-http
for what each transport actually is and why. For hosting this on a network
instead of running it locally, see docs/DEPLOYMENT.md.
What it can do
- Query & search —
sf_query(SOQL, auto-paginated),sf_search(SOSL) - Record CRUD —
sf_get_record,sf_create_record,sf_update_record,sf_upsert_record(by external ID),sf_delete_record - Bulk API 2.0 —
sf_bulk_query,sf_bulk_load, for record volumes too large for the one-record-per-call REST tools above - Composite —
sf_composite, to bundle several sub-requests into one atomic call - Describe/discovery —
sf_describe_object,sf_list_objects(trimmed fields + optionalname_contains/custom_onlyfilters, so it doesn't dump 800+ objects' full raw metadata), also available as MCP Resources (salesforce://objects,salesforce://schema/{sobject}) - Ops —
sf_api_usage(quick API-limit check),sf_org_health(fuller report: org info, all limits, and license seat usage) - Custom APIs —
sf_call_apex_restcalls any custom Apex REST endpoint (@RestResource) your org exposes, no code changes needed — see docs/USAGE.md - Prompts — ready-made task templates for common requests:
summarize_account,draft_followup_email,data_hygiene_check— see docs/USAGE.md - Platform events / Change Data Capture —
sf_subscribe_platform_eventreplays a bounded batch of events from a platform event or CDC channel, honoring Salesforce's 72-hour Pub/Sub API retention window — see docs/USAGE.md - Elicitation — confirms before an unscoped
sf_query/sf_searchor any delete (sf_delete_record,sf_bulk_load(operation="delete")); disable withSF_ELICITATION_ENABLED=false— see docs/USAGE.md - Two auth options — the default interactive "Login with Salesforce"
(OAuth Authorization Code + PKCE, per-user), via
python -m salesforce_mcp.loginor the in-sessionsf_logintool, or the OAuth Client Credentials Flow (one fixed service identity) for headless/shared use, switched withSF_AUTH_FLOW=client_credentials— see docs/AUTHENTICATION.md - Resilient by default — retries transient (5xx /
REQUEST_LIMIT_EXCEEDED) Salesforce errors automatically; every other error comes back as a clean, readable message instead of a stack trace
Every tool above talks to a standard Salesforce API out of the box — none
of them are specific to any one org. Two ways to add your own: call
sf_call_apex_rest (works today, zero code) or add a first-class tool of
your own — docs/EXTENDING.md is a step-by-step guide.
Running it remotely (cloud)
The same server also runs as a container behind a network-reachable Streamable HTTP endpoint, for when you want an agent that isn't on the same machine to reach it. This has been built and run locally with Docker and confirmed working — it has not yet been deployed to a real cloud account. docs/DEPLOYMENT.md has the full picture, including that caveat up front, plus two ready-to-try recipes (GCP Cloud Run, AWS App Runner).
Tests
pytest tests/ -v # all Salesforce calls are mocked with respx — no live org needed
ruff check src tests
This is the automated suite — fast, no Salesforce org or Docker required. There are two other, manual checks, each testing something different: Inspector-against-a-real-org (functional — see docs/USAGE.md) and Docker-build-and-curl (plumbing only — see docs/DEPLOYMENT.md).
Documentation
Read in this order if you're getting started:
| # | Doc | For |
|---|---|---|
| 1 | docs/MCP_PRIMER.md | New to MCP — what a server/client/tool call actually is |
| 2 | docs/SETUP.md | Creating the Salesforce org + integration, .env config |
| 3 | docs/AUTHENTICATION.md | Both auth flows side by side — Client Credentials vs. "Login with Salesforce" (PKCE) |
| 4 | docs/USAGE.md | Running it — Claude Desktop, Claude Code, MCP Inspector, example prompts |
| 5 | docs/DEPLOYMENT.md | Hosting it in the cloud instead of locally |
| 6 | docs/EXTENDING.md | Adding your own tool for a custom API |
| 7 | docs/RELEASING.md | Maintainers only — how a PyPI release actually gets published |
| 8 | docs/ARCHITECTURE.md | Optional — how and why it was built this way |
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sf_mcp_server-0.1.1.tar.gz.
File metadata
- Download URL: sf_mcp_server-0.1.1.tar.gz
- Upload date:
- Size: 91.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f3fad8cb8c935d2f9046bf536a5f0e54912e8c29e4ac6bad30602c00a5610b21
|
|
| MD5 |
f0b0a2c87fa4173fc095e0d02a57ba47
|
|
| BLAKE2b-256 |
4bff49716c13d6e4b4e36850e62c9553b786b48a9c76c4ad9f27072d04b65d41
|
Provenance
The following attestation bundles were made for sf_mcp_server-0.1.1.tar.gz:
Publisher:
publish.yml on sudhakar6/salesforce-mcp-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sf_mcp_server-0.1.1.tar.gz -
Subject digest:
f3fad8cb8c935d2f9046bf536a5f0e54912e8c29e4ac6bad30602c00a5610b21 - Sigstore transparency entry: 2740081740
- Sigstore integration time:
-
Permalink:
sudhakar6/salesforce-mcp-server@6dd749eda33f8e21d011c60a3f0f85453a5a8c5e -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/sudhakar6
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6dd749eda33f8e21d011c60a3f0f85453a5a8c5e -
Trigger Event:
push
-
Statement type:
File details
Details for the file sf_mcp_server-0.1.1-py3-none-any.whl.
File metadata
- Download URL: sf_mcp_server-0.1.1-py3-none-any.whl
- Upload date:
- Size: 53.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
522de4e3261348163bfd462d744a1322bfc971829692b7b4430616a98c62e72e
|
|
| MD5 |
da02d902763689ba032993a27b5440e7
|
|
| BLAKE2b-256 |
c81751e89e549e0b3272230910523e4b672adf722bce4c60d8a529821aea20a4
|
Provenance
The following attestation bundles were made for sf_mcp_server-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on sudhakar6/salesforce-mcp-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sf_mcp_server-0.1.1-py3-none-any.whl -
Subject digest:
522de4e3261348163bfd462d744a1322bfc971829692b7b4430616a98c62e72e - Sigstore transparency entry: 2740082341
- Sigstore integration time:
-
Permalink:
sudhakar6/salesforce-mcp-server@6dd749eda33f8e21d011c60a3f0f85453a5a8c5e -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/sudhakar6
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6dd749eda33f8e21d011c60a3f0f85453a5a8c5e -
Trigger Event:
push
-
Statement type: