@salesforce/mcp 0.17.1 → 0.17.2-dev.2

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.
Files changed (73) hide show
  1. package/lib/index.d.ts +1 -1
  2. package/lib/index.js +7 -5
  3. package/lib/main-server-provider.d.ts +7 -0
  4. package/lib/main-server-provider.js +31 -0
  5. package/lib/registry.d.ts +3 -29
  6. package/lib/registry.js +9 -113
  7. package/lib/scripts/build-index.js +1 -1
  8. package/lib/services.d.ts +12 -0
  9. package/lib/services.js +34 -0
  10. package/lib/sf-mcp-server.d.ts +12 -7
  11. package/lib/sf-mcp-server.js +6 -21
  12. package/lib/telemetry.d.ts +2 -1
  13. package/lib/tools/sf-enable-tools.d.ts +23 -0
  14. package/lib/tools/sf-enable-tools.js +77 -0
  15. package/lib/tools/sf-list-tools.d.ts +8 -0
  16. package/lib/{modules/platform-cli → tools}/sf-list-tools.js +33 -9
  17. package/lib/tools/sf-suggest-cli-command.d.ts +25 -0
  18. package/lib/{modules/platform-cli → tools}/sf-suggest-cli-command.js +46 -18
  19. package/lib/utils/assets.d.ts +21 -0
  20. package/lib/{assets.js → utils/assets.js} +23 -33
  21. package/lib/{shared → utils}/auth.d.ts +3 -8
  22. package/lib/{shared → utils}/auth.js +2 -42
  23. package/lib/utils/registry-utils.d.ts +4 -0
  24. package/lib/utils/registry-utils.js +87 -0
  25. package/lib/{modules/platform-cli/utils → utils}/tools.js +1 -1
  26. package/lib/utils/types.d.ts +5 -0
  27. package/package.json +8 -4
  28. package/README.md +0 -263
  29. package/lib/assets.d.ts +0 -44
  30. package/lib/modules/platform-cli/index.d.ts +0 -16
  31. package/lib/modules/platform-cli/index.js +0 -32
  32. package/lib/modules/platform-cli/sf-assign-permission-set.d.ts +0 -20
  33. package/lib/modules/platform-cli/sf-assign-permission-set.js +0 -89
  34. package/lib/modules/platform-cli/sf-create-org-snapshot.d.ts +0 -23
  35. package/lib/modules/platform-cli/sf-create-org-snapshot.js +0 -88
  36. package/lib/modules/platform-cli/sf-create-scratch-org.d.ts +0 -50
  37. package/lib/modules/platform-cli/sf-create-scratch-org.js +0 -132
  38. package/lib/modules/platform-cli/sf-delete-org.d.ts +0 -14
  39. package/lib/modules/platform-cli/sf-delete-org.js +0 -65
  40. package/lib/modules/platform-cli/sf-deploy-metadata.d.ts +0 -27
  41. package/lib/modules/platform-cli/sf-deploy-metadata.js +0 -164
  42. package/lib/modules/platform-cli/sf-enable-tools.d.ts +0 -2
  43. package/lib/modules/platform-cli/sf-enable-tools.js +0 -42
  44. package/lib/modules/platform-cli/sf-get-username.d.ts +0 -17
  45. package/lib/modules/platform-cli/sf-get-username.js +0 -109
  46. package/lib/modules/platform-cli/sf-list-all-orgs.d.ts +0 -11
  47. package/lib/modules/platform-cli/sf-list-all-orgs.js +0 -59
  48. package/lib/modules/platform-cli/sf-list-tools.d.ts +0 -2
  49. package/lib/modules/platform-cli/sf-org-open.d.ts +0 -17
  50. package/lib/modules/platform-cli/sf-org-open.js +0 -57
  51. package/lib/modules/platform-cli/sf-query-org.d.ts +0 -20
  52. package/lib/modules/platform-cli/sf-query-org.js +0 -66
  53. package/lib/modules/platform-cli/sf-resume.d.ts +0 -20
  54. package/lib/modules/platform-cli/sf-resume.js +0 -149
  55. package/lib/modules/platform-cli/sf-retrieve-metadata.d.ts +0 -2
  56. package/lib/modules/platform-cli/sf-retrieve-metadata.js +0 -128
  57. package/lib/modules/platform-cli/sf-suggest-cli-command.d.ts +0 -5
  58. package/lib/modules/platform-cli/sf-test-agents.d.ts +0 -21
  59. package/lib/modules/platform-cli/sf-test-agents.js +0 -84
  60. package/lib/modules/platform-cli/sf-test-apex.d.ts +0 -40
  61. package/lib/modules/platform-cli/sf-test-apex.js +0 -132
  62. package/lib/shared/params.d.ts +0 -5
  63. package/lib/shared/params.js +0 -46
  64. package/lib/shared/types.d.ts +0 -33
  65. package/lib/shared/utils.d.ts +0 -11
  66. package/lib/shared/utils.js +0 -71
  67. package/lib/tsconfig.tsbuildinfo +0 -1
  68. /package/lib/{shared → utils}/cache.d.ts +0 -0
  69. /package/lib/{shared → utils}/cache.js +0 -0
  70. /package/lib/{shared → utils}/rate-limiter.d.ts +0 -0
  71. /package/lib/{shared → utils}/rate-limiter.js +0 -0
  72. /package/lib/{modules/platform-cli/utils → utils}/tools.d.ts +0 -0
  73. /package/lib/{shared → utils}/types.js +0 -0
