The Salesforce MCP server has 25 tools with generally present schemas and descriptions, but significant inconsistencies in quality. All tools have names following verb_noun conventions (get_, list_, create_, update_, delete_). Most have descriptions, though quality varies from adequate to terse. Schemas are present for all tools with proper JSON Schema structure and type definitions. However, parameter descriptions are inconsistent, some parameters lack descriptions entirely (e.g., 'nameFilter' in list_apex_triggers has no description beyond the key name), and several tools have descriptions under 50 characters. Error handling is minimal across the board, with no recovery guidance or actionable error messages visible in the code. The generic REST API tool (call_rest_api) is particularly concerning as it allows POST/PATCH/DELETE on arbitrary endpoints with free-form bodies, creating security and validation risks. Output schemas are not documented for most tools. The server is transport-limited (STDIO only), which caps protocol readiness regardless of definition quality. Average description length is ~120 characters, below the 194-char baseline for A+ tools. Parameter descriptions average ~40 characters, significantly below the 72-char baseline.
Analyze SOQL query performance
Make a generic REST API call to Salesforce (supports GET, POST, PATCH, DELETE)
Check Apex class sharing declarations
Create a new Apex class
Delete an Apex class (use with caution)
Describe a specific SObject using REST API
Get schema information for Tooling API objects
Output schemas not documented for any tools. LLMs cannot plan downstream calls or extract return fields without knowing the response structure.
Parameter descriptions missing or minimal for multiple tools: 'nameFilter' in list_apex_triggers and list_apex_pages lacks description (visible in schema but no help text); 'apexClassId' in run_tests lacks description.
call_rest_api tool is dangerously generic. Allows POST, PATCH, DELETE to any endpoint with free-form body. No validation of endpoint paths, no rate limiting, no permission gating. This violates the security principle of least privilege and tool-gateway patterns.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 11 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 46 | - | v1 |
Execute SOQL queries against Tooling API
Get detailed information about a specific Apex class including its source code
Get detailed information about a Visualforce page
Get detailed information about a specific Apex trigger
Get a specific AsyncApexJob record by ID using Tooling API
Get code coverage information for Apex classes and triggers
Get recent debug logs
Get organization information
Get organization limits information from Salesforce REST API
Get list of all available SObjects from Salesforce REST API
Get symbol table for an Apex class
List Apex classes in the organization with optional name filtering
List Visualforce pages
List Apex triggers in the organization with optional name filtering
Execute Apex tests
Search AsyncApexJob records using Tooling API
Update the source code of an existing Apex class
Validate Apex class syntax
Error handling absent across all tools. No visible recovery guidance, no actionable error messages, no categorization of retryable vs fatal errors. Code shows console.log debug statements but no structured error reporting to the LLM.
Destructive operations (delete_apex_class, delete_apex_trigger) lack confirmation/dry-run support. No protection against agent mistakes.
Many tool descriptions under 50 characters (run_tests: 'Execute Apex tests'; get_org_info: 'Get organization information'; get_sobjects_list: 'Get list of all available SObjects'). These are too brief to guide LLM selection and lack context on WHEN to use the tool.
No pagination support visible for list tools. list_apex_classes accepts a 'limit' parameter (good) but does not document returning a 'nextCursor', 'offset', or 'total' field needed for pagination.
Tooling Client exposes raw SOQL queries with potential SQL injection risk via nameFilter parameter. No input sanitization visible; string interpolation used directly (e.g., `WHERE Name LIKE '%${nameFilter}%'`).