salesforce-remote-mcp-cloudflare

salesforce-remote-mcp-cloudflare

A remote MCP server for Salesforce deployed on Cloudflare Workers, enabling Claude to query and manage Salesforce data through SOQL, SOSL, DML, and Apex with per-user OAuth.

Category
Visit Server

README

salesforce-remote-mcp-cloudflare

A remote MCP (Model Context Protocol) server for Salesforce, deployable on Cloudflare Workers as a Claude custom connector. It exposes the same 15 Salesforce tools as the local stdio package @tsmztech/mcp-server-salesforce — SOQL/SOSL queries, DML, object/field/metadata management, Apex read/write/execute, debug logs — over Streamable HTTP with full per-user OAuth.

This is a self-hosted template, not a hosted service. You (the setup admin) create a Salesforce Connected App in your org, deploy your own Worker with your own credentials, and register your Worker's URL in Claude. Nothing is shared with anyone else, and no credentials ever leave your Cloudflare account and your Salesforce org.

How it works

Claude (web/desktop/mobile)
   │  OAuth 2.1 ─ handled automatically (Dynamic Client Registration, PKCE)
   ▼
Your Cloudflare Worker  ←  this repo
   │  "Login with Salesforce" ─ your Connected App (OAuth Web Server flow + PKCE)
   ▼
Your Salesforce org

There are two separate OAuth relationships:

  1. Claude ↔ Worker — handled entirely by @cloudflare/workers-oauth-provider. You configure nothing for this; Claude registers itself automatically.
  2. Worker ↔ Salesforce — your Connected App. Its consumer key/secret live only in Worker secrets.

When a user clicks Connect in Claude, they are redirected to your org's Salesforce login page. Their Salesforce tokens are stored encrypted inside the OAuth grant and are never visible to Claude or to other users. Every tool call runs as the connected user — their profile, permissions, and field-level security apply. Expired access tokens are refreshed automatically (proactively when Claude refreshes its own token, and reactively on INVALID_SESSION_ID).

One deployment = one Salesforce org. The org (production, sandbox, or a My Domain) is fixed by your configuration. End users don't pick an org — they just log in with their own identity in that org. To serve a second org, deploy a second Worker.

Prerequisites

  • A Cloudflare account (free tier works) — sign up
  • Node.js 18+ and npm
  • A Salesforce org you administer (production, Developer Edition, or sandbox)
  • A Claude plan that supports custom connectors (Pro, Max, Team, or Enterprise)

Step 1 — Deploy the Worker

Deploy first: you need your Worker's URL before you can create the Connected App (its OAuth callback points at the Worker).

git clone <this-repo>
cd salesforce-remote-mcp-cloudflare
npm install --legacy-peer-deps
npx wrangler login

Create the KV namespace the OAuth provider stores its (encrypted) state in:

npx wrangler kv namespace create OAUTH_KV

Copy the printed id into wrangler.jsonc:

"kv_namespaces": [{ "binding": "OAUTH_KV", "id": "<your-id-here>" }],

In the same file, set your org's login host — this pins the deployment to your org:

// production / Developer Edition:  login.salesforce.com
// sandbox:                         test.salesforce.com
// My Domain (recommended):         yourcompany.my.salesforce.com
"vars": { "SALESFORCE_LOGIN_HOST": "login.salesforce.com" }

Set the state-encryption key (any long random value; you never need it again):

openssl rand -base64 32 | npx wrangler secret put COOKIE_ENCRYPTION_KEY

Deploy:

npx wrangler deploy

Note the URL wrangler prints, e.g. https://salesforce-remote-mcp-cloudflare.<your-subdomain>.workers.dev. That is your Worker URL — you'll use it in Steps 2 and 4. (The server won't work yet; it still needs the Connected App credentials from the next step.)

Step 2 — Create the Connected App in Salesforce

Connected Apps can only be created through the Setup UI — the Metadata API blocks programmatic creation, so there is no CLI shortcut for this step.

  1. In your org: Setup → App Manager → New Connected App (in some orgs: New Connected App → Create a Connected App).
  2. Fill in the basics: any name (e.g. Claude MCP), your email.
  3. Check Enable OAuth Settings and configure:
    • Callback URL: https://<your-worker-url>/sf/callback (e.g. https://salesforce-remote-mcp-cloudflare.acme.workers.dev/sf/callback)
    • Selected OAuth Scopes — add exactly these two:
      • Manage user data via APIs (api)
      • Perform requests at any time (refresh_token, offline_access)
    • Require Proof Key for Code Exchange (PKCE): leave enabled (the server uses PKCE).
    • Require Secret for Web Server Flow: leave enabled.
  4. Save. Salesforce warns changes can take up to 10 minutes to take effect.
  5. Open the app's detail page → Manage Consumer Details (email verification may be required) and copy the Consumer Key and Consumer Secret.

