Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Theme
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Create API Key
Add Docs
Salesforce DX MCP Server
https://github.com/salesforcecli/mcp
Admin
The Salesforce DX MCP Server is a Model Context Protocol (MCP) implementation enabling large
...
Tokens:
22,937
Snippets:
206
Trust Score:
7.8
Update:
1 month ago
Context
Skills
Chat
Benchmark
57.7
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Salesforce DX MCP Server The Salesforce DX MCP Server is a specialized Model Context Protocol (MCP) implementation that enables seamless interaction between Large Language Models (LLMs) and Salesforce orgs. It provides a robust set of tools and capabilities that allow AI assistants to securely read, manage, and operate Salesforce resources including metadata deployment, SOQL queries, Apex test execution, org management, and code analysis. Built as a TypeScript monorepo, this server follows a provider-based architecture where functionality is organized into toolsets (like `data`, `metadata`, `orgs`, `testing`) that can be selectively enabled. The server integrates with popular MCP clients such as VS Code with Copilot, Claude Code, Cline, and Cursor. It supports telemetry, rate limiting, and both GA (Generally Available) and NON-GA tools for different release states. ## MCP Server Configuration The MCP server is started via npx and configured through JSON files. Configure the server by specifying allowed orgs and enabled toolsets. ```json { "servers": { "Salesforce DX": { "command": "npx", "args": [ "-y", "@salesforce/mcp", "--orgs", "DEFAULT_TARGET_ORG", "--toolsets", "orgs,metadata,data,users", "--tools", "run_apex_test", "--allow-non-ga-tools" ] } } } ``` ## Server Command Line Flags The server accepts various flags to customize behavior including org access, toolset selection, and debugging options. ```bash # Start with all toolsets and default org access npx @salesforce/mcp --toolsets all --orgs DEFAULT_TARGET_ORG # Allow access to specific orgs with selected toolsets npx @salesforce/mcp --orgs DEFAULT_TARGET_DEV_HUB,my-alias --toolsets data # Enable all toolsets with multiple orgs npx @salesforce/mcp --toolsets all --orgs test-org@example.com,my-dev-hub,my-alias # Use data toolset plus a specific tool npx @salesforce/mcp --orgs DEFAULT_TARGET_ORG --toolsets data --tools create_scratch_org # Enable non-GA tools for beta functionality npx @salesforce/mcp --toolsets all --orgs DEFAULT_TARGET_ORG --allow-non-ga-tools # Enable dynamic tool discovery (experimental) npx @salesforce/mcp --orgs DEFAULT_TARGET_ORG --dynamic-tools # Disable telemetry and enable debug logging npx @salesforce/mcp --toolsets all --orgs DEFAULT_TARGET_ORG --no-telemetry --debug ``` ## Claude Code Configuration Configure Claude Code to use the Salesforce DX MCP Server by creating a `.mcp.json` file in your project. ```json { "mcpServers": { "Salesforce DX": { "command": "npx", "args": [ "-y", "@salesforce/mcp", "--orgs", "DEFAULT_TARGET_ORG", "--toolsets", "orgs,metadata,data,users", "--tools", "run_apex_test", "--allow-non-ga-tools" ] } } } ``` ## Available Toolsets The server organizes tools into functional toolsets that can be selectively enabled. Each toolset contains related tools for specific Salesforce operations. ```typescript // Available toolsets (from Toolset enum) enum Toolset { CORE = 'core', // Always enabled - get_username, resume_tool_operation DATA = 'data', // run_soql_query ORGS = 'orgs', // list_all_orgs, create_scratch_org, delete_org, open_org METADATA = 'metadata', // deploy_metadata, retrieve_metadata TESTING = 'testing', // run_apex_test, run_agent_test USERS = 'users', // assign_permission_set MOBILE = 'mobile', // Mobile LWC tools (barcode, biometrics, etc.) MOBILE_CORE = 'mobile-core', AURA_EXPERTS = 'aura-experts', // Aura-to-LWC migration tools LWC_EXPERTS = 'lwc-experts', // LWC development, testing, optimization DEVOPS = 'devops', // DevOps Center tools CODE_ANALYSIS = 'code-analysis', // Salesforce Code Analyzer SCALE_PRODUCTS = 'scale-products', // Apex performance antipatterns ENRICHMENT = 'enrichment', // Metadata enrichment OTHER = 'other' } // Enable specific toolsets in config const config = { args: ["--toolsets", "data,metadata,testing"] }; // Enable all toolsets const configAll = { args: ["--toolsets", "all"] }; ``` ## run_soql_query Tool Executes SOQL queries against a Salesforce org to retrieve data. Supports both standard and Tooling API queries. ```typescript // Tool input schema const queryOrgParamsSchema = z.object({ query: z.string().describe('SOQL query to run'), usernameOrAlias: z.string().describe('Username or alias for the Salesforce org'), directory: z.string().describe('Directory of the local project'), useToolingApi: z.boolean().optional().describe('Use Tooling API instead of standard API') }); // Example MCP tool call from LLM const toolCall = { name: "run_soql_query", arguments: { query: "SELECT Id, Name, Email FROM Contact LIMIT 10", usernameOrAlias: "my-scratch-org", directory: "/path/to/project", useToolingApi: false } }; // Example response const response = { content: [{ type: "text", text: `SOQL query results: { "totalSize": 3, "done": true, "records": [ {"Id": "003xx000004TMG", "Name": "John Doe", "Email": "john@example.com"}, {"Id": "003xx000004TMH", "Name": "Jane Smith", "Email": "jane@example.com"} ] }` }] }; ``` ## deploy_metadata Tool Deploys metadata from your local DX project to a Salesforce org. Supports source tracking, manifest-based deployment, and Apex test execution during deployment. ```typescript // Tool input schema const deployMetadataParams = z.object({ ignoreConflicts: z.boolean().optional() .describe('Ignore conflicts and deploy local files'), sourceDir: z.array(z.string()).optional() .describe('Path to the local source files to deploy'), manifest: z.string().optional() .describe('Full file path for manifest (XML file) of components to deploy'), apexTestLevel: z.enum(['NoTestRun', 'RunLocalTests', 'RunAllTestsInOrg']).optional() .describe('Apex test level to use during deployment'), apexTests: z.array(z.string()).optional() .describe('Apex test classes to run'), usernameOrAlias: z.string().describe('Username or alias of the target org'), directory: z.string().describe('Directory of the local project') }); // Deploy with source tracking (auto-detect changes) const deployChanges = { name: "deploy_metadata", arguments: { usernameOrAlias: "my-scratch-org", directory: "/path/to/project" } }; // Deploy specific files with Apex tests const deployWithTests = { name: "deploy_metadata", arguments: { sourceDir: ["/path/to/project/force-app/main/default/classes/MyClass.cls"], apexTests: ["MyClassTest"], usernameOrAlias: "my-scratch-org", directory: "/path/to/project" } }; // Deploy from manifest const deployManifest = { name: "deploy_metadata", arguments: { manifest: "/path/to/project/manifest/package.xml", usernameOrAlias: "my-scratch-org", directory: "/path/to/project" } }; ``` ## retrieve_metadata Tool Retrieves metadata from a Salesforce org to your local DX project. Supports source tracking for incremental retrieval. ```typescript // Tool input schema const retrieveMetadataParams = z.object({ ignoreConflicts: z.boolean().optional().default(false) .describe('Ignore conflicts and overwrite local changes'), sourceDir: z.array(z.string()).optional() .describe('Path to the local source files to retrieve'), manifest: z.string().optional() .describe('Full file path for manifest (XML file) of components'), usernameOrAlias: z.string().describe('Username or alias of the source org'), directory: z.string().describe('Directory of the local project') }); // Retrieve tracked changes const retrieveChanges = { name: "retrieve_metadata", arguments: { usernameOrAlias: "my-scratch-org", directory: "/path/to/project" } }; // Retrieve specific files ignoring conflicts const retrieveSpecific = { name: "retrieve_metadata", arguments: { sourceDir: ["/path/to/project/force-app/main/default/classes/MyClass.cls"], ignoreConflicts: true, usernameOrAlias: "my-scratch-org", directory: "/path/to/project" } }; ``` ## run_apex_test Tool Executes Apex tests in a Salesforce org with support for test levels, code coverage, and async execution. ```typescript // Tool input schema const runApexTestsParam = z.object({ testLevel: z.enum(['RunLocalTests', 'RunAllTestsInOrg', 'RunSpecifiedTests']) .describe('Apex test level'), classNames: z.array(z.string()).optional() .describe('Apex test classes to run'), methodNames: z.array(z.string()).optional() .describe('Specific test method names'), async: z.boolean().default(false) .describe('Return immediately with test run ID'), suiteName: z.string().optional() .describe('A suite of apex test classes to run'), testRunId: z.string().optional() .describe('ID of an in-progress or completed test run'), verbose: z.boolean().default(false) .describe('Include passing test information'), codeCoverage: z.boolean().default(false) .describe('Calculate code coverage'), usernameOrAlias: z.string().describe('Username or alias of the org'), directory: z.string().describe('Directory of the local project') }); // Run specific test classes const runSpecificTests = { name: "run_apex_test", arguments: { testLevel: "RunSpecifiedTests", classNames: ["AccountTriggerTest", "ContactServiceTest"], codeCoverage: true, usernameOrAlias: "my-scratch-org", directory: "/path/to/project" } }; // Run all local tests const runAllLocal = { name: "run_apex_test", arguments: { testLevel: "RunLocalTests", verbose: true, usernameOrAlias: "my-scratch-org", directory: "/path/to/project" } }; // Run tests asynchronously const runAsync = { name: "run_apex_test", arguments: { testLevel: "RunSpecifiedTests", classNames: ["LongRunningTest"], async: true, usernameOrAlias: "my-scratch-org", directory: "/path/to/project" } }; // Returns: { "testRunId": "707xx0000004C8F" } ``` ## list_all_orgs Tool Lists all configured and allowed Salesforce orgs with their connection details. ```typescript // Tool input schema const listAllOrgsParamsSchema = z.object({ directory: z.string().describe('Directory to change to before running') }); // List all orgs const listOrgs = { name: "list_all_orgs", arguments: { directory: "/path/to/project" } }; // Example response const response = { content: [{ type: "text", text: `List of configured Salesforce orgs: [ { "aliases": ["my-scratch-org"], "username": "test-scratch@example.com", "instanceUrl": "https://flow-platform-1234-dev-ed.scratch.my.salesforce.com", "isScratchOrg": true, "isDevHub": false, "orgId": "00Dxx0000001234" }, { "aliases": ["my-devhub"], "username": "admin@devhub.example.com", "instanceUrl": "https://mycompany.my.salesforce.com", "isDevHub": true, "orgId": "00Dxx0000005678" } ]` }] }; ``` ## create_scratch_org Tool (NON-GA) Creates a new scratch org from a Dev Hub with customizable settings including duration, edition, and definition file. ```typescript // Tool input schema const createScratchOrgParams = z.object({ directory: z.string().describe('Directory of the local project'), devHub: z.string().describe('Username or alias of the Dev Hub'), duration: z.number().default(7).describe('Days before org expires'), edition: z.enum([ 'developer', 'enterprise', 'group', 'professional', 'partner-developer', 'partner-enterprise', 'partner-group', 'partner-professional' ]).optional(), definitionFile: z.string().default('config/project-scratch-def.json') .describe('Path to scratch definition JSON'), alias: z.string().optional().describe('Alias for the scratch org'), async: z.boolean().default(false).describe('Return immediately without waiting'), setDefault: z.boolean().optional().describe('Set as default-target-org'), snapshot: z.string().optional().describe('Snapshot name to use'), sourceOrg: z.string().length(15).optional().describe('15-char ID of org shape'), username: z.string().optional().describe('Admin user username'), description: z.string().optional().describe('Scratch org description'), orgName: z.string().optional().describe('Name of the scratch org'), adminEmail: z.string().optional().describe('Admin user email address') }); // Create scratch org with defaults const createDefault = { name: "create_scratch_org", arguments: { devHub: "my-devhub", directory: "/path/to/project" } }; // Create customized scratch org const createCustom = { name: "create_scratch_org", arguments: { devHub: "my-devhub", directory: "/path/to/project", alias: "feature-branch-org", duration: 14, edition: "developer", setDefault: true, description: "Feature branch testing" } }; // Create async for long-running operation const createAsync = { name: "create_scratch_org", arguments: { devHub: "my-devhub", directory: "/path/to/project", async: true } }; // Returns job ID for use with resume_tool_operation ``` ## run_code_analyzer Tool Performs static code analysis using Salesforce Code Analyzer to check for best practices, security vulnerabilities, and performance issues. ```typescript // Tool input schema const inputSchema = z.object({ target: z.array(z.string()) .describe('Array of 1-10 absolute file paths to scan'), selector: z.string().optional() .describe('Optional rule selector (e.g., "Security:pmd", "Critical")') }); // Analyze specific files const analyzeFiles = { name: "run_code_analyzer", arguments: { target: [ "/path/to/project/force-app/main/default/classes/AccountService.cls", "/path/to/project/force-app/main/default/classes/ContactTrigger.cls" ] } }; // Analyze with security rules only const analyzeSecurityRules = { name: "run_code_analyzer", arguments: { target: ["/path/to/project/force-app/main/default/classes/PaymentService.cls"], selector: "Security:pmd" } }; // Example response const response = { content: [{ type: "text", text: JSON.stringify({ status: "success", resultsFile: "/tmp/code-analyzer-results-12345.json", summary: { total: 5, sev1: 1, sev2: 2, sev3: 2, sev4: 0, sev5: 0 } }) }], structuredContent: { status: "success", resultsFile: "/tmp/code-analyzer-results-12345.json", summary: { total: 5, sev1: 1, sev2: 2, sev3: 2 } } }; ``` ## Creating Custom MCP Providers Extend the MCP server by creating custom providers that supply tools, resources, and prompts. Providers implement the `McpProvider` abstract class. ```typescript import { McpProvider, McpTool, Services } from "@salesforce/mcp-provider-api"; import { MyCustomTool } from "./tools/my_custom_tool.js"; export class MyCustomProvider extends McpProvider { // Return a unique name for your provider public getName(): string { return "MyCustomProvider"; } // Return array of McpTool instances to register public provideTools(services: Services): Promise<McpTool[]> { return Promise.resolve([ new MyCustomTool(services.getTelemetryService()), // Add more tools here ]); } // Optional: provide resources (not yet consumed by main server) public provideResources(services: Services): Promise<(McpResource | McpResourceTemplate)[]> { return Promise.resolve([]); } // Optional: provide prompts (not yet consumed by main server) public providePrompts(services: Services): Promise<McpPrompt[]> { return Promise.resolve([]); } } ``` ## Creating Custom MCP Tools Implement the `McpTool` abstract class to create tools that can be registered with the server. Tools define input/output schemas using Zod. ```typescript import { z } from "zod"; import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { McpTool, McpToolConfig, ReleaseState, TelemetryService, Toolset, } from "@salesforce/mcp-provider-api"; // Define input schema with Zod const myToolInputSchema = z.object({ recordId: z.string().describe("The Salesforce record ID to process"), operation: z.enum(["read", "update", "delete"]).describe("Operation type"), data: z.record(z.string(), z.unknown()).optional().describe("Data for update operations") }); type InputArgs = z.infer<typeof myToolInputSchema>; type InputArgsShape = typeof myToolInputSchema.shape; type OutputArgsShape = z.ZodRawShape; export class MyCustomTool extends McpTool<InputArgsShape, OutputArgsShape> { private readonly telemetryService: TelemetryService; // Inject dependencies for testability public constructor(telemetryService: TelemetryService) { super(); this.telemetryService = telemetryService; } // Set release state: GA or NON_GA public getReleaseState(): ReleaseState { return ReleaseState.GA; } // Assign to one or more toolsets public getToolsets(): Toolset[] { return [Toolset.DATA, Toolset.OTHER]; } // Tool name (snake_case recommended) public getName(): string { return "my_custom_tool"; } // Tool configuration including schema and annotations public getConfig(): McpToolConfig<InputArgsShape, OutputArgsShape> { return { title: "My Custom Tool", description: `Performs custom operations on Salesforce records. AGENT INSTRUCTIONS: Use this tool when the user wants to perform record operations. EXAMPLE USAGE: Process record 001xx000003DGb5 Update account with new data`, inputSchema: myToolInputSchema.shape, outputSchema: undefined, annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false } }; } // Main execution method - can be sync or async public async exec(input: InputArgs): Promise<CallToolResult> { // Send telemetry event this.telemetryService.sendEvent("myCustomToolExecuted", { operation: input.operation }); try { // Implement your tool logic here const result = await this.processRecord(input); return { content: [{ type: "text", text: `Successfully processed record: ${JSON.stringify(result)}` }] }; } catch (error) { return { isError: true, content: [{ type: "text", text: `Failed to process record: ${error instanceof Error ? error.message : 'Unknown error'}` }] }; } } private async processRecord(input: InputArgs): Promise<object> { // Implementation details return { recordId: input.recordId, status: "processed" }; } } ``` ## Services Interface Tools receive a `Services` object that provides access to telemetry, org connections, and configuration. Use these services to interact with Salesforce orgs. ```typescript import { Services, OrgService, TelemetryService, ConfigService } from "@salesforce/mcp-provider-api"; // Services interface provides access to core services interface Services { getTelemetryService(): TelemetryService; getOrgService(): OrgService; getConfigService(): ConfigService; } // OrgService for Salesforce org operations interface OrgService { getAllowedOrgUsernames(): Promise<Set<string>>; getAllowedOrgs(): Promise<SanitizedOrgAuthorization[]>; getConnection(username: string): Promise<Connection>; getDefaultTargetOrg(): Promise<OrgConfigInfo | undefined>; getDefaultTargetDevHub(): Promise<OrgConfigInfo | undefined>; findOrgByUsernameOrAlias( allOrgs: SanitizedOrgAuthorization[], usernameOrAlias: string ): SanitizedOrgAuthorization | undefined; } // Example: Using services in a tool public async exec(input: InputArgs): Promise<CallToolResult> { const orgService = this.services.getOrgService(); // Get connection to specified org const connection = await orgService.getConnection(input.usernameOrAlias); // Execute SOQL query const result = await connection.query("SELECT Id, Name FROM Account LIMIT 5"); // Send telemetry this.services.getTelemetryService().sendEvent("queryExecuted", { recordCount: result.totalSize }); return { content: [{ type: "text", text: JSON.stringify(result) }] }; } ``` ## SfMcpServer Class The main server class extends the base MCP server with telemetry tracking, rate limiting, and tool registration capabilities. ```typescript import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; // Server configuration options type SfMcpServerOptions = { telemetry?: Telemetry; rateLimit?: { maxRequests?: number; // Max requests in window windowMs?: number; // Time window in ms }; }; // Create and configure server const server = new SfMcpServer( { name: 'sf-mcp-server', version: '0.27.1', capabilities: { resources: {}, tools: {}, }, }, { telemetry: telemetryInstance, rateLimit: { maxRequests: 100, windowMs: 60000 } } ); // Register a tool programmatically server.registerTool( 'my_tool', { title: 'My Tool', description: 'Does something useful', inputSchema: myInputSchema.shape, annotations: { readOnlyHint: true } }, async (args, extra) => { // Tool implementation return { content: [{ type: 'text', text: 'Result' }] }; } ); // Connect to stdio transport const transport = new StdioServerTransport(); await server.connect(transport); console.error('Server running on stdio'); ``` ## Summary The Salesforce DX MCP Server provides comprehensive integration between AI assistants and Salesforce development workflows. The primary use cases include metadata deployment and retrieval with source tracking, executing SOQL queries and Apex tests, managing scratch orgs and org configurations, performing static code analysis, and supporting LWC/Aura component development. The server's toolset architecture allows developers to enable only the functionality they need, reducing LLM context size and improving performance. For integration, the server follows standard MCP patterns and can be configured in any MCP-compatible client through JSON configuration files. Custom extensions can be built by implementing the `McpProvider` and `McpTool` abstract classes, making it straightforward to add organization-specific tools. The provider registry pattern ensures clean separation between different functional areas (DX Core, Code Analysis, LWC Experts, etc.) while the services interface provides consistent access to Salesforce connections, telemetry, and configuration across all tools.