Skip to content

An experimental Cloudflare MCP server enables Salesforce Oauth and wraps a subset of Salesforce API features

Notifications You must be signed in to change notification settings

build-with-groq/groq-salesforce-mcp-server

Repository files navigation

Salesforce MCP Wrapper

A production-ready Salesforce API wrapper with Model Context Protocol (MCP) server that works seamlessly on both Deno and Cloudflare Workers. Perfect for integrating Salesforce with AI assistants, chatbots, and automation tools.

The MCP server wraps traditional REST API endpoints, providing both MCP tool interfaces for LLM integration and standard HTTP endpoints for direct API access. This dual-interface approach means you can use the same server for AI-driven interactions (via MCP) or traditional programmatic access (via REST APIs).

Key Features:

  • πŸ€– MCP Protocol Support - Works with Claude, Groq, and other MCP-compatible LLMs
  • 🌐 REST API Endpoints - Standard HTTP endpoints available alongside MCP tools
  • ⚑ Session-Based Auth - Set credentials once, use across multiple calls
  • πŸ”„ Dual Platform - Run on Deno locally or deploy to Cloudflare Workers
  • πŸ› οΈ Complete CRUD - Full Salesforce object management (Leads, Contacts, Accounts, Opportunities)
  • πŸ“ SOQL Support - Execute custom queries for advanced use cases
  • πŸ” OAuth 2.0 - Built-in OAuth flow or bring your own tokens

πŸš€ Quick Start

1. Setup Environment

# Clone the repository
git clone <your-repo-url>
cd salesforce-mcp-wrapper

# Copy environment template
cp .env.example .env

# Edit .env with your credentials (see Setup Guide below)

2. Run Locally (Deno)

# Install Deno: https://deno.land/
deno task serve

# In another terminal, run a test
deno task test

Using Tunnels for Local Development

When running locally, LLM providers like Groq need a public URL to access your MCP server. Use Cloudflare Tunnel (or alternatives like ngrok):

# Install and start Cloudflare Tunnel
brew install cloudflared
cloudflared tunnel --url http://localhost:8000

# You'll get a public URL like: https://random-name.trycloudflare.com
# Update .env with: MCP_SERVER_URL=https://random-name.trycloudflare.com/mcp

Now your tests will hit the tunneled endpoint and LLMs can access your local server!

3. Deploy to Cloudflare Workers

# Install dependencies
npm install

# Set up secrets
npm run cf:setup

# Deploy
npm run deploy

πŸ“‹ Environment Setup Guide

Required Environment Variables

Create a .env file with the following variables:

# Salesforce Connected App (for OAuth)
SALESFORCE_CLIENT_ID=your_connected_app_client_id
SALESFORCE_CLIENT_SECRET=your_connected_app_client_secret
SALESFORCE_REDIRECT_URI=http://localhost:8000/callback

# Groq API (for LLM integration)
GROQ_API_KEY=your_groq_api_key

# MCP Server URL
MCP_SERVER_URL=http://localhost:8000/mcp  # or your deployed URL

# Salesforce Test Credentials (for testing)
SALESFORCE_ACCESS_TOKEN=your_access_token
SALESFORCE_INSTANCE_URL=https://your-instance.my.salesforce.com
SALESFORCE_TOKEN_TYPE=Bearer

Getting Salesforce Credentials

Method 1: Using Workbench (Easiest for Testing)

  1. Go to workbench.developerforce.com
  2. Login with your Salesforce credentials
  3. Open Browser DevTools β†’ Application β†’ Cookies
  4. Copy the sid value (this is your access token)
  5. Your instance URL is shown in the browser's address bar

Method 2: Using Salesforce CLI

# Authenticate with your org
sf org login web

# Display org info including session ID
sf org display --target-org your-org-alias --verbose

Method 3: Using OAuth Flow (Recommended for Production)

  1. Create a Connected App in Salesforce Setup
  2. Run the server: deno task serve
  3. Visit http://localhost:8000/auth/login
  4. Complete the OAuth flow
  5. Copy the credentials from the success page

Setting Up a Salesforce Connected App

For OAuth functionality, you need to create a Connected App in Salesforce:

  1. In Salesforce Setup, search for "App Manager"
  2. Click "New Connected App"
  3. Fill in basic information:
    • Connected App Name: Your app name
    • API Name: Auto-generated
    • Contact Email: Your email
  4. Enable OAuth Settings:
    • βœ… Enable OAuth Settings
    • Callback URL: http://localhost:8000/callback (for local dev)
    • Selected OAuth Scopes: Add api, refresh_token, offline_access
  5. Save and copy the Consumer Key (Client ID) and Consumer Secret

