| name | salesforce-marketing-cloud-mcp |
| description | Deploy and use the Vinkius Salesforce Marketing Cloud MCP server to enable AI agents to query data extensions, trigger journeys, and manage subscribers via natural language. |
| triggers | ["integrate Salesforce Marketing Cloud with my AI agent","query Marketing Cloud data extensions from an LLM","trigger a Journey Builder workflow programmatically","manage Marketing Cloud subscribers with AI","set up MCP server for Salesforce Marketing Cloud","automate marketing campaigns with model context protocol","connect Claude to Salesforce Marketing Cloud","deploy Marketing Cloud MCP to Vinkius Edge"] |
Salesforce Marketing Cloud MCP Server
Skill by ara.so — Marketing Skills collection.
Overview
The Salesforce Marketing Cloud MCP Integration is a Model Context Protocol (MCP) server that enables AI agents (like Claude, GPT, or any LLM) to interact with Salesforce Marketing Cloud (SFMC) through natural language. It provides three core capabilities:
- Query Data Extensions: Safely retrieve subscriber and customer data from SFMC Data Extensions
- Trigger Journeys: Enroll contacts into Journey Builder workflows programmatically
- Manage Subscribers: View, update, or unsubscribe contacts while respecting communication preferences
This server abstracts away the complexity of SFMC's SOAP/REST APIs, rate limits, and XML envelopes, providing LLMs with deterministic, safe tools for marketing automation.
Installation
Deploy to Vinkius Edge (Recommended)
The fastest way to deploy this MCP server is via Vinkius Edge, which provides automatic scaling, credential management, and enterprise compliance:
npx mcpfusion deploy
After deployment, Vinkius provides an endpoint URL that you connect to your LLM client (Claude Desktop, Cursor, etc.).
Local Development Setup
For local development and testing:
git clone https://github.com/vinkius-labs/salesforce-marketing-mcp.git
cd salesforce-marketing-mcp
npm install
npm run dev
Docker Deployment
docker pull vinkius/salesforce-marketing-mcp
docker run -d \
-e SFMC_CLIENT_ID=$SFMC_CLIENT_ID \
-e SFMC_CLIENT_SECRET=$SFMC_CLIENT_SECRET \
-e SFMC_SUBDOMAIN=$SFMC_SUBDOMAIN \
-e SFMC_ACCOUNT_ID=$SFMC_ACCOUNT_ID \
-p 3000:3000 \
vinkius/salesforce-marketing-mcp
Configuration
Environment Variables
The MCP server requires the following Salesforce Marketing Cloud credentials:
SFMC_CLIENT_ID=your_client_id
SFMC_CLIENT_SECRET=your_client_secret
SFMC_SUBDOMAIN=your_subdomain
SFMC_ACCOUNT_ID=your_account_id
SFMC_API_BASE_URL=https://your_subdomain.rest.marketingcloudapis.com
Obtaining SFMC Credentials
- Log into Salesforce Marketing Cloud
- Navigate to Setup → Apps → Installed Packages
- Create a new package or select an existing one
- Add a new API Integration component
- Set the required scopes:
- Data Extensions: Read, Write
- Journeys: Execute, Read
- List and Subscribers: Read, Write
- Copy the Client ID and Client Secret
- Note your Subdomain from the Marketing Cloud URL (e.g.,
mc123456789.exacttarget.com)
- Find your Account MID in Setup → Account Settings
Claude Desktop Configuration
Add to your claude_desktop_config.json:
{
"mcpServers": {
"salesforce-marketing": {
"command": "node",
"args": ["/path/to/salesforce-marketing-mcp/build/index.js"],
"env": {
"SFMC_CLIENT_ID": "your_client_id",
"SFMC_CLIENT_SECRET": "your_client_secret",
"SFMC_SUBDOMAIN": "mc123456789",
"SFMC_ACCOUNT_ID": "your_account_id"
}
}
}
}
Available MCP Tools
1. query_data_extension
Query subscriber data from a Salesforce Marketing Cloud Data Extension.
Parameters:
dataExtensionKey (string, required): The external key of the Data Extension
fields (array, optional): Specific fields to retrieve (defaults to all)
filter (object, optional): Filter criteria { field, operator, value }
limit (number, optional): Maximum records to return (default: 100)
Example Usage:
{
"tool": "query_data_extension",
"arguments": {
"dataExtensionKey": "CustomerPreferences",
"fields": ["EmailAddress", "FirstName", "PreferredCategory"],
"filter": {
"field": "PreferredCategory",
"operator": "equals",
"value": "Electronics"
},
"limit": 50
}
}
Natural Language Prompt:
"Show me the first 50 customers from the CustomerPreferences data extension who prefer Electronics"
2. trigger_journey
Enroll a contact into a Journey Builder workflow.
Parameters:
journeyKey (string, required): The unique key of the Journey
contactKey (string, required): Unique identifier for the contact
eventData (object, optional): Additional event data to pass into the Journey
Example Usage:
{
"tool": "trigger_journey",
"arguments": {
"journeyKey": "welcome-series-2024",
"contactKey": "user@example.com",
"eventData": {
"RegistrationDate": "2024-01-15",
"Source": "WebsiteSignup",
"InterestCategory": "AI Tools"
}
}
}
Natural Language Prompt:
"Enroll user@example.com into the welcome-series-2024 journey with registration date January 15, 2024"
3. manage_subscriber
View, update, or unsubscribe a Marketing Cloud subscriber.
Parameters:
action (string, required): One of get, update, or unsubscribe
subscriberKey (string, required): Unique subscriber identifier (usually email)
attributes (object, optional): Attributes to update (for update action)
Example Usage:
{
"tool": "manage_subscriber",
"arguments": {
"action": "get",
"subscriberKey": "user@example.com"
}
}
{
"tool": "manage_subscriber",
"arguments": {
"action": "update",
"subscriberKey": "user@example.com",
"attributes": {
"FirstName": "Jane",
"Industry": "Technology",
"CompanySize": "50-200"
}
}
}
{
"tool": "manage_subscriber",
"arguments": {
"action": "unsubscribe",
"subscriberKey": "user@example.com"
}
}
Natural Language Prompts:
"Get the subscriber details for user@example.com"
"Update Jane's industry to Technology and company size to 50-200"
"Unsubscribe user@example.com from all communications"
Common Patterns
Pattern 1: Audience Segmentation for Campaign
const highValueCustomers = await queryDataExtension({
dataExtensionKey: "CustomerEngagement",
fields: ["EmailAddress", "EngagementScore", "LastPurchaseDate"],
filter: {
field: "EngagementScore",
operator: "greaterThan",
value: "80"
},
limit: 500
});
for (const customer of highValueCustomers.records) {
await triggerJourney({
journeyKey: "vip-exclusive-offer",
contactKey: customer.EmailAddress,
eventData: {
EngagementScore: customer.EngagementScore,
LastPurchase: customer.LastPurchaseDate
}
});
}
Pattern 2: Event-Driven Journey Enrollment
async function enrollAfterWebinar(attendeeEmail: string, webinarTitle: string) {
await triggerJourney({
journeyKey: "post-webinar-nurture",
contactKey: attendeeEmail,
eventData: {
WebinarTitle: webinarTitle,
AttendedDate: new Date().toISOString(),
FollowUpPriority: "High"
}
});
}
Pattern 3: Preference Management
async function updatePreferencesFromBehavior(email: string, pageViews: string[]) {
const interests = categorizeInterests(pageViews);
await manageSubscriber({
action: "update",
subscriberKey: email,
attributes: {
InterestCategories: interests.join(","),
LastActivityDate: new Date().toISOString(),
PreferenceSource: "WebsiteBehavior"
}
});
}
Pattern 4: Compliance-Safe Unsubscribe
async function processUnsubscribeRequest(email: string, reason?: string) {
await queryDataExtension({
dataExtensionKey: "UnsubscribeLog",
});
await manageSubscriber({
action: "unsubscribe",
subscriberKey: email
});
}
Troubleshooting
Authentication Failures
Error: 401 Unauthorized or Invalid client credentials
Solution: Verify your SFMC credentials:
- Double-check
SFMC_CLIENT_ID and SFMC_CLIENT_SECRET
- Ensure the API Integration has not expired
- Confirm the required scopes are enabled in your Installed Package
curl -X POST https://$SFMC_SUBDOMAIN.auth.marketingcloudapis.com/v2/token \
-H "Content-Type: application/json" \
-d "{\"grant_type\":\"client_credentials\",\"client_id\":\"$SFMC_CLIENT_ID\",\"client_secret\":\"$SFMC_CLIENT_SECRET\"}"
Data Extension Not Found
Error: Data Extension with key 'XYZ' not found
Solution:
- Verify the external key (not the name) of the Data Extension
- Check that the Data Extension exists in the correct Business Unit
- Ensure your API user has permission to access the Data Extension
Rate Limiting
Error: 429 Too Many Requests
Solution:
- Implement exponential backoff in your agent logic
- When deploying on Vinkius Edge, rate limiting is handled automatically
- For local deployments, add retry logic:
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.status === 429 && i < maxRetries - 1) {
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
continue;
}
throw error;
}
}
throw new Error('Max retries exceeded');
}
Journey Not Triggering
Error: Contact enrolled but journey does not fire
Solution:
- Verify the Journey is in Running state (not Draft or Stopped)
- Check that the
journeyKey matches the API Event Definition Key
- Ensure the contact meets the Journey entry criteria
- Review Journey Builder logs in SFMC for entry rejections
TypeScript Build Errors
Error: Module resolution or type errors during local development
Solution:
rm -rf build/ node_modules/
npm install
npm run build
Advanced Configuration
Custom Timeout Settings
For long-running queries, adjust timeout values:
export const CONFIG = {
SFMC_TIMEOUT_MS: 30000,
MAX_RECORDS_PER_QUERY: 1000
};
Multi-Business Unit Support
When working with multiple SFMC Business Units:
SFMC_ACCOUNT_ID=parent_mid
{
"tool": "query_data_extension",
"arguments": {
"dataExtensionKey": "CustomerData",
"businessUnitId": "child_bu_mid"
}
}
Resources