sf-mcp-server 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. sf_mcp_server-0.1.0/.dockerignore +10 -0
  2. sf_mcp_server-0.1.0/.env.example +22 -0
  3. sf_mcp_server-0.1.0/.github/workflows/ci.yml +34 -0
  4. sf_mcp_server-0.1.0/.gitignore +11 -0
  5. sf_mcp_server-0.1.0/Dockerfile +21 -0
  6. sf_mcp_server-0.1.0/LICENSE +21 -0
  7. sf_mcp_server-0.1.0/PKG-INFO +207 -0
  8. sf_mcp_server-0.1.0/README.md +170 -0
  9. sf_mcp_server-0.1.0/docs/ARCHITECTURE.md +492 -0
  10. sf_mcp_server-0.1.0/docs/AUTHENTICATION.md +213 -0
  11. sf_mcp_server-0.1.0/docs/DEPLOYMENT.md +151 -0
  12. sf_mcp_server-0.1.0/docs/EXTENDING.md +207 -0
  13. sf_mcp_server-0.1.0/docs/MCP_PRIMER.md +149 -0
  14. sf_mcp_server-0.1.0/docs/SETUP.md +156 -0
  15. sf_mcp_server-0.1.0/docs/USAGE.md +457 -0
  16. sf_mcp_server-0.1.0/pyproject.toml +72 -0
  17. sf_mcp_server-0.1.0/scripts/diagnose_pubsub.py +122 -0
  18. sf_mcp_server-0.1.0/scripts/generate_pubsub_stubs.sh +24 -0
  19. sf_mcp_server-0.1.0/src/salesforce_mcp/__init__.py +1 -0
  20. sf_mcp_server-0.1.0/src/salesforce_mcp/auth/__init__.py +19 -0
  21. sf_mcp_server-0.1.0/src/salesforce_mcp/auth/client_credentials.py +33 -0
  22. sf_mcp_server-0.1.0/src/salesforce_mcp/auth/errors.py +7 -0
  23. sf_mcp_server-0.1.0/src/salesforce_mcp/auth/pkce.py +61 -0
  24. sf_mcp_server-0.1.0/src/salesforce_mcp/config.py +82 -0
  25. sf_mcp_server-0.1.0/src/salesforce_mcp/elicitation.py +47 -0
  26. sf_mcp_server-0.1.0/src/salesforce_mcp/errors.py +132 -0
  27. sf_mcp_server-0.1.0/src/salesforce_mcp/http_auth.py +26 -0
  28. sf_mcp_server-0.1.0/src/salesforce_mcp/login.py +209 -0
  29. sf_mcp_server-0.1.0/src/salesforce_mcp/prompts.py +114 -0
  30. sf_mcp_server-0.1.0/src/salesforce_mcp/pubsub/__init__.py +0 -0
  31. sf_mcp_server-0.1.0/src/salesforce_mcp/pubsub/pubsub_api.proto +413 -0
  32. sf_mcp_server-0.1.0/src/salesforce_mcp/pubsub/pubsub_api_pb2.py +75 -0
  33. sf_mcp_server-0.1.0/src/salesforce_mcp/pubsub/pubsub_api_pb2.pyi +206 -0
  34. sf_mcp_server-0.1.0/src/salesforce_mcp/pubsub/pubsub_api_pb2_grpc.py +422 -0
  35. sf_mcp_server-0.1.0/src/salesforce_mcp/pubsub_client.py +172 -0
  36. sf_mcp_server-0.1.0/src/salesforce_mcp/resources.py +39 -0
  37. sf_mcp_server-0.1.0/src/salesforce_mcp/salesforce_client.py +123 -0
  38. sf_mcp_server-0.1.0/src/salesforce_mcp/server.py +104 -0
  39. sf_mcp_server-0.1.0/src/salesforce_mcp/tools/__init__.py +0 -0
  40. sf_mcp_server-0.1.0/src/salesforce_mcp/tools/bulk.py +160 -0
  41. sf_mcp_server-0.1.0/src/salesforce_mcp/tools/composite.py +35 -0
  42. sf_mcp_server-0.1.0/src/salesforce_mcp/tools/custom_api.py +60 -0
  43. sf_mcp_server-0.1.0/src/salesforce_mcp/tools/describe.py +72 -0
  44. sf_mcp_server-0.1.0/src/salesforce_mcp/tools/ops.py +51 -0
  45. sf_mcp_server-0.1.0/src/salesforce_mcp/tools/org_health.py +60 -0
  46. sf_mcp_server-0.1.0/src/salesforce_mcp/tools/query.py +82 -0
  47. sf_mcp_server-0.1.0/src/salesforce_mcp/tools/records.py +94 -0
  48. sf_mcp_server-0.1.0/src/salesforce_mcp/tools/sf_login.py +49 -0
  49. sf_mcp_server-0.1.0/src/salesforce_mcp/tools/subscribe.py +133 -0
  50. sf_mcp_server-0.1.0/tests/__init__.py +0 -0
  51. sf_mcp_server-0.1.0/tests/conftest.py +62 -0
  52. sf_mcp_server-0.1.0/tests/test_auth_client_credentials.py +35 -0
  53. sf_mcp_server-0.1.0/tests/test_auth_factory.py +19 -0
  54. sf_mcp_server-0.1.0/tests/test_auth_pkce.py +106 -0
  55. sf_mcp_server-0.1.0/tests/test_elicitation.py +59 -0
  56. sf_mcp_server-0.1.0/tests/test_errors.py +62 -0
  57. sf_mcp_server-0.1.0/tests/test_login.py +141 -0
  58. sf_mcp_server-0.1.0/tests/test_prompts.py +81 -0
  59. sf_mcp_server-0.1.0/tests/test_pubsub_client.py +152 -0
  60. sf_mcp_server-0.1.0/tests/test_resources.py +53 -0
  61. sf_mcp_server-0.1.0/tests/test_salesforce_client.py +132 -0
  62. sf_mcp_server-0.1.0/tests/tools/__init__.py +0 -0
  63. sf_mcp_server-0.1.0/tests/tools/test_bulk.py +180 -0
  64. sf_mcp_server-0.1.0/tests/tools/test_composite.py +45 -0
  65. sf_mcp_server-0.1.0/tests/tools/test_custom_api.py +69 -0
  66. sf_mcp_server-0.1.0/tests/tools/test_describe.py +84 -0
  67. sf_mcp_server-0.1.0/tests/tools/test_ops.py +33 -0
  68. sf_mcp_server-0.1.0/tests/tools/test_org_health.py +65 -0
  69. sf_mcp_server-0.1.0/tests/tools/test_query.py +107 -0
  70. sf_mcp_server-0.1.0/tests/tools/test_records.py +116 -0
  71. sf_mcp_server-0.1.0/tests/tools/test_sf_login.py +124 -0
  72. sf_mcp_server-0.1.0/tests/tools/test_subscribe.py +153 -0