Optional hardening (Setup → Connected Apps → Manage → Edit Policies): set Permitted Users to Admin approved users are pre-authorized to allowlist which profiles/permission sets may use the connector at all.

Step 3 — Give the Worker its Salesforce credentials

npx wrangler secret put SALESFORCE_CLIENT_ID       # paste the Consumer Key
npx wrangler secret put SALESFORCE_CLIENT_SECRET   # paste the Consumer Secret

Secrets are stored by Cloudflare, never in code or git. That's the whole server-side setup — no redeploy needed after setting secrets.

Step 4 — Add the connector in Claude

  • Team / Enterprise: an org owner/admin adds it once for everyone — Admin settings → Connectors → Add custom connector.
  • Pro / Max: add it for yourself — Settings → Connectors → Add custom connector.

In the dialog:

  • Name: anything, e.g. Salesforce
  • Remote MCP server URL: https://<your-worker-url>/mcp — note the /mcp path
  • Advanced settings → OAuth Client ID / Client Secret: LEAVE BLANK. Those fields are a fallback for servers that can't register clients automatically; this server supports Dynamic Client Registration, so Claude configures itself. Your Connected App's key/secret belong only in Worker secrets (Step 3) — never paste them into Claude.

Step 5 — Connect (end users)

  1. In Claude, find the connector and click Connect.
  2. You're redirected to your company's Salesforce login — log in and click Allow.
  3. Done. Ask Claude to ping the Salesforce connector to confirm: it replies with the Salesforce username the session is bound to.

Each user connects individually and gets their own permissions — what a user can't see or edit in Salesforce, they can't see or edit through Claude.

The tools

Category Tools
Discovery salesforce_search_objects, salesforce_describe_object
Query salesforce_query_records, salesforce_aggregate_query, salesforce_search_all (SOSL)
Data salesforce_dml_records (insert/update/delete/upsert)
Schema salesforce_manage_object, salesforce_manage_field, salesforce_manage_field_permissions
Apex salesforce_read_apex, salesforce_write_apex, salesforce_read_apex_trigger, salesforce_write_apex_trigger, salesforce_execute_anonymous
Debug salesforce_manage_debug_logs
Health ping (no Salesforce call; shows the bound user)

Tool behavior matches the local @tsmztech/mcp-server-salesforce package. Large results are truncated at ~140k characters (Claude's connector limit is ~150k) with a notice asking to narrow the query.

Troubleshooting

Symptom Likely cause / fix
Claude: "could not reach server" when adding the connector URL must end in /mcp. The Worker must be deployed (npx wrangler deploy).
Salesforce error page during Connect: redirect_uri_mismatch Connected App callback URL doesn't exactly match https://<worker-url>/sf/callback. Remember changes take up to 10 min.
invalid_client_id / invalid_client during Connect SALESFORCE_CLIENT_ID/SECRET secrets missing or wrong (re-run Step 3), or the Connected App hasn't propagated yet.
Login page is the wrong org type (prod vs sandbox) Fix SALESFORCE_LOGIN_HOST in wrangler.jsonc and redeploy.
Tool calls fail with "reconnect" message The refresh token was revoked or expired (e.g. admin revoked OAuth usage, or org token policies). Disconnect and reconnect the connector.
INVALID_SESSION_ID errors surfacing to the user Shouldn't happen — the server auto-refreshes once and retries. If persistent, check the Connected App's refresh-token policy (Refresh token is valid until revoked is the friendliest).
Worker logs npx wrangler tail streams live logs (no tokens are ever logged).
Corporate IP allowlisting Claude's egress range is 160.79.104.0/21 — relevant if your org enforces login IP ranges on the Connected App.

Security notes

  • Per-user identity: every Salesforce call uses the connected user's own token; org permissions and FLS always apply. There is no service account.
  • No token passthrough: Claude's token and Salesforce's tokens are separate; neither is ever forwarded to the other side.
  • Storage: Salesforce tokens are stored encrypted at rest inside the OAuth grant (Cloudflare KV, encrypted by workers-oauth-provider); the interim login state is AES-GCM sealed with COOKIE_ENCRYPTION_KEY.
  • Secrets: only ever via wrangler secret put — never in code, config, or git.
  • Revocation: a Salesforce admin can cut any user (or the whole app) off at any time — Setup → Connected Apps OAuth Usage → Revoke. Users can also disconnect from Claude's connector settings.
  • See SECURITY.md for reporting vulnerabilities.

Local development

cp .dev.vars.example .dev.vars   # fill in your Connected App creds (gitignored)
npx wrangler dev                 # http://localhost:8787
npm run typecheck
npm test

Note: connecting from claude.ai requires a public HTTPS URL, so end-to-end connector testing happens against a deployed Worker; wrangler dev is for the OAuth endpoints and unit-testable logic.

License

MIT

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured