@salesforce/mcp 0.17.1 → 0.17.2-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +1 -1
- package/lib/index.js +7 -5
- package/lib/main-server-provider.d.ts +7 -0
- package/lib/main-server-provider.js +31 -0
- package/lib/registry.d.ts +3 -29
- package/lib/registry.js +9 -113
- package/lib/scripts/build-index.js +1 -1
- package/lib/services.d.ts +12 -0
- package/lib/services.js +34 -0
- package/lib/sf-mcp-server.d.ts +12 -7
- package/lib/sf-mcp-server.js +6 -21
- package/lib/telemetry.d.ts +2 -1
- package/lib/tools/sf-enable-tools.d.ts +23 -0
- package/lib/tools/sf-enable-tools.js +77 -0
- package/lib/tools/sf-list-tools.d.ts +8 -0
- package/lib/{modules/platform-cli → tools}/sf-list-tools.js +33 -9
- package/lib/tools/sf-suggest-cli-command.d.ts +25 -0
- package/lib/{modules/platform-cli → tools}/sf-suggest-cli-command.js +46 -18
- package/lib/utils/assets.d.ts +21 -0
- package/lib/{assets.js → utils/assets.js} +23 -33
- package/lib/{shared → utils}/auth.d.ts +3 -8
- package/lib/{shared → utils}/auth.js +2 -42
- package/lib/utils/registry-utils.d.ts +4 -0
- package/lib/utils/registry-utils.js +87 -0
- package/lib/{modules/platform-cli/utils → utils}/tools.js +1 -1
- package/lib/utils/types.d.ts +5 -0
- package/package.json +8 -4
- package/README.md +0 -263
- package/lib/assets.d.ts +0 -44
- package/lib/modules/platform-cli/index.d.ts +0 -16
- package/lib/modules/platform-cli/index.js +0 -32
- package/lib/modules/platform-cli/sf-assign-permission-set.d.ts +0 -20
- package/lib/modules/platform-cli/sf-assign-permission-set.js +0 -89
- package/lib/modules/platform-cli/sf-create-org-snapshot.d.ts +0 -23
- package/lib/modules/platform-cli/sf-create-org-snapshot.js +0 -88
- package/lib/modules/platform-cli/sf-create-scratch-org.d.ts +0 -50
- package/lib/modules/platform-cli/sf-create-scratch-org.js +0 -132
- package/lib/modules/platform-cli/sf-delete-org.d.ts +0 -14
- package/lib/modules/platform-cli/sf-delete-org.js +0 -65
- package/lib/modules/platform-cli/sf-deploy-metadata.d.ts +0 -27
- package/lib/modules/platform-cli/sf-deploy-metadata.js +0 -164
- package/lib/modules/platform-cli/sf-enable-tools.d.ts +0 -2
- package/lib/modules/platform-cli/sf-enable-tools.js +0 -42
- package/lib/modules/platform-cli/sf-get-username.d.ts +0 -17
- package/lib/modules/platform-cli/sf-get-username.js +0 -109
- package/lib/modules/platform-cli/sf-list-all-orgs.d.ts +0 -11
- package/lib/modules/platform-cli/sf-list-all-orgs.js +0 -59
- package/lib/modules/platform-cli/sf-list-tools.d.ts +0 -2
- package/lib/modules/platform-cli/sf-org-open.d.ts +0 -17
- package/lib/modules/platform-cli/sf-org-open.js +0 -57
- package/lib/modules/platform-cli/sf-query-org.d.ts +0 -20
- package/lib/modules/platform-cli/sf-query-org.js +0 -66
- package/lib/modules/platform-cli/sf-resume.d.ts +0 -20
- package/lib/modules/platform-cli/sf-resume.js +0 -149
- package/lib/modules/platform-cli/sf-retrieve-metadata.d.ts +0 -2
- package/lib/modules/platform-cli/sf-retrieve-metadata.js +0 -128
- package/lib/modules/platform-cli/sf-suggest-cli-command.d.ts +0 -5
- package/lib/modules/platform-cli/sf-test-agents.d.ts +0 -21
- package/lib/modules/platform-cli/sf-test-agents.js +0 -84
- package/lib/modules/platform-cli/sf-test-apex.d.ts +0 -40
- package/lib/modules/platform-cli/sf-test-apex.js +0 -132
- package/lib/shared/params.d.ts +0 -5
- package/lib/shared/params.js +0 -46
- package/lib/shared/types.d.ts +0 -33
- package/lib/shared/utils.d.ts +0 -11
- package/lib/shared/utils.js +0 -71
- package/lib/tsconfig.tsbuildinfo +0 -1
- /package/lib/{shared → utils}/cache.d.ts +0 -0
- /package/lib/{shared → utils}/cache.js +0 -0
- /package/lib/{shared → utils}/rate-limiter.d.ts +0 -0
- /package/lib/{shared → utils}/rate-limiter.js +0 -0
- /package/lib/{modules/platform-cli/utils → utils}/tools.d.ts +0 -0
- /package/lib/{shared → utils}/types.js +0 -0
package/lib/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export default class McpServerCommand extends Command {
|
|
|
4
4
|
static description: string;
|
|
5
5
|
static flags: {
|
|
6
6
|
orgs: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
-
toolsets: import("@oclif/core/interfaces").OptionFlag<("
|
|
7
|
+
toolsets: import("@oclif/core/interfaces").OptionFlag<(import("@salesforce/mcp-provider-api/src/toolset.js").Toolset | "all")[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
8
|
version: import("@oclif/core/interfaces").BooleanFlag<void>;
|
|
9
9
|
'no-telemetry': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
10
|
debug: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
package/lib/index.js
CHANGED
|
@@ -14,13 +14,15 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
/* eslint-disable no-console */
|
|
17
|
+
import { TOOLSETS } from '@salesforce/mcp-provider-api';
|
|
17
18
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
18
19
|
import { Command, Flags, ux } from '@oclif/core';
|
|
19
|
-
import Cache from './
|
|
20
|
+
import Cache from './utils/cache.js';
|
|
20
21
|
import { Telemetry } from './telemetry.js';
|
|
21
22
|
import { SfMcpServer } from './sf-mcp-server.js';
|
|
22
|
-
import { maybeBuildIndex } from './assets.js';
|
|
23
|
-
import {
|
|
23
|
+
import { maybeBuildIndex } from './utils/assets.js';
|
|
24
|
+
import { registerToolsets } from './utils/registry-utils.js';
|
|
25
|
+
import { Services } from './services.js';
|
|
24
26
|
/**
|
|
25
27
|
* Sanitizes an array of org usernames by replacing specific orgs with a placeholder.
|
|
26
28
|
* Special values (DEFAULT_TARGET_ORG, DEFAULT_TARGET_DEV_HUB, ALLOW_ALL_ORGS) are preserved.
|
|
@@ -130,10 +132,10 @@ You can also use special values to control access to orgs:
|
|
|
130
132
|
},
|
|
131
133
|
}, {
|
|
132
134
|
telemetry: this.telemetry,
|
|
133
|
-
dynamicTools: flags['dynamic-tools'] ?? false,
|
|
134
135
|
});
|
|
135
136
|
await maybeBuildIndex(this.config.dataDir);
|
|
136
|
-
|
|
137
|
+
const services = new Services({ telemetry: this.telemetry, dataDir: this.config.dataDir });
|
|
138
|
+
await registerToolsets(flags.toolsets ?? ['all'], flags['dynamic-tools'] ?? false, server, services);
|
|
137
139
|
const transport = new StdioServerTransport();
|
|
138
140
|
await server.connect(transport);
|
|
139
141
|
console.error(`✅ Salesforce MCP Server v${this.config.version} running on stdio`);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { McpProvider, McpTool, Services } from '@salesforce/mcp-provider-api';
|
|
2
|
+
import { SfMcpServer } from './sf-mcp-server.js';
|
|
3
|
+
export declare function createDynamicServerTools(server: SfMcpServer): McpTool[];
|
|
4
|
+
export declare class MainServerProvider extends McpProvider {
|
|
5
|
+
getName(): string;
|
|
6
|
+
provideTools(services: Services): Promise<McpTool[]>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025, Salesforce, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { McpProvider } from '@salesforce/mcp-provider-api';
|
|
17
|
+
import { EnableToolsMcpTool } from './tools/sf-enable-tools.js';
|
|
18
|
+
import { ListToolsMcpTool } from './tools/sf-list-tools.js';
|
|
19
|
+
import { SuggestCliCommandMcpTool } from './tools/sf-suggest-cli-command.js';
|
|
20
|
+
export function createDynamicServerTools(server) {
|
|
21
|
+
return [new EnableToolsMcpTool(server), new ListToolsMcpTool()];
|
|
22
|
+
}
|
|
23
|
+
export class MainServerProvider extends McpProvider {
|
|
24
|
+
getName() {
|
|
25
|
+
return 'MainServerProvider';
|
|
26
|
+
}
|
|
27
|
+
async provideTools(services) {
|
|
28
|
+
return Promise.resolve([new SuggestCliCommandMcpTool(services)]);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=main-server-provider.js.map
|
package/lib/registry.d.ts
CHANGED
|
@@ -1,29 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export declare const CORE_TOOLS: string[];
|
|
5
|
-
/**
|
|
6
|
-
* Determines which toolsets should be enabled based on the provided toolsets array and dynamic tools flag.
|
|
7
|
-
*
|
|
8
|
-
* @param {Array<Toolset | 'all'>} toolsets - Array of toolsets to enable. Can include 'all' to enable all non-experimental toolsets.
|
|
9
|
-
* @param {boolean} dynamicTools - Flag indicating whether dynamic tools should be enabled. When true, only core and dynamic toolsets are enabled.
|
|
10
|
-
* @returns {Record<Toolset | 'dynamic' | 'core', boolean>} Object mapping each toolset to a boolean indicating whether it should be enabled.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* // Enable all toolsets except experimental
|
|
14
|
-
* determineToolsetsToEnable(['all'], false)
|
|
15
|
-
* // Returns: { core: true, data: true, dynamic: false, experimental: false, metadata: true, orgs: true, testing: true, users: true }
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* // Enable only dynamic tools
|
|
19
|
-
* determineToolsetsToEnable([], true)
|
|
20
|
-
* // Returns: { core: true, data: false, dynamic: true, experimental: false, metadata: false, orgs: false, testing: false, users: false }
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* // Enable specific toolsets
|
|
24
|
-
* determineToolsetsToEnable(['data', 'users'], false)
|
|
25
|
-
* // Returns: { core: true, data: true, dynamic: false, experimental: false, metadata: false, orgs: false, testing: false, users: true }
|
|
26
|
-
*/
|
|
27
|
-
export declare function determineToolsetsToEnable(toolsets: Array<Toolset | 'all'>, dynamicTools: boolean): Record<Toolset | 'dynamic' | 'core', boolean>;
|
|
28
|
-
export declare function registerToolsets(toolsets: Array<Toolset | 'all'>, dynamicTools: boolean, server: SfMcpServer): void;
|
|
29
|
-
export {};
|
|
1
|
+
import { McpProvider } from '@salesforce/mcp-provider-api';
|
|
2
|
+
/** -------- ADD McpProvider INSTANCES HERE ------------------------------------------------------------------------- */
|
|
3
|
+
export declare const MCP_PROVIDER_REGISTRY: McpProvider[];
|
package/lib/registry.js
CHANGED
|
@@ -13,118 +13,14 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
17
|
-
import
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
'sf-get-username',
|
|
26
|
-
'sf-resume',
|
|
27
|
-
'sf-enable-tools',
|
|
28
|
-
'sf-list-tools',
|
|
29
|
-
'sf-suggest-cli-command',
|
|
16
|
+
import { DxCoreMcpProvider } from '@salesforce/mcp-provider-dx-core';
|
|
17
|
+
import { CodeAnalyzerMcpProvider } from '@salesforce/mcp-provider-code-analyzer';
|
|
18
|
+
import { MainServerProvider } from './main-server-provider.js';
|
|
19
|
+
/** -------- ADD McpProvider INSTANCES HERE ------------------------------------------------------------------------- */
|
|
20
|
+
export const MCP_PROVIDER_REGISTRY = [
|
|
21
|
+
new MainServerProvider(),
|
|
22
|
+
new DxCoreMcpProvider(),
|
|
23
|
+
new CodeAnalyzerMcpProvider(),
|
|
24
|
+
// Add new instances here
|
|
30
25
|
];
|
|
31
|
-
/**
|
|
32
|
-
* The tool registry maps toolsets to functions that register tools with the server.
|
|
33
|
-
*
|
|
34
|
-
* When adding a new tool, you must add it to the appropriate toolset in this registry.
|
|
35
|
-
*/
|
|
36
|
-
const TOOL_REGISTRY = {
|
|
37
|
-
core: [platformCli.getUsername, platformCli.resume, platformCli.suggestCliCommand],
|
|
38
|
-
dynamic: [platformCli.enableTools, platformCli.listTools],
|
|
39
|
-
orgs: [platformCli.listAllOrgs],
|
|
40
|
-
data: [platformCli.queryOrg],
|
|
41
|
-
users: [platformCli.assignPermissionSet],
|
|
42
|
-
testing: [platformCli.testAgent, platformCli.testApex],
|
|
43
|
-
metadata: [platformCli.deployMetadata, platformCli.retrieveMetadata],
|
|
44
|
-
experimental: [
|
|
45
|
-
platformCli.orgOpen,
|
|
46
|
-
platformCli.createScratchOrg,
|
|
47
|
-
platformCli.deleteOrg,
|
|
48
|
-
platformCli.createOrgSnapshot,
|
|
49
|
-
],
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Determines which toolsets should be enabled based on the provided toolsets array and dynamic tools flag.
|
|
53
|
-
*
|
|
54
|
-
* @param {Array<Toolset | 'all'>} toolsets - Array of toolsets to enable. Can include 'all' to enable all non-experimental toolsets.
|
|
55
|
-
* @param {boolean} dynamicTools - Flag indicating whether dynamic tools should be enabled. When true, only core and dynamic toolsets are enabled.
|
|
56
|
-
* @returns {Record<Toolset | 'dynamic' | 'core', boolean>} Object mapping each toolset to a boolean indicating whether it should be enabled.
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* // Enable all toolsets except experimental
|
|
60
|
-
* determineToolsetsToEnable(['all'], false)
|
|
61
|
-
* // Returns: { core: true, data: true, dynamic: false, experimental: false, metadata: true, orgs: true, testing: true, users: true }
|
|
62
|
-
*
|
|
63
|
-
* @example
|
|
64
|
-
* // Enable only dynamic tools
|
|
65
|
-
* determineToolsetsToEnable([], true)
|
|
66
|
-
* // Returns: { core: true, data: false, dynamic: true, experimental: false, metadata: false, orgs: false, testing: false, users: false }
|
|
67
|
-
*
|
|
68
|
-
* @example
|
|
69
|
-
* // Enable specific toolsets
|
|
70
|
-
* determineToolsetsToEnable(['data', 'users'], false)
|
|
71
|
-
* // Returns: { core: true, data: true, dynamic: false, experimental: false, metadata: false, orgs: false, testing: false, users: true }
|
|
72
|
-
*/
|
|
73
|
-
export function determineToolsetsToEnable(toolsets, dynamicTools) {
|
|
74
|
-
if (dynamicTools) {
|
|
75
|
-
return {
|
|
76
|
-
core: true,
|
|
77
|
-
data: true,
|
|
78
|
-
dynamic: true,
|
|
79
|
-
experimental: false,
|
|
80
|
-
metadata: true,
|
|
81
|
-
orgs: true,
|
|
82
|
-
testing: true,
|
|
83
|
-
users: true,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
if (toolsets.includes('all')) {
|
|
87
|
-
return {
|
|
88
|
-
core: true,
|
|
89
|
-
data: true,
|
|
90
|
-
dynamic: false,
|
|
91
|
-
experimental: false,
|
|
92
|
-
metadata: true,
|
|
93
|
-
orgs: true,
|
|
94
|
-
testing: true,
|
|
95
|
-
users: true,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
core: true,
|
|
100
|
-
data: toolsets.includes('data'),
|
|
101
|
-
dynamic: false,
|
|
102
|
-
experimental: toolsets.includes('experimental'),
|
|
103
|
-
metadata: toolsets.includes('metadata'),
|
|
104
|
-
orgs: toolsets.includes('orgs'),
|
|
105
|
-
testing: toolsets.includes('testing'),
|
|
106
|
-
users: toolsets.includes('users'),
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
function registerToolset(toolset, server) {
|
|
110
|
-
if (TOOL_REGISTRY[toolset]) {
|
|
111
|
-
for (const tool of TOOL_REGISTRY[toolset]) {
|
|
112
|
-
tool(server);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
throw new Error(`Failed to register toolset ${toolset}.`);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
export function registerToolsets(toolsets, dynamicTools, server) {
|
|
120
|
-
const toolsetsToEnable = determineToolsetsToEnable(toolsets, dynamicTools);
|
|
121
|
-
for (const toolset of ['core', 'dynamic', ...TOOLSETS]) {
|
|
122
|
-
if (!toolsetsToEnable[toolset]) {
|
|
123
|
-
ux.stderr(`Skipping registration of ${toolset} tools`);
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
ux.stderr(`Registering ${toolset} tools`);
|
|
127
|
-
registerToolset(toolset, server);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
26
|
//# sourceMappingURL=registry.js.map
|
|
@@ -36,7 +36,7 @@ const main = async () => {
|
|
|
36
36
|
}
|
|
37
37
|
// Define the output file paths
|
|
38
38
|
const commandsPath = path.join(outputDir, 'sf-commands.json');
|
|
39
|
-
const faissIndexPath = path.join(outputDir, '
|
|
39
|
+
const faissIndexPath = path.join(outputDir, 'commands-index.bin');
|
|
40
40
|
ux.stderr('Starting offline data preparation...');
|
|
41
41
|
// 1. Ensure output directory exists
|
|
42
42
|
if (!fs.existsSync(outputDir)) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Services as IServices, TelemetryService, OrgService, ConfigService } from '@salesforce/mcp-provider-api';
|
|
2
|
+
export declare class Services implements IServices {
|
|
3
|
+
private readonly telemetry;
|
|
4
|
+
private readonly dataDir;
|
|
5
|
+
constructor(opts: {
|
|
6
|
+
telemetry: TelemetryService | undefined;
|
|
7
|
+
dataDir: string;
|
|
8
|
+
});
|
|
9
|
+
getTelemetryService(): TelemetryService;
|
|
10
|
+
getConfigService(): ConfigService;
|
|
11
|
+
getOrgService(): OrgService;
|
|
12
|
+
}
|
package/lib/services.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import Cache from './utils/cache.js';
|
|
2
|
+
import { getConnection, getDefaultTargetOrg, getDefaultTargetDevHub, getAllAllowedOrgs, findOrgByUsernameOrAlias, } from './utils/auth.js';
|
|
3
|
+
export class Services {
|
|
4
|
+
telemetry;
|
|
5
|
+
dataDir;
|
|
6
|
+
constructor(opts) {
|
|
7
|
+
this.telemetry = opts.telemetry ? opts.telemetry : new NoopTelemetryService();
|
|
8
|
+
this.dataDir = opts.dataDir;
|
|
9
|
+
}
|
|
10
|
+
getTelemetryService() {
|
|
11
|
+
return this.telemetry;
|
|
12
|
+
}
|
|
13
|
+
getConfigService() {
|
|
14
|
+
return {
|
|
15
|
+
getDataDir: () => this.dataDir,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
getOrgService() {
|
|
19
|
+
return {
|
|
20
|
+
getAllowedOrgUsernames: async () => Cache.safeGet('allowedOrgs'),
|
|
21
|
+
getAllowedOrgs: () => getAllAllowedOrgs(),
|
|
22
|
+
getConnection: (username) => getConnection(username),
|
|
23
|
+
getDefaultTargetOrg: () => getDefaultTargetOrg(),
|
|
24
|
+
getDefaultTargetDevHub: () => getDefaultTargetDevHub(),
|
|
25
|
+
findOrgByUsernameOrAlias: (allOrgs, usernameOrAlias) => findOrgByUsernameOrAlias(allOrgs, usernameOrAlias),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
class NoopTelemetryService {
|
|
30
|
+
sendEvent(_eventName, _event) {
|
|
31
|
+
// no-op
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=services.js.map
|
package/lib/sf-mcp-server.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { Implementation } from '@modelcontextprotocol/sdk/types.js';
|
|
1
|
+
import { McpServer, RegisteredTool, ToolCallback } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { Implementation, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
|
|
3
3
|
import { ServerOptions } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
+
import { ZodRawShape } from 'zod';
|
|
4
5
|
import { Telemetry } from './telemetry.js';
|
|
5
|
-
import { RateLimitConfig } from './
|
|
6
|
+
import { RateLimitConfig } from './utils/rate-limiter.js';
|
|
6
7
|
type ToolMethodSignatures = {
|
|
7
8
|
tool: McpServer['tool'];
|
|
8
9
|
connect: McpServer['connect'];
|
|
10
|
+
registerTool: McpServer['registerTool'];
|
|
9
11
|
};
|
|
10
12
|
/**
|
|
11
13
|
* Extended server options that include telemetry and rate limiting
|
|
@@ -15,8 +17,6 @@ export type SfMcpServerOptions = ServerOptions & {
|
|
|
15
17
|
telemetry?: Telemetry;
|
|
16
18
|
/** Optional rate limiting configuration */
|
|
17
19
|
rateLimit?: Partial<RateLimitConfig>;
|
|
18
|
-
/** Enable dynamic tool loading */
|
|
19
|
-
dynamicTools?: boolean;
|
|
20
20
|
};
|
|
21
21
|
/**
|
|
22
22
|
* A server implementation that extends the base MCP server with telemetry and rate limiting capabilities.
|
|
@@ -30,7 +30,6 @@ export declare class SfMcpServer extends McpServer implements ToolMethodSignatur
|
|
|
30
30
|
private logger;
|
|
31
31
|
/** Optional telemetry instance for tracking server events */
|
|
32
32
|
private telemetry?;
|
|
33
|
-
private dynamicTools;
|
|
34
33
|
/** Rate limiter for controlling tool call frequency */
|
|
35
34
|
private rateLimiter?;
|
|
36
35
|
/**
|
|
@@ -41,6 +40,12 @@ export declare class SfMcpServer extends McpServer implements ToolMethodSignatur
|
|
|
41
40
|
*/
|
|
42
41
|
constructor(serverInfo: Implementation, options?: SfMcpServerOptions);
|
|
43
42
|
connect: McpServer['connect'];
|
|
44
|
-
|
|
43
|
+
registerTool<InputArgs extends ZodRawShape, OutputArgs extends ZodRawShape>(name: string, config: {
|
|
44
|
+
title?: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
inputSchema?: InputArgs;
|
|
47
|
+
outputSchema?: OutputArgs;
|
|
48
|
+
annotations?: ToolAnnotations;
|
|
49
|
+
}, cb: ToolCallback<InputArgs>): RegisteredTool;
|
|
45
50
|
}
|
|
46
51
|
export {};
|
package/lib/sf-mcp-server.js
CHANGED
|
@@ -15,9 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
17
17
|
import { Logger } from '@salesforce/core';
|
|
18
|
-
import {
|
|
19
|
-
import { createRateLimiter } from './shared/rate-limiter.js';
|
|
20
|
-
import { CORE_TOOLS } from './registry.js';
|
|
18
|
+
import { createRateLimiter } from './utils/rate-limiter.js';
|
|
21
19
|
/**
|
|
22
20
|
* A server implementation that extends the base MCP server with telemetry and rate limiting capabilities.
|
|
23
21
|
*
|
|
@@ -30,7 +28,6 @@ export class SfMcpServer extends McpServer {
|
|
|
30
28
|
logger = Logger.childFromRoot('mcp-server');
|
|
31
29
|
/** Optional telemetry instance for tracking server events */
|
|
32
30
|
telemetry;
|
|
33
|
-
dynamicTools;
|
|
34
31
|
/** Rate limiter for controlling tool call frequency */
|
|
35
32
|
rateLimiter;
|
|
36
33
|
/**
|
|
@@ -42,7 +39,6 @@ export class SfMcpServer extends McpServer {
|
|
|
42
39
|
constructor(serverInfo, options) {
|
|
43
40
|
super(serverInfo, options);
|
|
44
41
|
this.telemetry = options?.telemetry;
|
|
45
|
-
this.dynamicTools = options?.dynamicTools ?? false;
|
|
46
42
|
// Initialize rate limiter if configuration is provided
|
|
47
43
|
if (options?.rateLimit !== undefined) {
|
|
48
44
|
this.rateLimiter = createRateLimiter(options.rateLimit);
|
|
@@ -75,10 +71,8 @@ export class SfMcpServer extends McpServer {
|
|
|
75
71
|
});
|
|
76
72
|
}
|
|
77
73
|
};
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const cb = rest[rest.length - 1];
|
|
81
|
-
const wrappedCb = async (args) => {
|
|
74
|
+
registerTool(name, config, cb) {
|
|
75
|
+
const wrappedCb = async (args, extra) => {
|
|
82
76
|
this.logger.debug(`Tool ${name} called`);
|
|
83
77
|
// Check rate limit before executing tool
|
|
84
78
|
if (this.rateLimiter) {
|
|
@@ -103,7 +97,7 @@ export class SfMcpServer extends McpServer {
|
|
|
103
97
|
this.logger.debug(`Tool ${name} rate check passed. Remaining: ${rateLimitResult.remaining}`);
|
|
104
98
|
}
|
|
105
99
|
const startTime = Date.now();
|
|
106
|
-
const result = await cb(args);
|
|
100
|
+
const result = await cb(args, extra);
|
|
107
101
|
const runtimeMs = Date.now() - startTime;
|
|
108
102
|
this.logger.debug(`Tool ${name} completed in ${runtimeMs}ms`);
|
|
109
103
|
if (result.isError)
|
|
@@ -115,17 +109,8 @@ export class SfMcpServer extends McpServer {
|
|
|
115
109
|
});
|
|
116
110
|
return result;
|
|
117
111
|
};
|
|
118
|
-
|
|
119
|
-
const tool = super.tool(name, ...rest.slice(0, -1), wrappedCb);
|
|
120
|
-
if (this.dynamicTools) {
|
|
121
|
-
// Only disable the tool if it's not a core tool
|
|
122
|
-
if (!CORE_TOOLS.includes(name))
|
|
123
|
-
tool.disable();
|
|
124
|
-
addTool(tool, name).catch((error) => {
|
|
125
|
-
this.logger.error(`Failed to add tool ${name}:`, error);
|
|
126
|
-
});
|
|
127
|
-
}
|
|
112
|
+
const tool = super.registerTool(name, config, wrappedCb);
|
|
128
113
|
return tool;
|
|
129
|
-
}
|
|
114
|
+
}
|
|
130
115
|
}
|
|
131
116
|
//# sourceMappingURL=sf-mcp-server.js.map
|
package/lib/telemetry.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Attributes } from '@salesforce/telemetry';
|
|
2
2
|
import { Config } from '@oclif/core';
|
|
3
|
-
|
|
3
|
+
import { TelemetryService } from '@salesforce/mcp-provider-api/src/index.js';
|
|
4
|
+
export declare class Telemetry implements TelemetryService {
|
|
4
5
|
private readonly config;
|
|
5
6
|
private attributes;
|
|
6
7
|
/**
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { McpTool, McpToolConfig, Toolset } from '@salesforce/mcp-provider-api';
|
|
3
|
+
import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
4
|
+
import { SfMcpServer } from '../sf-mcp-server.js';
|
|
5
|
+
declare const enableToolsParamsSchema: z.ZodObject<{
|
|
6
|
+
tools: z.ZodArray<z.ZodString, "many">;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
tools: string[];
|
|
9
|
+
}, {
|
|
10
|
+
tools: string[];
|
|
11
|
+
}>;
|
|
12
|
+
type InputArgs = z.infer<typeof enableToolsParamsSchema>;
|
|
13
|
+
type InputArgsShapeType = typeof enableToolsParamsSchema.shape;
|
|
14
|
+
type OutputArgsShapeType = z.ZodRawShape;
|
|
15
|
+
export declare class EnableToolsMcpTool extends McpTool<InputArgsShapeType, OutputArgsShapeType> {
|
|
16
|
+
private readonly server;
|
|
17
|
+
constructor(server: SfMcpServer);
|
|
18
|
+
getToolsets(): Toolset[];
|
|
19
|
+
getName(): string;
|
|
20
|
+
getConfig(): McpToolConfig<InputArgsShapeType, OutputArgsShapeType>;
|
|
21
|
+
exec(input: InputArgs): Promise<CallToolResult>;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025, Salesforce, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { z } from 'zod';
|
|
17
|
+
import { McpTool, Toolset } from '@salesforce/mcp-provider-api';
|
|
18
|
+
import { enableTools as utilEnableTools } from '../utils/tools.js';
|
|
19
|
+
const enableToolsParamsSchema = z.object({
|
|
20
|
+
tools: z.array(z.string()).describe('The names of the tools to enable'),
|
|
21
|
+
});
|
|
22
|
+
export class EnableToolsMcpTool extends McpTool {
|
|
23
|
+
server;
|
|
24
|
+
constructor(server) {
|
|
25
|
+
super();
|
|
26
|
+
this.server = server;
|
|
27
|
+
}
|
|
28
|
+
getToolsets() {
|
|
29
|
+
return [Toolset.CORE];
|
|
30
|
+
}
|
|
31
|
+
getName() {
|
|
32
|
+
return 'sf-enable-tools';
|
|
33
|
+
}
|
|
34
|
+
getConfig() {
|
|
35
|
+
return {
|
|
36
|
+
title: 'Enable Salesforce MCP tools',
|
|
37
|
+
description: `Enable one or more of the tools the Salesforce MCP server provides.
|
|
38
|
+
|
|
39
|
+
AGENT INSTRUCTIONS:
|
|
40
|
+
Use sf-list-all-tools first to learn what tools are available for enabling.
|
|
41
|
+
Once you have enabled the tool, you MUST invoke that tool to accomplish the user's original request - DO NOT USE A DIFFERENT TOOL OR THE COMMAND LINE.`,
|
|
42
|
+
inputSchema: enableToolsParamsSchema.shape,
|
|
43
|
+
outputSchema: undefined,
|
|
44
|
+
annotations: {
|
|
45
|
+
title: 'Enable Salesforce MCP tools',
|
|
46
|
+
readOnlyHint: true,
|
|
47
|
+
openWorldHint: false,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async exec(input) {
|
|
52
|
+
if (input.tools.length === 0) {
|
|
53
|
+
return {
|
|
54
|
+
isError: true,
|
|
55
|
+
content: [
|
|
56
|
+
{
|
|
57
|
+
type: 'text',
|
|
58
|
+
text: 'No tools specified to enable.',
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const results = await utilEnableTools(input.tools);
|
|
64
|
+
this.server.sendToolListChanged();
|
|
65
|
+
const isError = results.some((result) => !result.success);
|
|
66
|
+
return {
|
|
67
|
+
isError,
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: 'text',
|
|
71
|
+
text: results.map((result) => result.message).join('\n'),
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=sf-enable-tools.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { McpTool, McpToolConfig, Toolset } from '@salesforce/mcp-provider-api';
|
|
2
|
+
import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
export declare class ListToolsMcpTool extends McpTool {
|
|
4
|
+
getToolsets(): Toolset[];
|
|
5
|
+
getName(): string;
|
|
6
|
+
getConfig(): McpToolConfig;
|
|
7
|
+
exec(): Promise<CallToolResult>;
|
|
8
|
+
}
|
|
@@ -13,10 +13,19 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
17
|
-
import { listAllTools } from '
|
|
18
|
-
export
|
|
19
|
-
|
|
16
|
+
import { McpTool, Toolset } from '@salesforce/mcp-provider-api';
|
|
17
|
+
import { listAllTools } from '../utils/tools.js';
|
|
18
|
+
export class ListToolsMcpTool extends McpTool {
|
|
19
|
+
getToolsets() {
|
|
20
|
+
return [Toolset.CORE];
|
|
21
|
+
}
|
|
22
|
+
getName() {
|
|
23
|
+
return 'sf-list-tools';
|
|
24
|
+
}
|
|
25
|
+
getConfig() {
|
|
26
|
+
return {
|
|
27
|
+
title: 'List all individual tools',
|
|
28
|
+
description: `List all available tools this Salesforce MCP server can offer, providing the enabled status and description of each.
|
|
20
29
|
|
|
21
30
|
AGENT INSTRUCTIONS:
|
|
22
31
|
DO NOT USE THIS TOOL if you already know what tool you need - try to call the tool directly first.
|
|
@@ -27,10 +36,25 @@ ONLY use this tool if:
|
|
|
27
36
|
|
|
28
37
|
If you find one or more tools you want to enable, call sf-enable-tools with all the tool names.
|
|
29
38
|
Once you have enabled a tool, you MUST invoke the tool to accomplish the user's original request - DO NOT USE A DIFFERENT TOOL OR THE COMMAND LINE.
|
|
30
|
-
Once a tool has been enabled, you do not need to call sf-list-tools again - instead, invoke the desired tool directly.`,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
Once a tool has been enabled, you do not need to call sf-list-tools again - instead, invoke the desired tool directly.`,
|
|
40
|
+
inputSchema: undefined,
|
|
41
|
+
outputSchema: undefined,
|
|
42
|
+
annotations: {
|
|
43
|
+
readOnlyHint: true,
|
|
44
|
+
openWorldHint: false,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async exec() {
|
|
49
|
+
return {
|
|
50
|
+
isError: false,
|
|
51
|
+
content: [
|
|
52
|
+
{
|
|
53
|
+
type: 'text',
|
|
54
|
+
text: JSON.stringify(await listAllTools(), null, 2),
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
35
59
|
}
|
|
36
60
|
//# sourceMappingURL=sf-list-tools.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { McpTool, McpToolConfig, Toolset, Services } from '@salesforce/mcp-provider-api';
|
|
3
|
+
import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Suggest a Salesforce CLI (sf) command based on user input.
|
|
6
|
+
*/
|
|
7
|
+
declare const suggestCliCommandParamsSchema: z.ZodObject<{
|
|
8
|
+
query: z.ZodString;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
query: string;
|
|
11
|
+
}, {
|
|
12
|
+
query: string;
|
|
13
|
+
}>;
|
|
14
|
+
type InputArgs = z.infer<typeof suggestCliCommandParamsSchema>;
|
|
15
|
+
type InputArgsShape = typeof suggestCliCommandParamsSchema.shape;
|
|
16
|
+
type OutputArgsShape = z.ZodRawShape;
|
|
17
|
+
export declare class SuggestCliCommandMcpTool extends McpTool<InputArgsShape, OutputArgsShape> {
|
|
18
|
+
private readonly services;
|
|
19
|
+
constructor(services: Services);
|
|
20
|
+
getToolsets(): Toolset[];
|
|
21
|
+
getName(): string;
|
|
22
|
+
getConfig(): McpToolConfig<InputArgsShape, OutputArgsShape>;
|
|
23
|
+
exec(input: InputArgs): Promise<CallToolResult>;
|
|
24
|
+
}
|
|
25
|
+
export {};
|