@@ -14,16 +14,30 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { z } from 'zod';
17
- import { getAssets } from '../../assets.js';
18
- import { textResponse } from '../../shared/utils.js';
19
- const suggestCliCommandParamsSchema = z.object({
20
- query: z.string().describe('The natural language query to suggest an `sf` command'),
21
- });
17
+ import { McpTool, Toolset } from '@salesforce/mcp-provider-api';
18
+ import { getAssets } from '../utils/assets.js';
22
19
  /**
23
20
  * Suggest a Salesforce CLI (sf) command based on user input.
24
21
  */
25
- export const suggestCliCommand = (server) => {
26
- server.tool('sf-suggest-cli-command', `Suggests an \`sf\` CLI command based on a natural language query. It finds relevant commands from a local index and uses an LLM to construct the final, precise command to fulfill the user's request.
22
+ const suggestCliCommandParamsSchema = z.object({
23
+ query: z.string().describe('The natural language query to suggest an `sf` command'),
24
+ });
25
+ export class SuggestCliCommandMcpTool extends McpTool {
26
+ services;
27
+ constructor(services) {
28
+ super();
29
+ this.services = services;
30
+ }
31
+ getToolsets() {
32
+ return [Toolset.CORE];
33
+ }
34
+ getName() {
35
+ return 'sf-suggest-cli-command';
36
+ }
37
+ getConfig() {
38
+ return {
39
+ title: 'Suggest CLI Command',
40
+ description: `Suggests an \`sf\` CLI command based on a natural language query. It finds relevant commands from a local index and uses an LLM to construct the final, precise command to fulfill the user's request.
27
41
 
28
42
  AGENT INSTRUCTIONS:
29
43
  Use this tool whenever a user:
@@ -34,22 +48,28 @@ Use this tool whenever a user:
34
48
  NEVER use this tool for enabling Salesforce MCP tools (use sf-enable-tools instead).
35
49
  NEVER use this tool for listing available Salesforce MCP tools (use sf-list-tools instead).
36
50
  NEVER use this tool for understanding the Salesforce MCP server's capabilities.
37
- NEVER use this tool for understanding the input schema of a Salesforce MCP tool.`, suggestCliCommandParamsSchema.shape, {
38
- readOnlyHint: true,
39
- }, async ({ query }) => {
40
- const assets = await getAssets();
51
+ NEVER use this tool for understanding the input schema of a Salesforce MCP tool.`,
52
+ inputSchema: suggestCliCommandParamsSchema.shape,
53
+ outputSchema: undefined,
54
+ annotations: {
55
+ readOnlyHint: true,
56
+ },
57
+ };
58
+ }
59
+ async exec(input) {
60
+ const assets = await getAssets(this.services.getConfigService().getDataDir(), 'sf-commands.json', 'commands-index.bin');
41
61
  // Embed the user query
42
- const queryEmbedding = await assets.embedder(query, {
62
+ const queryEmbedding = await assets.embedder(input.query, {
43
63
  pooling: 'mean',
44
64
  normalize: true,
45
65
  });
46
66
  // Perform Semantic Search (FAISS)
47
- const searchResults = assets.faissIndex.search(
67
+ const searchResults = assets.index.search(
48
68
  // Convert the embedding tensor data to a flat array of numbers
49
69
  Array.from(queryEmbedding.data), 5);
50
70
  const topCandidateIds = searchResults.labels.slice(0, 5);
51
71
  const contextCommands = topCandidateIds.map((id) => {
52
- const command = assets.commands.find((c) => c.id === id);
72
+ const command = assets.data.find((c) => c.id === id);
53
73
  // Remove the embedding text to avoid sending it to the LLM
54
74
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
55
75
  const { embeddingText, ...commandWithoutEmbeddingText } = command;
@@ -65,7 +85,7 @@ NEVER use this tool for understanding the input schema of a Salesforce MCP tool.
65
85
  - Do not use any flags or commands not listed in the reference.
66
86
 
67
87
  User Request:
68
- "${query}"
88
+ "${input.query}"
69
89
 
70
90
  Command Reference:
71
91
  ${JSON.stringify(contextCommands, null, 2)}
@@ -83,7 +103,15 @@ Notes about Flag Properties:
83
103
 
84
104
  Synthesize the single "sf" command that best fulfills the user's request.
85
105
  `;
86
- return textResponse(prompt);
87
- });
88
- };
106
+ return {
107
+ isError: false,
108
+ content: [
109
+ {
110
+ type: 'text',
111
+ text: prompt,
112
+ },
113
+ ],
114
+ };
115
+ }
116
+ }
89
117
  //# sourceMappingURL=sf-suggest-cli-command.js.map