Security Best Practices

⚠️ Important:

  • Never commit .env files (already in .gitignore)
  • Rotate tokens regularly
  • Use separate credentials for testing and production
  • Keep .env.example generic with no real credentials

πŸ€– Using with LLMs (Groq, Claude, etc.)

The MCP server exposes Salesforce operations as tools that LLMs can call. Here's how to use it:

Session-Based Authentication Pattern

The server uses a session-based pattern for efficiency:

  1. Set Credentials Once: Call sf_set_credentials and get a session_id
  2. Use Session ID: Pass the session_id to subsequent tool calls
  3. No Re-authentication: Credentials persist for the session

Example: Complete Flow

// 1. Set credentials and get session_id
const setCredsResult = await mcpClient.callTool("sf_set_credentials", {
  access_token: "your_salesforce_token",
  instance_url: "https://your-instance.salesforce.com"
});

const sessionId = setCredsResult.meta.session_id; // e.g., "mcp_1759872687750_y133q224f"

// 2. Use session_id for all subsequent calls
const leads = await mcpClient.callTool("sf_search_leads", {
  session_id: sessionId,
  limit: 10
});

Copy-Paste Templates for LLM Prompts

For creating leads:

Create a lead in Salesforce with these details:
- Access Token: {YOUR_SALESFORCE_TOKEN}
- Instance URL: {YOUR_SALESFORCE_INSTANCE_URL}
- First Name: {FIRST_NAME}
- Last Name: {LAST_NAME}
- Company: {COMPANY_NAME}
- Email: {EMAIL_ADDRESS}
- Title: {JOB_TITLE}
- Lead Source: {LEAD_SOURCE}

For searching leads:

Search for leads in Salesforce:
- Access Token: {YOUR_SALESFORCE_TOKEN}
- Instance URL: {YOUR_SALESFORCE_INSTANCE_URL}
- Company filter: {COMPANY_NAME}
- Limit: 10

For adding notes:

Add a note to Salesforce record:
- Access Token: {YOUR_SALESFORCE_TOKEN}
- Instance URL: {YOUR_SALESFORCE_INSTANCE_URL}
- Record ID: {RECORD_ID}
- Note Title: {NOTE_TITLE}
- Note Body: {NOTE_CONTENT}

Template 1: Set credentials and search leads

First, call sf_set_credentials with:
- Access Token: YOUR_TOKEN
- Instance URL: YOUR_INSTANCE_URL

Then use the session_id from the response to call sf_search_leads with limit: 10

Template 2: Create a lead

Call sf_create_lead with:
- Session ID: YOUR_SESSION_ID (from previous sf_set_credentials call)
- First Name: Sarah
- Last Name: Johnson
- Company: Innovation Labs Inc
- Email: sarah.johnson@innovationlabs.com
- Title: VP of Engineering

πŸ› οΈ Available MCP Tools

Authentication & Session Management

  • sf_set_credentials - Set Salesforce credentials and get a session_id for subsequent calls
  • sf_auth_status - Check current authentication status and get OAuth URL if not authenticated
  • sf_start_oauth - Start OAuth flow and get authorization URL
  • sf_use_oauth_state - Use credentials from completed OAuth flow
  • sf_getting_started - Get step-by-step guidance for authentication and setup
  • sf_health_check - Check server health and list available tools
  • sf_login - Get login URL for web-based OAuth flow
  • sf_get_session_info - Get current session information

Lead Management

  • sf_create_lead - Create new leads with name, company, email, phone, etc.
  • sf_search_leads - Search for leads with filters (company, email, status, etc.)
  • sf_update_lead - Update existing lead fields (status, contact info, description, etc.)
  • sf_convert_lead - Convert a lead to Account, Contact, and optionally Opportunity

Contact Management

  • sf_create_contact - Create new contacts with name, email, phone, account association
  • sf_search_contacts - Search for contacts with filters (account, email, name, etc.)

Account Management

  • sf_create_account - Create new accounts (companies) with name, industry, address, etc.
  • sf_search_accounts - Search for accounts with filters (name, type, industry, etc.)

Opportunity Management

  • sf_create_opportunity - Create sales opportunities with name, stage, amount, close date
  • sf_search_opportunities - Search for opportunities with filters (account, stage, amount, etc.)

Task/Activity Management

  • sf_create_task - Create follow-up tasks with subject, due date, priority, related records
  • sf_search_tasks - Search for tasks with filters (related records, status, subject, etc.)

Record Management (Generic)

  • sf_get_record - Get detailed information about any Salesforce record (Lead, Account, Contact, Opportunity, etc.)
  • sf_update_record - Update any Salesforce record by providing object type, record ID, and fields

Notes & Activity Management

  • sf_create_note - Add notes to any Salesforce record (Leads, Accounts, Contacts, etc.)
  • sf_search_notes - Search for notes with filters (parent record, title, etc.)
  • sf_get_note - Get details of a specific note by ID
  • sf_update_note - Update an existing note's title, body, or privacy setting
  • sf_delete_note - Delete a note from Salesforce

Advanced Queries

  • sf_run_soql_query - Execute custom SOQL queries for complex data retrieval and filtering

Note: Most tools accept an optional session_id parameter for credential persistence. Set credentials once with sf_set_credentials, then pass the returned session_id to subsequent tool calls. Alternatively, you can provide access_token and instance_url with each call.

Tool Usage Examples

Update a Lead's Status:

sf_update_lead({
  session_id: "your_session_id",
  lead_id: "00Q...",
  status: "Working - Contacted",
  description: "Had initial call, interested in premium package"
})

Add a Note to a Record:

sf_create_note({
  session_id: "your_session_id",
  parent_id: "00Q...",  // Lead, Account, Contact, or Opportunity ID
  title: "Follow-up Meeting Notes",
  body: "Discussed pricing and implementation timeline. Next steps: send proposal.",
  is_private: false
})

Get All Notes for a Lead:

sf_search_notes({
  session_id: "your_session_id",
  parent_id: "00Q...",  // Lead ID
  limit: 20
})

Update a Note:

sf_update_note({
  session_id: "your_session_id",
  note_id: "002...",
  body: "Updated meeting notes with new action items"
})

Get Full Record Details:

sf_get_record({
  session_id: "your_session_id",
  sobject_type: "Lead",
  record_id: "00Q..."
})

πŸ§ͺ Testing Your Setup

Run the Test Suite

# Quick test (default)
deno task test

# Individual tests
deno task test:credentials    # Test credential setting
deno task test:llm            # Test LLM integration with Groq
deno task test:mcp            # Test direct MCP client
deno task test:session        # Test session flow
deno task test:oauth-direct   # Test OAuth direct
deno task test:oauth-session  # Test OAuth session
deno task test:debug          # Test simple debug

# Or run directly:
deno run --allow-net --allow-read --allow-env ./tests/test-set-and-search.ts

Expected Output

Successful test output should look like:

πŸ§ͺ Testing Set Credentials + Search Leads
========================================
Session ID: mcp_1759872687750_y133q224f
Session Credentials: Present
βœ… Lead search successful:
  Total records: 5
  - John Doe, Acme Corp
  - Jane Smith, TechCorp
  ...
βœ… Credential persistence SUCCESS - got Salesforce data!

Troubleshooting

Issue Solution
Environment variables missing Make sure .env file exists and all variables are set
Invalid access token Token expired - generate a new one from Salesforce
Cannot connect to MCP server Ensure server is running and MCP_SERVER_URL is correct
HTTP 530 error MCP server not reachable - check tunnel is running and MCP_SERVER_URL is correct
Request timed out Tunnel may have expired - restart cloudflared/ngrok and update MCP_SERVER_URL
Tests fail with local server Make sure you're using a tunnel URL in MCP_SERVER_URL, not localhost

πŸ—οΈ Architecture

How It Works

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   LLM       │─────▢│  MCP Server  │─────▢│ Salesforce  β”‚
β”‚ (Groq/etc)  │◀─────│  (This App)  │◀─────│     API     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
                     β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
                     β”‚   Session   β”‚
                     β”‚   Storage   β”‚
                     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. LLM makes tool call β†’ Groq/Claude sends MCP request
  2. MCP server receives β†’ Routes to appropriate Salesforce function
  3. Session management β†’ Retrieves credentials from session storage
  4. Salesforce API call β†’ Makes authenticated REST/SOQL request
  5. Response formatting β†’ Returns structured data to LLM
  6. LLM processes β†’ Generates natural language response