@@ -0,0 +1,10 @@
1
+ .venv/
2
+ .git/
3
+ .github/
4
+ docs/
5
+ tests/
6
+ __pycache__/
7
+ *.pyc
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .env
@@ -0,0 +1,22 @@
1
+ # Copy this file to .env and fill in real values. Never commit .env.
2
+
3
+ # --- Salesforce auth (External Client App, Client Credentials Flow) ---
4
+ # Your org's My Domain login URL, no trailing slash.
5
+ SF_LOGIN_URL=https://your-domain.my.salesforce.com
6
+ SF_CLIENT_ID=your-external-client-app-client-id
7
+ SF_CLIENT_SECRET=your-external-client-app-client-secret
8
+ # Optional, defaults to v61.0.
9
+ SF_API_VERSION=v61.0
10
+
11
+ # --- Transport ---
12
+ # "stdio" (default, for Claude Desktop / local MCP clients) or "http" (hosted).
13
+ MCP_TRANSPORT=stdio
14
+
15
+ # --- Required only when MCP_TRANSPORT=http ---
16
+ # Shared secret clients must send as `Authorization: Bearer <this value>`.
17
+ # Generate one with: python -c "import secrets; print(secrets.token_urlsafe(32))"
18
+ MCP_SERVER_TOKEN=
19
+ # Host/port to bind. PORT is honored first (the convention most container
20
+ # platforms inject automatically); MCP_PORT is a fallback for local use.
21
+ MCP_HOST=0.0.0.0
22
+ PORT=8080
@@ -0,0 +1,34 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ lint-and-test:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.12"
17
+
18
+ - name: Install dependencies
19
+ run: pip install -e ".[dev]"
20
+
21
+ - name: Lint (ruff)
22
+ run: ruff check src tests
23
+
24
+ - name: Test (pytest)
25
+ run: pytest tests/ -v
26
+
27
+ docker-build:
28
+ runs-on: ubuntu-latest
29
+ needs: lint-and-test
30
+ steps:
31
+ - uses: actions/checkout@v4
32
+
33
+ - name: Build image
34
+ run: docker build -t salesforce-mcp-server:ci .
@@ -0,0 +1,11 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ *.egg-info/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ .env
8
+ .salesforce_pkce_token.json
9
+ dist/
10
+ build/
11
+ .DS_Store
@@ -0,0 +1,21 @@
1
+ # Platform-agnostic image: no cloud-vendor SDKs baked in, just Python + a plain
2
+ # HTTP listener on $PORT. Runs on Cloud Run, AWS App Runner/Fargate, Fly.io,
3
+ # Render, a bare VM, or a k8s cluster unchanged — see docs/DEPLOYMENT.md.
4
+
5
+ FROM python:3.12-slim AS builder
6
+ WORKDIR /build
7
+ COPY pyproject.toml README.md ./
8
+ COPY src ./src
9
+ RUN pip install --no-cache-dir --prefix=/install .
10
+
11
+ FROM python:3.12-slim
12
+ WORKDIR /app
13
+ COPY --from=builder /install /usr/local
14
+
15
+ ENV MCP_TRANSPORT=http \
16
+ MCP_HOST=0.0.0.0 \
17
+ PYTHONUNBUFFERED=1
18
+
19
+ EXPOSE 8080
20
+ USER nobody
21
+ CMD ["python", "-m", "salesforce_mcp.server"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SudhakarDH
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,207 @@
1
+ Metadata-Version: 2.5
2
+ Name: sf-mcp-server
3
+ Version: 0.1.0
4
+ Summary: An independent, open-source MCP server for Salesforce (REST, Bulk API 2.0, Composite) — not a Salesforce product.
5
+ Project-URL: Homepage, https://github.com/sudhakar6/salesforce-mcp-server
6
+ Project-URL: Repository, https://github.com/sudhakar6/salesforce-mcp-server
7
+ Project-URL: Documentation, https://github.com/sudhakar6/salesforce-mcp-server/tree/main/docs
8
+ Project-URL: Issues, https://github.com/sudhakar6/salesforce-mcp-server/issues
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: ai-agents,mcp,model-context-protocol,salesforce,soql
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: fastavro>=1.9
22
+ Requires-Dist: grpcio>=1.66
23
+ Requires-Dist: httpx>=0.27
24
+ Requires-Dist: mcp[cli]>=2.1.0
25
+ Requires-Dist: protobuf>=5
26
+ Requires-Dist: python-dotenv>=1.0
27
+ Requires-Dist: starlette>=0.37
28
+ Requires-Dist: uvicorn>=0.30
29
+ Provides-Extra: codegen
30
+ Requires-Dist: grpcio-tools>=1.66; extra == 'codegen'
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
33
+ Requires-Dist: pytest>=8.0; extra == 'dev'
34
+ Requires-Dist: respx>=0.21; extra == 'dev'
35
+ Requires-Dist: ruff>=0.6; extra == 'dev'
36
+ Description-Content-Type: text/markdown
37
+
38
+ # Salesforce MCP Server
39
+
40
+ A custom-built, self-hosted MCP server that lets AI agents (Claude Desktop,
41
+ Claude Code, the MCP Inspector, or any other MCP client) connect to
42
+ Salesforce — to query, search, and modify data in an org.
43
+
44
+ > **Not a Salesforce product.** This is an independent, personal learning
45
+ > project — not affiliated with, endorsed by, or supported by Salesforce,
46
+ > Inc. Full explanation: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#not-a-salesforce-product).
47
+
48
+ > **New to MCP?** If "server," "client," and "tool call" aren't already
49
+ > familiar terms, read [docs/MCP_PRIMER.md](docs/MCP_PRIMER.md) first — five
50
+ > minutes, and everything else here will make more sense.
51
+
52
+ ## Quickstart
53
+
54
+ **You'll need:** a Salesforce org with an External Client App set up — a
55
+ free [Developer Edition org](https://developer.salesforce.com/signup) works
56
+ fine — and its Consumer Key in hand. [docs/SETUP.md](docs/SETUP.md) walks
57
+ through creating that (10–15 min); do it first, then come back here.
58
+
59
+ Three ways to get a running server — pick whichever fits:
60
+
61
+ **Option A — `uvx`** (fastest; no clone, no venv; requires [uv](https://docs.astral.sh/uv/getting-started/installation/)):
62
+
63
+ ```bash
64
+ export SF_LOGIN_URL=https://your-domain.my.salesforce.com
65
+ export SF_CLIENT_ID=your-client-id
66
+ uvx sf-mcp-login # one-time interactive login — opens your browser
67
+ uvx sf-mcp-server
68
+ ```
69
+
70
+ Or drop straight into an MCP client's config (Claude Desktop's
71
+ `claude_desktop_config.json`, Claude Code's `.mcp.json`) with `"command":
72
+ "uvx", "args": ["sf-mcp-server"]` and the same env vars — see
73
+ [docs/USAGE.md](docs/USAGE.md) for full client config examples. That login
74
+ step is only needed once — see [docs/AUTHENTICATION.md](docs/AUTHENTICATION.md)
75
+ for what it does and why, and for the alternative Client Credentials Flow
76
+ (`SF_CLIENT_SECRET`, no login step) if you'd rather use a fixed service
77
+ identity instead.
78
+
79
+ **Option B — Python from source** (for contributing, or if you'd rather not
80
+ use `uv`):
81
+
82
+ ```bash
83
+ git clone <this-repo-url> && cd salesforce-mcp-server
84
+ python3 -m venv .venv && source .venv/bin/activate
85
+ pip install -e ".[dev]"
86
+ cp .env.example .env # fill in SF_LOGIN_URL / SF_CLIENT_ID
87
+ python -m salesforce_mcp.login # one-time interactive login — opens your browser
88
+ python -m salesforce_mcp.server
89
+ ```
90
+
91
+ **Option C — Docker** (no Python setup needed; requires Docker installed
92
+ *and running* — check with `docker info`):
93
+
94
+ ```bash
95
+ git clone <this-repo-url> && cd salesforce-mcp-server
96
+ docker build -t salesforce-mcp-server .
97
+ docker run --rm -i \
98
+ -e SF_LOGIN_URL=https://your-domain.my.salesforce.com \
99
+ -e SF_CLIENT_ID=your-client-id \
100
+ -e SF_CLIENT_SECRET=your-client-secret \
101
+ -e SF_AUTH_FLOW=client_credentials \
102
+ -e MCP_TRANSPORT=stdio \
103
+ salesforce-mcp-server
104
+ ```
105
+
106
+ Docker explicitly pins `SF_AUTH_FLOW=client_credentials` here rather than
107
+ using the default interactive login — there's no browser or display inside
108
+ a container for that flow to use. See
109
+ [docs/AUTHENTICATION.md](docs/AUTHENTICATION.md) if you actually want PKCE
110
+ in a container anyway (mount a pre-existing `.salesforce_pkce_token.json`
111
+ from the host).
112
+
113
+ Whichever you pick, that's it running. **Next:** point the
114
+ [MCP Inspector](https://github.com/modelcontextprotocol/inspector) or Claude
115
+ Desktop at it and actually try a tool — see [docs/USAGE.md](docs/USAGE.md).
116
+
117
+ Quick note on that `-e MCP_TRANSPORT=stdio` flag in Option C: **Python vs.
118
+ Docker and stdio vs. HTTP are two separate choices, not tied together** —
119
+ Python defaults to stdio and Docker's image defaults to HTTP purely for
120
+ convenience, but all four combinations actually work. See
121
+ [docs/MCP_PRIMER.md#the-two-transports-stdio-and-streamable-http](docs/MCP_PRIMER.md#the-two-transports-stdio-and-streamable-http)
122
+ for what each transport actually is and why. For hosting this on a network
123
+ instead of running it locally, see [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md).
124
+
125
+ ## What it can do
126
+
127
+ - **Query & search** — `sf_query` (SOQL, auto-paginated), `sf_search` (SOSL)
128
+ - **Record CRUD** — `sf_get_record`, `sf_create_record`, `sf_update_record`,
129
+ `sf_upsert_record` (by external ID), `sf_delete_record`
130
+ - **Bulk API 2.0** — `sf_bulk_query`, `sf_bulk_load`, for record volumes too
131
+ large for the one-record-per-call REST tools above
132
+ - **Composite** — `sf_composite`, to bundle several sub-requests into one
133
+ atomic call
134
+ - **Describe/discovery** — `sf_describe_object`, `sf_list_objects` (trimmed
135
+ fields + optional `name_contains`/`custom_only` filters, so it doesn't
136
+ dump 800+ objects' full raw metadata), also available as MCP **Resources**
137
+ (`salesforce://objects`, `salesforce://schema/{sobject}`)
138
+ - **Ops** — `sf_api_usage` (quick API-limit check), `sf_org_health` (fuller
139
+ report: org info, all limits, and license seat usage)
140
+ - **Custom APIs** — `sf_call_apex_rest` calls any custom Apex REST endpoint
141
+ (`@RestResource`) your org exposes, no code changes needed — see
142
+ [docs/USAGE.md](docs/USAGE.md#calling-a-custom-apex-rest-api)
143
+ - **Prompts** — ready-made task templates for common requests:
144
+ `summarize_account`, `draft_followup_email`, `data_hygiene_check` — see
145
+ [docs/USAGE.md](docs/USAGE.md#prompts)
146
+ - **Platform events / Change Data Capture** — `sf_subscribe_platform_event`
147
+ replays a bounded batch of events from a platform event or CDC channel,
148
+ honoring Salesforce's 72-hour Pub/Sub API retention window — see
149
+ [docs/USAGE.md](docs/USAGE.md#subscribing-to-platform-events)
150
+ - **Elicitation** — confirms before an unscoped `sf_query`/`sf_search` or any
151
+ delete (`sf_delete_record`, `sf_bulk_load(operation="delete")`); disable
152
+ with `SF_ELICITATION_ENABLED=false` — see
153
+ [docs/USAGE.md](docs/USAGE.md#elicitation)
154
+ - **Two auth options** — the default interactive "Login with Salesforce"
155
+ (OAuth Authorization Code + PKCE, per-user), via `python -m
156
+ salesforce_mcp.login` or the in-session `sf_login` tool, or the OAuth
157
+ Client Credentials Flow (one fixed service identity) for headless/shared
158
+ use, switched with `SF_AUTH_FLOW=client_credentials` — see
159
+ [docs/AUTHENTICATION.md](docs/AUTHENTICATION.md)
160
+ - **Resilient by default** — retries transient (5xx / `REQUEST_LIMIT_EXCEEDED`)
161
+ Salesforce errors automatically; every other error comes back as a clean,
162
+ readable message instead of a stack trace
163
+
164
+ **Every tool above talks to a standard Salesforce API out of the box** — none
165
+ of them are specific to any one org. Two ways to add your own: call
166
+ `sf_call_apex_rest` (works today, zero code) or add a first-class tool of
167
+ your own — [docs/EXTENDING.md](docs/EXTENDING.md) is a step-by-step guide.
168
+
169
+ ## Running it remotely (cloud)
170
+
171
+ The same server also runs as a container behind a network-reachable
172
+ Streamable HTTP endpoint, for when you want an agent that isn't on the same
173
+ machine to reach it. **This has been built and run locally with Docker and
174
+ confirmed working — it has not yet been deployed to a real cloud account.**
175
+ [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) has the full picture, including that
176
+ caveat up front, plus two ready-to-try recipes (GCP Cloud Run, AWS App
177
+ Runner).
178
+
179
+ ## Tests
180
+
181
+ ```bash
182
+ pytest tests/ -v # all Salesforce calls are mocked with respx — no live org needed
183
+ ruff check src tests
184
+ ```
185
+
186
+ This is the automated suite — fast, no Salesforce org or Docker required.
187
+ There are two other, manual checks, each testing something different:
188
+ Inspector-against-a-real-org (functional — see [docs/USAGE.md](docs/USAGE.md))
189
+ and Docker-build-and-curl (plumbing only — see [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md#build-and-run-locally-first)).
190
+
191
+ ## Documentation
192
+
193
+ Read in this order if you're getting started:
194
+
195
+ | # | Doc | For |
196
+ |---|---|---|
197
+ | 1 | [docs/MCP_PRIMER.md](docs/MCP_PRIMER.md) | New to MCP — what a server/client/tool call actually is |
198
+ | 2 | [docs/SETUP.md](docs/SETUP.md) | Creating the Salesforce org + integration, `.env` config |
199
+ | 3 | [docs/AUTHENTICATION.md](docs/AUTHENTICATION.md) | Both auth flows side by side — Client Credentials vs. "Login with Salesforce" (PKCE) |
200
+ | 4 | [docs/USAGE.md](docs/USAGE.md) | Running it — Claude Desktop, Claude Code, MCP Inspector, example prompts |
201
+ | 5 | [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) | Hosting it in the cloud instead of locally |
202
+ | 6 | [docs/EXTENDING.md](docs/EXTENDING.md) | Adding your own tool for a custom API |
203
+ | 7 | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Optional — how and why it was built this way |
204
+
205
+ ## License
206
+
207
+ [MIT](LICENSE)
@@ -0,0 +1,170 @@
1
+ # Salesforce MCP Server
2
+
3
+ A custom-built, self-hosted MCP server that lets AI agents (Claude Desktop,
4
+ Claude Code, the MCP Inspector, or any other MCP client) connect to
5
+ Salesforce — to query, search, and modify data in an org.
6
+
7
+ > **Not a Salesforce product.** This is an independent, personal learning
8
+ > project — not affiliated with, endorsed by, or supported by Salesforce,
9
+ > Inc. Full explanation: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#not-a-salesforce-product).
10
+
11
+ > **New to MCP?** If "server," "client," and "tool call" aren't already
12
+ > familiar terms, read [docs/MCP_PRIMER.md](docs/MCP_PRIMER.md) first — five
13
+ > minutes, and everything else here will make more sense.
14
+
15
+ ## Quickstart
16
+
17
+ **You'll need:** a Salesforce org with an External Client App set up — a
18
+ free [Developer Edition org](https://developer.salesforce.com/signup) works
19
+ fine — and its Consumer Key in hand. [docs/SETUP.md](docs/SETUP.md) walks
20
+ through creating that (10–15 min); do it first, then come back here.
21
+
22
+ Three ways to get a running server — pick whichever fits:
23
+
24
+ **Option A — `uvx`** (fastest; no clone, no venv; requires [uv](https://docs.astral.sh/uv/getting-started/installation/)):
25
+
26
+ ```bash
27
+ export SF_LOGIN_URL=https://your-domain.my.salesforce.com
28
+ export SF_CLIENT_ID=your-client-id
29
+ uvx sf-mcp-login # one-time interactive login — opens your browser
30
+ uvx sf-mcp-server
31
+ ```
32
+
33
+ Or drop straight into an MCP client's config (Claude Desktop's
34
+ `claude_desktop_config.json`, Claude Code's `.mcp.json`) with `"command":
35
+ "uvx", "args": ["sf-mcp-server"]` and the same env vars — see
36
+ [docs/USAGE.md](docs/USAGE.md) for full client config examples. That login
37
+ step is only needed once — see [docs/AUTHENTICATION.md](docs/AUTHENTICATION.md)
38
+ for what it does and why, and for the alternative Client Credentials Flow
39
+ (`SF_CLIENT_SECRET`, no login step) if you'd rather use a fixed service
40
+ identity instead.
41
+
42
+ **Option B — Python from source** (for contributing, or if you'd rather not
43
+ use `uv`):
44
+
45
+ ```bash
46
+ git clone <this-repo-url> && cd salesforce-mcp-server
47
+ python3 -m venv .venv && source .venv/bin/activate
48
+ pip install -e ".[dev]"
49
+ cp .env.example .env # fill in SF_LOGIN_URL / SF_CLIENT_ID
50
+ python -m salesforce_mcp.login # one-time interactive login — opens your browser
51
+ python -m salesforce_mcp.server
52
+ ```
53
+
54
+ **Option C — Docker** (no Python setup needed; requires Docker installed
55
+ *and running* — check with `docker info`):
56
+
57
+ ```bash
58
+ git clone <this-repo-url> && cd salesforce-mcp-server
59
+ docker build -t salesforce-mcp-server .
60
+ docker run --rm -i \
61
+ -e SF_LOGIN_URL=https://your-domain.my.salesforce.com \
62
+ -e SF_CLIENT_ID=your-client-id \
63
+ -e SF_CLIENT_SECRET=your-client-secret \
64
+ -e SF_AUTH_FLOW=client_credentials \
65
+ -e MCP_TRANSPORT=stdio \
66
+ salesforce-mcp-server
67
+ ```
68
+
69
+ Docker explicitly pins `SF_AUTH_FLOW=client_credentials` here rather than
70
+ using the default interactive login — there's no browser or display inside
71
+ a container for that flow to use. See
72
+ [docs/AUTHENTICATION.md](docs/AUTHENTICATION.md) if you actually want PKCE
73
+ in a container anyway (mount a pre-existing `.salesforce_pkce_token.json`
74
+ from the host).
75
+
76
+ Whichever you pick, that's it running. **Next:** point the
77
+ [MCP Inspector](https://github.com/modelcontextprotocol/inspector) or Claude
78
+ Desktop at it and actually try a tool — see [docs/USAGE.md](docs/USAGE.md).
79
+
80
+ Quick note on that `-e MCP_TRANSPORT=stdio` flag in Option C: **Python vs.
81
+ Docker and stdio vs. HTTP are two separate choices, not tied together** —
82
+ Python defaults to stdio and Docker's image defaults to HTTP purely for
83
+ convenience, but all four combinations actually work. See
84
+ [docs/MCP_PRIMER.md#the-two-transports-stdio-and-streamable-http](docs/MCP_PRIMER.md#the-two-transports-stdio-and-streamable-http)
85
+ for what each transport actually is and why. For hosting this on a network
86
+ instead of running it locally, see [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md).
87
+
88
+ ## What it can do
89
+
90
+ - **Query & search** — `sf_query` (SOQL, auto-paginated), `sf_search` (SOSL)
91
+ - **Record CRUD** — `sf_get_record`, `sf_create_record`, `sf_update_record`,
92
+ `sf_upsert_record` (by external ID), `sf_delete_record`
93
+ - **Bulk API 2.0** — `sf_bulk_query`, `sf_bulk_load`, for record volumes too
94
+ large for the one-record-per-call REST tools above
95
+ - **Composite** — `sf_composite`, to bundle several sub-requests into one
96
+ atomic call
97
+ - **Describe/discovery** — `sf_describe_object`, `sf_list_objects` (trimmed
98
+ fields + optional `name_contains`/`custom_only` filters, so it doesn't
99
+ dump 800+ objects' full raw metadata), also available as MCP **Resources**
100
+ (`salesforce://objects`, `salesforce://schema/{sobject}`)
101
+ - **Ops** — `sf_api_usage` (quick API-limit check), `sf_org_health` (fuller
102
+ report: org info, all limits, and license seat usage)
103
+ - **Custom APIs** — `sf_call_apex_rest` calls any custom Apex REST endpoint
104
+ (`@RestResource`) your org exposes, no code changes needed — see
105
+ [docs/USAGE.md](docs/USAGE.md#calling-a-custom-apex-rest-api)
106
+ - **Prompts** — ready-made task templates for common requests:
107
+ `summarize_account`, `draft_followup_email`, `data_hygiene_check` — see
108
+ [docs/USAGE.md](docs/USAGE.md#prompts)
109
+ - **Platform events / Change Data Capture** — `sf_subscribe_platform_event`
110
+ replays a bounded batch of events from a platform event or CDC channel,
111
+ honoring Salesforce's 72-hour Pub/Sub API retention window — see
112
+ [docs/USAGE.md](docs/USAGE.md#subscribing-to-platform-events)
113
+ - **Elicitation** — confirms before an unscoped `sf_query`/`sf_search` or any
114
+ delete (`sf_delete_record`, `sf_bulk_load(operation="delete")`); disable
115
+ with `SF_ELICITATION_ENABLED=false` — see
116
+ [docs/USAGE.md](docs/USAGE.md#elicitation)
117
+ - **Two auth options** — the default interactive "Login with Salesforce"
118
+ (OAuth Authorization Code + PKCE, per-user), via `python -m
119
+ salesforce_mcp.login` or the in-session `sf_login` tool, or the OAuth
120
+ Client Credentials Flow (one fixed service identity) for headless/shared
121
+ use, switched with `SF_AUTH_FLOW=client_credentials` — see
122
+ [docs/AUTHENTICATION.md](docs/AUTHENTICATION.md)
123
+ - **Resilient by default** — retries transient (5xx / `REQUEST_LIMIT_EXCEEDED`)
124
+ Salesforce errors automatically; every other error comes back as a clean,
125
+ readable message instead of a stack trace
126
+
127
+ **Every tool above talks to a standard Salesforce API out of the box** — none
128
+ of them are specific to any one org. Two ways to add your own: call
129
+ `sf_call_apex_rest` (works today, zero code) or add a first-class tool of
130
+ your own — [docs/EXTENDING.md](docs/EXTENDING.md) is a step-by-step guide.
131
+
132
+ ## Running it remotely (cloud)
133
+
134
+ The same server also runs as a container behind a network-reachable
135
+ Streamable HTTP endpoint, for when you want an agent that isn't on the same
136
+ machine to reach it. **This has been built and run locally with Docker and
137
+ confirmed working — it has not yet been deployed to a real cloud account.**
138
+ [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) has the full picture, including that
139
+ caveat up front, plus two ready-to-try recipes (GCP Cloud Run, AWS App
140
+ Runner).
141
+
142
+ ## Tests
143
+
144
+ ```bash
145
+ pytest tests/ -v # all Salesforce calls are mocked with respx — no live org needed
146
+ ruff check src tests
147
+ ```
148
+
149
+ This is the automated suite — fast, no Salesforce org or Docker required.
150
+ There are two other, manual checks, each testing something different:
151
+ Inspector-against-a-real-org (functional — see [docs/USAGE.md](docs/USAGE.md))
152
+ and Docker-build-and-curl (plumbing only — see [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md#build-and-run-locally-first)).
153
+
154
+ ## Documentation
155
+
156
+ Read in this order if you're getting started:
157
+
158
+ | # | Doc | For |
159
+ |---|---|---|
160
+ | 1 | [docs/MCP_PRIMER.md](docs/MCP_PRIMER.md) | New to MCP — what a server/client/tool call actually is |
161
+ | 2 | [docs/SETUP.md](docs/SETUP.md) | Creating the Salesforce org + integration, `.env` config |
162
+ | 3 | [docs/AUTHENTICATION.md](docs/AUTHENTICATION.md) | Both auth flows side by side — Client Credentials vs. "Login with Salesforce" (PKCE) |
163
+ | 4 | [docs/USAGE.md](docs/USAGE.md) | Running it — Claude Desktop, Claude Code, MCP Inspector, example prompts |
164
+ | 5 | [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) | Hosting it in the cloud instead of locally |
165
+ | 6 | [docs/EXTENDING.md](docs/EXTENDING.md) | Adding your own tool for a custom API |
166
+ | 7 | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Optional — how and why it was built this way |
167
+
168
+ ## License
169
+
170
+ [MIT](LICENSE)