@@ -0,0 +1,21 @@
1
+ import { FeatureExtractionPipeline } from '@huggingface/transformers';
2
+ import faiss from 'faiss-node';
3
+ type Assets<T> = {
4
+ data: T;
5
+ embedder: FeatureExtractionPipeline;
6
+ index: faiss.IndexFlatL2;
7
+ };
8
+ /**
9
+ * Conditionally builds or rebuilds a FAISS index based on its existence and age.
10
+ *
11
+ * This function checks if a FAISS index file exists in the specified output directory.
12
+ * If the index exists but is older than one week, it triggers a rebuild. If the index
13
+ * doesn't exist, it initiates the initial build process. The build process can run as a
14
+ * detached child process or in the same process depending on the detached parameter.
15
+ *
16
+ * @param indexPath - The path to the FAISS index file.
17
+ * @param detached - Whether to run the build process detached (default: true)
18
+ */
19
+ export declare function maybeBuildIndex(indexPath: string, detached?: boolean): Promise<void>;
20
+ export declare function getAssets<T>(dataDir: string, dataPath: string, indexPath: string): Promise<Assets<T>>;
21
+ export {};
@@ -19,7 +19,6 @@ import { spawn } from 'node:child_process';
19
19
  import faiss from 'faiss-node';
20
20
  import { pipeline } from '@huggingface/transformers';
21
21
  import { ux } from '@oclif/core';
22
- let CACHED_DATA_DIR = null;
23
22
  /**
24
23
  * Conditionally builds or rebuilds a FAISS index based on its existence and age.
25
24
  *
@@ -28,36 +27,31 @@ let CACHED_DATA_DIR = null;
28
27
  * doesn't exist, it initiates the initial build process. The build process can run as a
29
28
  * detached child process or in the same process depending on the detached parameter.
30
29
  *
31
- * @param outputDir - The directory path where the FAISS index should be located or created
30
+ * @param indexPath - The path to the FAISS index file.
32
31
  * @param detached - Whether to run the build process detached (default: true)
33
- *
34
- * @remarks
35
- * - Sets the global CACHED_DATA_DIR variable to the provided outputDir. This is used to locate the index file.
36
32
  */