Platform Support

Platform Status Use Case
Deno βœ… Ready Local development, self-hosted
Cloudflare Workers βœ… Ready Production deployment, edge computing

πŸ“ Project Structure

β”œβ”€β”€ main.ts                    # Deno entry point
β”œβ”€β”€ salesforce-mcp-server.ts  # Main MCP server implementation
β”œβ”€β”€ worker/
β”‚   └── index.ts              # Cloudflare Worker entry point
β”œβ”€β”€ utils/                    # Utility modules
β”‚   β”œβ”€β”€ salesforce-utils.ts  # Salesforce API client
β”‚   β”œβ”€β”€ auth-utils.ts        # Authentication utilities
β”‚   β”œβ”€β”€ mcp-utils.ts         # MCP protocol handlers
β”‚   β”œβ”€β”€ route-utils.ts       # HTTP/REST API endpoints
β”‚   β”œβ”€β”€ http-utils.ts        # HTTP/CORS utilities
β”‚   β”œβ”€β”€ oauth-utils.ts       # OAuth flow utilities
β”‚   β”œβ”€β”€ shared-ui.ts         # Web UI components
β”‚   └── html-templates.ts    # HTML templates
β”œβ”€β”€ tests/                    # Test files
β”‚   β”œβ”€β”€ test-credentials.ts
β”‚   β”œβ”€β”€ test-llm-mcp.ts
β”‚   β”œβ”€β”€ test-mcp-client.ts
β”‚   β”œβ”€β”€ test-session-flow.ts
β”‚   └── ...
β”œβ”€β”€ .env.example              # Environment template
β”œβ”€β”€ wrangler.jsonc           # Cloudflare config
β”œβ”€β”€ deno.json                # Deno config (includes test tasks)
└── README.md                # This file

πŸš€ Deployment Options

Option 1: Deno (Local or Self-Hosted)

# Development with hot reload
deno task serve

# Production with PM2 or systemd
deno run --allow-all main.ts

Option 2: Cloudflare Workers

# Install dependencies
npm install

# Set secrets
wrangler secret put SALESFORCE_CLIENT_ID
wrangler secret put SALESFORCE_CLIENT_SECRET
wrangler secret put GROQ_API_KEY

# Deploy
npm run deploy

Your worker will be available at: https://your-worker.your-account.workers.dev

πŸ“– Advanced Usage

Custom SOQL Queries

await mcpClient.callTool("sf_run_soql_query", {
  session_id: sessionId,
  soql: "SELECT Id, Name, Email, (SELECT Subject FROM Tasks) FROM Lead WHERE Company = 'Acme Corp' LIMIT 10"
});

Multi-Org Support

The session-based pattern makes it easy to work with multiple Salesforce orgs:

// Org A
const sessionA = await setCredentials(orgAToken, orgAInstance);
const leadsA = await searchLeads(sessionA.session_id);

// Org B  
const sessionB = await setCredentials(orgBToken, orgBInstance);
const leadsB = await searchLeads(sessionB.session_id);

Error Handling

All tools return consistent error responses:

{
  "error": {
    "code": "INVALID_SESSION",
    "message": "Session not found or expired",
    "details": "..."
  }
}

REST API Endpoints

In addition to MCP tools, the server exposes traditional REST endpoints:

  • MCP Endpoint: POST /mcp - MCP protocol endpoint for LLM tool calls
  • OAuth Flow: GET /auth/login, GET /callback - Standard OAuth 2.0 flow
  • Salesforce Operations: POST /salesforce/query, POST /leads/create, etc.
  • Web Interface: GET / - Interactive UI for testing

All MCP tools have corresponding REST API endpoints for non-MCP integrations.

🎯 Use Cases

  • AI Assistants: Enable Claude, ChatGPT, or Groq to interact with Salesforce
  • Chatbots: Build Slack/Discord/Teams bots that create leads and log activities
  • Automation: Trigger Salesforce actions from webhooks or scheduled jobs
  • Data Sync: Sync data between Salesforce and other systems
  • Analytics: Query Salesforce data for custom reporting
  • Voice Apps: Build Alexa/Google Home skills that query Salesforce

🀝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes (test on both Deno and Cloudflare)
  4. Submit a pull request

πŸ“ License

MIT - See LICENSE file for details

About

An experimental Cloudflare MCP server enables Salesforce Oauth and wraps a subset of Salesforce API features

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published