Skip to content

Commit 7388a1a

Browse files
authored
Merge pull request #5 from advancedcommunities/fix-deployment
Fix deployment
2 parents 71faf24 + 7141f25 commit 7388a1a

File tree

6 files changed

+91
-45
lines changed

6 files changed

+91
-45
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.5.4] - 2025-10-22
9+
10+
### Fixed
11+
12+
- **Salesforce CLI Error Handling**: Fixed `executeSfCommand` to properly parse and return JSON error responses from Salesforce CLI
13+
- When SF CLI commands fail with `--json` flag, errors are now properly captured from stdout
14+
- Error details (name, message, exitCode, context, stack) are now correctly returned to MCP clients
15+
- Fixes issue where deployment errors like "No source-backed components present in the package" were not visible
16+
- Maintains backward compatibility with existing error handling
17+
818
## [1.5.3] - 2025-09-20
919

1020
### Fixed

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"dxt_version": "0.2",
33
"name": "salesforce-mcp-server",
44
"display_name": "Salesforce MCP Server",
5-
"version": "1.5.3",
5+
"version": "1.5.4",
66
"description": "Salesforce MCP Server - Interact with Salesforce orgs through AI assistants",
77
"icon": "icon.png",
88
"long_description": "Enables AI assistants to execute Apex code, query Salesforce data, and manage org metadata using your existing Salesforce CLI authentication. Perfect for developers and administrators who want to automate Salesforce tasks through natural language interactions.\n\nSupports environment variables:\n- READ_ONLY=true - Prevents Apex code execution\n- ALLOWED_ORGS=ALL or comma-separated org list - Restricts access to specific orgs (default: ALL)",

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@advanced-communities/salesforce-mcp-server",
3-
"version": "1.5.3",
3+
"version": "1.5.4",
44
"description": "MCP server enabling AI assistants to interact with Salesforce orgs through the Salesforce CLI",
55
"main": "./src/index.ts",
66
"scripts": {

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function buildServerDescription(): string {
4949

5050
const server = new McpServer({
5151
name: "salesforce-mcp-server",
52-
version: "1.5.0",
52+
version: "1.5.4",
5353
description: buildServerDescription(),
5454
capabilities: {
5555
tools: {},

src/utils/sfCommand.ts

Lines changed: 76 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ function findSfPath(): string {
3333
}
3434

3535
const currentPlatform = platform();
36-
const pathsToCheck = COMMON_SF_PATHS[currentPlatform as keyof typeof COMMON_SF_PATHS] || COMMON_SF_PATHS.linux;
36+
const pathsToCheck =
37+
COMMON_SF_PATHS[currentPlatform as keyof typeof COMMON_SF_PATHS] ||
38+
COMMON_SF_PATHS.linux;
3739

3840
for (const path of pathsToCheck) {
3941
if (path && existsSync(path)) {
@@ -51,29 +53,50 @@ export function executeSfCommand(command: string): Promise<any> {
5153
const fullCommand = command.replace(/^sf\s+/, `"${sfPath}" `);
5254

5355
return new Promise((resolve, reject) => {
54-
exec(fullCommand, { maxBuffer: 50 * 1024 * 1024 }, (error, stdout, stderr) => {
55-
if (error) {
56-
if (error.message.includes("command not found") || error.message.includes("is not recognized")) {
57-
reject(new Error(
58-
"Salesforce CLI (sf) not found. Please ensure it is installed and accessible. " +
59-
"Visit https://developer.salesforce.com/tools/salesforcecli for installation instructions."
60-
));
61-
} else {
56+
exec(
57+
fullCommand,
58+
{ maxBuffer: 50 * 1024 * 1024 },
59+
(error, stdout, stderr) => {
60+
if (error) {
61+
if (
62+
error.message.includes("command not found") ||
63+
error.message.includes("is not recognized")
64+
) {
65+
reject(
66+
new Error(
67+
"Salesforce CLI (sf) not found. Please ensure it is installed and accessible. " +
68+
"Visit https://developer.salesforce.com/tools/salesforcecli for installation instructions."
69+
)
70+
);
71+
return;
72+
}
73+
// When --json flag is used, SF CLI returns errors as JSON in stdout
74+
// Try to parse stdout as JSON error response
75+
if (stdout && stdout.trim().length > 0) {
76+
try {
77+
const result = JSON.parse(stdout);
78+
// If it's a valid JSON response (error or success), return it
79+
resolve(result);
80+
return;
81+
} catch (parseError) {
82+
// If JSON parsing fails, fall through to reject with original error
83+
}
84+
}
6285
reject(error);
86+
return;
87+
}
88+
if (stderr && !stderr.includes("Warning")) {
89+
reject(new Error(stderr));
90+
return;
91+
}
92+
try {
93+
const result = JSON.parse(stdout);
94+
resolve(result);
95+
} catch (parseError) {
96+
reject(parseError);
6397
}
64-
return;
65-
}
66-
if (stderr && !stderr.includes("Warning")) {
67-
reject(new Error(stderr));
68-
return;
69-
}
70-
try {
71-
const result = JSON.parse(stdout);
72-
resolve(result);
73-
} catch (parseError) {
74-
reject(parseError);
7598
}
76-
});
99+
);
77100
});
78101
}
79102

@@ -82,26 +105,39 @@ export function executeSfCommandRaw(command: string): Promise<string> {
82105
const fullCommand = command.replace(/^sf\s+/, `"${sfPath}" `);
83106

84107
return new Promise((resolve, reject) => {
85-
exec(fullCommand, { maxBuffer: 50 * 1024 * 1024 }, (error, stdout, stderr) => {
86-
if (error) {
87-
if (error.message.includes("command not found") || error.message.includes("is not recognized")) {
88-
reject(new Error(
89-
"Salesforce CLI (sf) not found. Please ensure it is installed and accessible. " +
90-
"Visit https://developer.salesforce.com/tools/salesforcecli for installation instructions."
91-
));
92-
} else {
93-
// For scanner commands, non-zero exit code with stdout means violations were found
94-
// We should still return the output in this case
95-
if (stdout && (command.includes("scanner") || command.includes("code-analyzer"))) {
96-
resolve(stdout);
97-
return;
108+
exec(
109+
fullCommand,
110+
{ maxBuffer: 50 * 1024 * 1024 },
111+
(error, stdout, stderr) => {
112+
if (error) {
113+
if (
114+
error.message.includes("command not found") ||
115+
error.message.includes("is not recognized")
116+
) {
117+
reject(
118+
new Error(
119+
"Salesforce CLI (sf) not found. Please ensure it is installed and accessible. " +
120+
"Visit https://developer.salesforce.com/tools/salesforcecli for installation instructions."
121+
)
122+
);
123+
} else {
124+
// For scanner commands, non-zero exit code with stdout means violations were found
125+
// We should still return the output in this case
126+
if (
127+
stdout &&
128+
(command.includes("scanner") ||
129+
command.includes("code-analyzer"))
130+
) {
131+
resolve(stdout);
132+
return;
133+
}
134+
reject(error);
98135
}
99-
reject(error);
136+
return;
100137
}
101-
return;
138+
// Return raw stdout without JSON parsing
139+
resolve(stdout);
102140
}
103-
// Return raw stdout without JSON parsing
104-
resolve(stdout);
105-
});
141+
);
106142
});
107-
}
143+
}

0 commit comments

Comments
 (0)