37
- export async function maybeBuildIndex(outputDir, detached = true) {
38
- CACHED_DATA_DIR = outputDir;
39
- const faissIndexPath = join(outputDir, 'faiss-index.bin');
33
+ export async function maybeBuildIndex(indexPath, detached = true) {
40
34
  try {
41
- const stats = fs.statSync(faissIndexPath);
35
+ const stats = fs.statSync(indexPath);
42
36
  const oneWeekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
43
- ux.stderr(`Checking FAISS index in ${outputDir}...`);
37
+ ux.stderr(`Checking FAISS index in ${indexPath}...`);
44
38
  ux.stderr(`Last modified: ${stats.mtime.toString()}`);
45
39
  if (stats.mtime < oneWeekAgo) {
46
- ux.stderr(`FAISS index is more than 1 week old - rebuilding in ${outputDir}...`);
47
- await spawnBuildScript(outputDir, detached);
40
+ ux.stderr(`FAISS index is more than 1 week old - rebuilding in ${indexPath}...`);
41
+ await spawnBuildScript(indexPath, detached);
48
42
  }
49
43
  else {
50
- ux.stderr(`FAISS index is up to date in ${outputDir}. No rebuild needed.`);
44
+ ux.stderr(`FAISS index is up to date in ${indexPath}. No rebuild needed.`);
51
45
  }
52
46
  }
53
47
  catch (error) {
54
48
  // File doesn't exist, so build the index
55
- ux.stderr(`Building FAISS index in ${outputDir}...`);
56
- await spawnBuildScript(outputDir, detached);
49
+ ux.stderr(`Building FAISS index in ${indexPath}...`);
50
+ await spawnBuildScript(indexPath, detached);
57
51
  }
58
52
  }
59
53
  function spawnBuildScript(outputDir, detached) {
60
- const scriptPath = resolve(import.meta.dirname, 'scripts', 'build-index.js');
54
+ const scriptPath = resolve(import.meta.dirname, '..', 'scripts', 'build-index.js');
61
55
  const args = [scriptPath, outputDir];
62
56
  if (detached) {
63
57
  spawn('node', args, {
@@ -85,37 +79,33 @@ function spawnBuildScript(outputDir, detached) {
85
79
  });
86
80
  }
87
81
  }
88
- export async function getAssets() {
89
- if (!CACHED_DATA_DIR) {
90
- throw new Error('Data directory not set. Please call maybeBuildIndex first.');
91
- }
82
+ export async function getAssets(dataDir, dataPath, indexPath) {
83
+ const fullDataPath = join(dataDir, dataPath);
84
+ const fullIndexPath = join(dataDir, indexPath);
92
85
  // Ensure the index is built or rebuilt if necessary
93
- await maybeBuildIndex(CACHED_DATA_DIR, false);
94
- const commandsPath = join(CACHED_DATA_DIR, 'sf-commands.json');
95
- const faissIndexPath = join(CACHED_DATA_DIR, 'faiss-index.bin');
86
+ await maybeBuildIndex(fullIndexPath, false);
96
87
  try {
97
- await fs.promises.access(commandsPath);
88
+ await fs.promises.access(fullDataPath);
98
89
  }
99
90
  catch {
100
- throw new Error(`Commands file not found at ${commandsPath}. Please run maybeBuildIndex to build the index.`);
91
+ throw new Error(`Commands file not found at ${fullDataPath}. Please run maybeBuildIndex to build the index.`);
101
92
  }
102
93
  try {
103
- await fs.promises.access(faissIndexPath);
94
+ await fs.promises.access(fullIndexPath);
104
95
  }
105
96
  catch {
106
- throw new Error(`FAISS index not found at ${faissIndexPath}. Please run maybeBuildIndex to build the index.`);
97
+ throw new Error(`FAISS index not found at ${fullIndexPath}. Please run maybeBuildIndex to build the index.`);
107
98
  }
108
99
  try {
109
- const commandsData = await fs.promises.readFile(commandsPath, 'utf-8');
110
- const commands = JSON.parse(commandsData);
111
- const faissIndex = faiss.IndexFlatL2.read(faissIndexPath);
100
+ const dataRaw = await fs.promises.readFile(fullDataPath, 'utf-8');
101
+ const data = JSON.parse(dataRaw);
102
+ const index = faiss.IndexFlatL2.read(fullIndexPath);
112
103
  const embedder = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2', {
113
104
  dtype: 'fp32',
114
105
  });
115
106
  return {
116
- commands,
117
- commandNames: commands.map((cmd) => cmd.command),
118
- faissIndex,
107
+ data,
108
+ index,
119
109
  embedder,
120
110
  };
121
111
  }
@@ -1,5 +1,5 @@
1
1
  import { Connection, type OrgAuthorization } from '@salesforce/core';
2
- import { type ConfigInfoWithCache, type SanitizedOrgAuthorization } from './types.js';
2
+ import { type OrgConfigInfo, type SanitizedOrgAuthorization } from '@salesforce/mcp-provider-api';
3
3
  /**
4
4
  * Sanitizes org authorization data by filtering out sensitive fields
5
5
  *
@@ -7,14 +7,9 @@ import { type ConfigInfoWithCache, type SanitizedOrgAuthorization } from './type
7
7
  * @returns Array of sanitized org authorization objects with only allowed fields
8
8
  */
9
9
  export declare function sanitizeOrgs(orgs: OrgAuthorization[]): SanitizedOrgAuthorization[];
10
- export declare function suggestUsername(): Promise<{
11
- suggestedUsername: string | undefined;
12
- reasoning: string;
13
- aliasForReference?: string;
14
- }>;
15
10
  export declare function getConnection(username: string): Promise<Connection>;
16
11
  export declare function findOrgByUsernameOrAlias(allOrgs: SanitizedOrgAuthorization[], usernameOrAlias: string): SanitizedOrgAuthorization | undefined;
17
12
  export declare function getAllAllowedOrgs(): Promise<SanitizedOrgAuthorization[]>;
18
13
  export declare function filterAllowedOrgs(orgs: SanitizedOrgAuthorization[], allowList: Set<string>): Promise<SanitizedOrgAuthorization[]>;
19
- export declare function getDefaultTargetOrg(): Promise<ConfigInfoWithCache | undefined>;
20
- export declare function getDefaultTargetDevHub(): Promise<ConfigInfoWithCache | undefined>;
14
+ export declare function getDefaultTargetOrg(): Promise<OrgConfigInfo | undefined>;
15
+ export declare function getDefaultTargetDevHub(): Promise<OrgConfigInfo | undefined>;
@@ -13,7 +13,6 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- /* eslint-disable no-console */
17
16
  import { AuthInfo, Connection, ConfigAggregator, OrgConfigProperties } from '@salesforce/core';
18
17
  import Cache from './cache.js';
19
18
  /**
@@ -36,41 +35,6 @@ export function sanitizeOrgs(orgs) {
36
35
  isExpired: org.isExpired,
37
36
  }));
38
37
  }
39
- export async function suggestUsername() {
40
- let reasoning;
41
- let suggestedUsername;
42
- let aliasForReference;
43
- const allAllowedOrgs = await getAllAllowedOrgs();
44
- const defaultTargetOrg = await getDefaultTargetOrg();
45
- const defaultTargetDevHub = await getDefaultTargetDevHub();
46
- const targetOrgLocation = defaultTargetOrg?.location ? `(${defaultTargetOrg.location}) ` : '';
47
- const targetDevHubLocation = defaultTargetDevHub?.location ? `(${defaultTargetDevHub.location}) ` : '';
48
- if (allAllowedOrgs.length === 1) {
49
- suggestedUsername = allAllowedOrgs[0].username;
50
- aliasForReference = allAllowedOrgs[0].aliases?.[0];
51
- reasoning = 'it was the only org found in the MCP Servers allowlisted orgs';
52
- }
53
- else if (defaultTargetOrg?.value) {
54
- const foundOrg = findOrgByUsernameOrAlias(allAllowedOrgs, defaultTargetOrg.value);
55
- suggestedUsername = foundOrg?.username;
56
- aliasForReference = foundOrg?.aliases?.[0];
57
- reasoning = `it is the default ${targetOrgLocation}target org`;
58
- }
59
- else if (defaultTargetDevHub?.value) {
60
- const foundOrg = findOrgByUsernameOrAlias(allAllowedOrgs, defaultTargetDevHub.value);
61
- suggestedUsername = foundOrg?.username;
62
- aliasForReference = foundOrg?.aliases?.[0];
63
- reasoning = `it is the default ${targetDevHubLocation}dev hub org`;
64
- }
65
- else {
66
- reasoning = 'Error: no org was inferred. Ask the user to specify one';
67
- }
68
- return {
69
- suggestedUsername,
70
- aliasForReference,
71
- reasoning,
72
- };
73
- }
74
38
  // This function is the main entry point for Tools to get an allowlisted Connection
75
39
  export async function getConnection(username) {
76
40
  // We get all allowed orgs each call in case the directory has changed (default configs)
@@ -91,11 +55,7 @@ export function findOrgByUsernameOrAlias(allOrgs, usernameOrAlias) {
91
55
  });
92
56
  }
93
57
  export async function getAllAllowedOrgs() {
94
- // Support for passing orgs via URL parameters for testing purposes
95
- const url = new URL(import.meta.url);
96
- const params = url.searchParams.get('orgs');
97
- const paramOrg = params ? params : undefined;
98
- const orgAllowList = paramOrg ? new Set([paramOrg]) : (await Cache.safeGet('allowedOrgs')) ?? new Set();
58
+ const orgAllowList = (await Cache.safeGet('allowedOrgs')) ?? new Set();
99
59
  // Get all orgs on the user's machine
100
60
  const allOrgs = await AuthInfo.listAllAuthorizations();
101
61
  // Sanitize the orgs to remove sensitive data
@@ -162,7 +122,7 @@ async function getDefaultConfig(property) {
162
122
  if (defaultOrgMaps[property].has(path)) {
163
123
  // If the cache has the config's path set, use the cached config
164
124
  const cachedConfig = defaultOrgMaps[property].get(path);
165
- return { ...cachedConfig, cached: true };
125
+ return cachedConfig;
166
126
  }
167
127
  else {
168
128
  defaultOrgMaps[property].set(path, typedConfig);
@@ -0,0 +1,4 @@
1
+ import { Toolset } from '@salesforce/mcp-provider-api';
2
+ import { SfMcpServer } from '../sf-mcp-server.js';
3
+ import { Services } from '../services.js';
4
+ export declare function registerToolsets(toolsets: Array<Toolset | 'all'>, useDynamicTools: boolean, server: SfMcpServer, services: Services): Promise<void>;
@@ -0,0 +1,87 @@
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 { ux } from '@oclif/core';
17
+ import { MCP_PROVIDER_API_VERSION, Toolset, TOOLSETS, } from '@salesforce/mcp-provider-api';
18
+ import { MCP_PROVIDER_REGISTRY } from '../registry.js';
19
+ import { addTool } from '../utils/tools.js';
20
+ import { createDynamicServerTools } from '../main-server-provider.js';
21
+ export async function registerToolsets(toolsets, useDynamicTools, server, services) {
22
+ if (useDynamicTools) {
23
+ const dynamicTools = createDynamicServerTools(server);
24
+ ux.stderr('Registering dynamic tools');
25
+ // eslint-disable-next-line no-await-in-loop
26
+ await registerTools(dynamicTools, server, useDynamicTools);
27
+ }
28
+ else {
29
+ ux.stderr('Skipping registration of dynamic tools');
30
+ }
31
+ const toolsetsToEnable = toolsets.includes('all')
32
+ ? new Set(TOOLSETS.filter((ts) => ts !== Toolset.EXPERIMENTAL))
33
+ : new Set([Toolset.CORE, ...toolsets]);
34
+ const newToolRegistry = await createToolRegistryFromProviders(MCP_PROVIDER_REGISTRY, services);
35
+ for (const toolset of TOOLSETS) {
36
+ if (toolsetsToEnable.has(toolset)) {
37
+ ux.stderr(`Registering ${toolset} tools`);
38
+ // eslint-disable-next-line no-await-in-loop
39
+ await registerTools(newToolRegistry[toolset], server, useDynamicTools);
40
+ }
41
+ else {
42
+ ux.stderr(`Skipping registration of ${toolset} tools`);
43
+ }
44
+ }
45
+ }
46
+ async function registerTools(tools, server, useDynamicTools) {
47
+ for (const tool of tools) {
48
+ const registeredTool = server.registerTool(tool.getName(), tool.getConfig(), (...args) => tool.exec(...args));
49
+ const toolsets = tool.getToolsets();
50
+ if (useDynamicTools && !toolsets.includes(Toolset.CORE)) {
51
+ registeredTool.disable();
52
+ }
53
+ // eslint-disable-next-line no-await-in-loop
54
+ await addTool(registeredTool, tool.getName());
55
+ }
56
+ }
57
+ async function createToolRegistryFromProviders(providers, services) {
58
+ // Initialize an empty registry
59
+ const registry = Object.fromEntries(Object.values(Toolset).map((key) => [key, []]));
60
+ // Avoid calling await in a loop by first getting all the promises
61
+ const toolPromises = [];
62
+ for (const provider of providers) {
63
+ validateMcpProviderVersion(provider);
64
+ const toolsPromise = provider.provideTools(services);
65
+ toolPromises.push(toolsPromise);
66
+ }
67
+ // Get all the tools from the promises and then add them to the registry
68
+ const tools = (await Promise.all(toolPromises)).flat();
69
+ for (const tool of tools) {
70
+ for (const toolset of tool.getToolsets()) {
71
+ registry[toolset].push(tool);
72
+ }
73
+ }
74
+ return registry;
75
+ }
76
+ /**
77
+ * Validation function to confirm that providers are at the expected major version.
78
+ */
79
+ function validateMcpProviderVersion(provider) {
80
+ if (provider.getVersion().major !== MCP_PROVIDER_API_VERSION.major) {
81
+ throw new Error(`The version '${provider
82
+ .getVersion()
83
+ .toString()}' for '${provider.getName()}' is incompatible with this MCP Server.\n` +
84
+ `Expected the major version to be '${MCP_PROVIDER_API_VERSION.major}'.`);
85
+ }
86
+ }
87
+ //# sourceMappingURL=registry-utils.js.map
@@ -13,7 +13,7 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import Cache from '../../../shared/cache.js';
16
+ import Cache from './cache.js';
17
17
  /**
18
18
  * Add a tool to the cache
19
19
  */
@@ -0,0 +1,5 @@
1
+ import { RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export type ToolInfo = {
3
+ tool: RegisteredTool;
4
+ name: string;
5
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/mcp",
3
- "version": "0.17.1",
3
+ "version": "0.17.2-dev.2",
4
4
  "description": "MCP Server for interacting with Salesforce instances",
5
5
  "bin": {
6
6
  "sf-mcp-server": "bin/run.js"
@@ -20,6 +20,7 @@
20
20
  "link-check": "wireit",
21
21
  "lint": "wireit",
22
22
  "lint-fix": "yarn sf-lint --fix",
23
+ "package": "yarn pack",
23
24
  "postpack": "sf-clean --ignore-signing-artifacts",
24
25
  "prepack": "sf-prepack",
25
26
  "prepare": "sf-install",
@@ -36,23 +37,26 @@
36
37
  "bin",
37
38
  "lib",
38
39
  "!lib/**/*.map",
39
- "messages"
40
+ "messages",
41
+ "LICENSE.txt",
42
+ "package.json"
40
43
  ],
41
44
  "dependencies": {
42
45
  "@huggingface/transformers": "^3.7.0",
43
- "@jsforce/jsforce-node": "^3.9.4",
44
46
  "@modelcontextprotocol/sdk": "^1.16.0",
45
47
  "@oclif/core": "^4.5.1",
46
48
  "@salesforce/agents": "^0.15.4",
47
49
  "@salesforce/apex-node": "^8.2.1",
48
50
  "@salesforce/core": "^8.18.0",
49
51
  "@salesforce/kit": "^3.1.6",
52
+ "@salesforce/mcp-provider-api": "^0.1.0",
53
+ "@salesforce/mcp-provider-dx-core": "^0.1.2",
54
+ "@salesforce/mcp-provider-code-analyzer": "^0.0.1",
50
55
  "@salesforce/source-deploy-retrieve": "^12.22.0",
51
56
  "@salesforce/source-tracking": "^7.4.8",
52
57
  "@salesforce/telemetry": "^6.1.0",
53
58
  "@salesforce/ts-types": "^2.0.11",
54
59
  "faiss-node": "^0.5.1",
55
- "open": "^10.1.2",
56
60
  "zod": "^3.25.76"
57
61
  },
58
62
  "devDependencies": {