@salesforce/b2c-dx-mcp 0.0.1 → 0.3.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.
- package/README.md +422 -29
- package/bin/run.cmd +3 -0
- package/bin/run.js +27 -0
- package/content/auth.md +62 -0
- package/content/components.md +123 -0
- package/content/config.md +180 -0
- package/content/data-fetching.md +323 -0
- package/content/extensions.md +80 -0
- package/content/i18n.md +121 -0
- package/content/page-designer.md +86 -0
- package/content/performance.md +80 -0
- package/content/pitfalls.md +141 -0
- package/content/quick-reference.md +226 -0
- package/content/state-management.md +75 -0
- package/content/styling.md +51 -0
- package/content/testing.md +232 -0
- package/dist/commands/mcp.d.ts +110 -0
- package/dist/commands/mcp.js +333 -0
- package/dist/registry.d.ts +37 -0
- package/dist/registry.js +212 -0
- package/dist/server.d.ts +46 -0
- package/dist/server.js +98 -0
- package/dist/services.d.ts +168 -0
- package/dist/services.js +191 -0
- package/dist/tools/adapter.d.ts +201 -0
- package/dist/tools/adapter.js +220 -0
- package/dist/tools/cartridges/index.d.ts +20 -0
- package/dist/tools/cartridges/index.js +101 -0
- package/dist/tools/index.d.ts +17 -0
- package/dist/tools/index.js +25 -0
- package/dist/tools/mrt/index.d.ts +20 -0
- package/dist/tools/mrt/index.js +101 -0
- package/dist/tools/pwav3/index.d.ts +13 -0
- package/dist/tools/pwav3/index.js +78 -0
- package/dist/tools/scapi/index.d.ts +9 -0
- package/dist/tools/scapi/index.js +68 -0
- package/dist/tools/storefrontnext/developer-guidelines.d.ts +9 -0
- package/dist/tools/storefrontnext/developer-guidelines.js +140 -0
- package/dist/tools/storefrontnext/index.d.ts +13 -0
- package/dist/tools/storefrontnext/index.js +83 -0
- package/dist/utils/constants.d.ts +16 -0
- package/dist/utils/constants.js +18 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.js +16 -0
- package/dist/utils/types.d.ts +45 -0
- package/dist/utils/types.js +7 -0
- package/oclif.manifest.json +377 -0
- package/package.json +123 -7
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { McpTool, Toolset, StartupFlags } from './utils/index.js';
|
|
2
|
+
import type { B2CDxMcpServer } from './server.js';
|
|
3
|
+
import type { Services } from './services.js';
|
|
4
|
+
/**
|
|
5
|
+
* Registry of tools organized by toolset.
|
|
6
|
+
* Tools can belong to multiple toolsets via their `toolsets` array.
|
|
7
|
+
*/
|
|
8
|
+
export type ToolRegistry = Record<Toolset, McpTool[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Creates the tool registry from all toolset providers.
|
|
11
|
+
* Tools are organized by their declared `toolsets` array, allowing
|
|
12
|
+
* a single tool to appear in multiple toolsets.
|
|
13
|
+
*
|
|
14
|
+
* @param services - Services instance for dependency injection
|
|
15
|
+
* @returns Complete tool registry
|
|
16
|
+
*/
|
|
17
|
+
export declare function createToolRegistry(services: Services): ToolRegistry;
|
|
18
|
+
/**
|
|
19
|
+
* Register tools with the MCP server based on startup flags.
|
|
20
|
+
*
|
|
21
|
+
* Tool selection logic:
|
|
22
|
+
* 1. If no valid tools result from --toolsets and --tools, perform auto-discovery
|
|
23
|
+
* 2. Start with all tools from --toolsets (or auto-discovered toolsets)
|
|
24
|
+
* 3. Add individual tools from --tools (can be from any toolset)
|
|
25
|
+
*
|
|
26
|
+
* Auto-discovery always enables at least the BASE_TOOLSET (SCAPI), even if no
|
|
27
|
+
* project types are detected in the workspace.
|
|
28
|
+
*
|
|
29
|
+
* Example:
|
|
30
|
+
* --toolsets STOREFRONTNEXT,MRT --tools cartridge_deploy
|
|
31
|
+
* This enables STOREFRONTNEXT and MRT toolsets, plus adds cartridge_deploy from CARTRIDGES.
|
|
32
|
+
*
|
|
33
|
+
* @param flags - Startup flags from CLI
|
|
34
|
+
* @param server - B2CDxMcpServer instance
|
|
35
|
+
* @param services - Services instance
|
|
36
|
+
*/
|
|
37
|
+
export declare function registerToolsets(flags: StartupFlags, server: B2CDxMcpServer, services: Services): Promise<void>;
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2
|
|
4
|
+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { getLogger } from '@salesforce/b2c-tooling-sdk/logging';
|
|
7
|
+
import { detectWorkspaceType } from '@salesforce/b2c-tooling-sdk/discovery';
|
|
8
|
+
import { ALL_TOOLSETS, TOOLSETS, VALID_TOOLSET_NAMES } from './utils/index.js';
|
|
9
|
+
import { createCartridgesTools } from './tools/cartridges/index.js';
|
|
10
|
+
import { createMrtTools } from './tools/mrt/index.js';
|
|
11
|
+
import { createPwav3Tools } from './tools/pwav3/index.js';
|
|
12
|
+
import { createScapiTools } from './tools/scapi/index.js';
|
|
13
|
+
import { createStorefrontNextTools } from './tools/storefrontnext/index.js';
|
|
14
|
+
/**
|
|
15
|
+
* Base toolset that is always enabled.
|
|
16
|
+
* Provides SCAPI discovery and custom API scaffolding tools.
|
|
17
|
+
*/
|
|
18
|
+
const BASE_TOOLSET = 'SCAPI';
|
|
19
|
+
/**
|
|
20
|
+
* Toolset mapping by project type.
|
|
21
|
+
* Each project type enables specific toolsets IN ADDITION to the base toolset.
|
|
22
|
+
*/
|
|
23
|
+
const PROJECT_TYPE_TOOLSETS = {
|
|
24
|
+
cartridges: ['CARTRIDGES'],
|
|
25
|
+
'pwa-kit-v3': ['PWAV3', 'MRT'],
|
|
26
|
+
'storefront-next': ['STOREFRONTNEXT', 'MRT', 'CARTRIDGES'],
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Gets toolsets for a project type, always including the base toolset.
|
|
30
|
+
*/
|
|
31
|
+
function getToolsetsForProjectType(projectType) {
|
|
32
|
+
const additionalToolsets = PROJECT_TYPE_TOOLSETS[projectType] ?? [];
|
|
33
|
+
return [...additionalToolsets, BASE_TOOLSET];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Maps multiple detected project types to a union of MCP toolsets.
|
|
37
|
+
*
|
|
38
|
+
* Combines toolsets from all matched project types, enabling hybrid
|
|
39
|
+
* project support (e.g., cartridges + pwa-kit-v3 gets CARTRIDGES + PWAV3 + MRT + SCAPI).
|
|
40
|
+
*
|
|
41
|
+
* @param projectTypes - Array of detected project types
|
|
42
|
+
* @returns Union of all toolsets for the detected project types (always includes base toolset)
|
|
43
|
+
*/
|
|
44
|
+
function getToolsetsForProjectTypes(projectTypes) {
|
|
45
|
+
const toolsetSet = new Set();
|
|
46
|
+
// Always include base toolset
|
|
47
|
+
toolsetSet.add(BASE_TOOLSET);
|
|
48
|
+
// Add toolsets for each detected project type
|
|
49
|
+
for (const projectType of projectTypes) {
|
|
50
|
+
for (const toolset of getToolsetsForProjectType(projectType)) {
|
|
51
|
+
toolsetSet.add(toolset);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return [...toolsetSet];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Creates the tool registry from all toolset providers.
|
|
58
|
+
* Tools are organized by their declared `toolsets` array, allowing
|
|
59
|
+
* a single tool to appear in multiple toolsets.
|
|
60
|
+
*
|
|
61
|
+
* @param services - Services instance for dependency injection
|
|
62
|
+
* @returns Complete tool registry
|
|
63
|
+
*/
|
|
64
|
+
export function createToolRegistry(services) {
|
|
65
|
+
const registry = {
|
|
66
|
+
CARTRIDGES: [],
|
|
67
|
+
MRT: [],
|
|
68
|
+
PWAV3: [],
|
|
69
|
+
SCAPI: [],
|
|
70
|
+
STOREFRONTNEXT: [],
|
|
71
|
+
};
|
|
72
|
+
// Collect all tools from all factories
|
|
73
|
+
const allTools = [
|
|
74
|
+
...createCartridgesTools(services),
|
|
75
|
+
...createMrtTools(services),
|
|
76
|
+
...createPwav3Tools(services),
|
|
77
|
+
...createScapiTools(services),
|
|
78
|
+
...createStorefrontNextTools(services),
|
|
79
|
+
];
|
|
80
|
+
// Organize tools by their declared toolsets (supports multi-toolset)
|
|
81
|
+
for (const tool of allTools) {
|
|
82
|
+
for (const toolset of tool.toolsets) {
|
|
83
|
+
registry[toolset].push(tool);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return registry;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Performs workspace auto-discovery and returns appropriate toolsets.
|
|
90
|
+
* Always includes BASE_TOOLSET even if no project types are detected.
|
|
91
|
+
*
|
|
92
|
+
* @param flags - Startup flags containing workingDirectory
|
|
93
|
+
* @param reason - Reason for triggering auto-discovery (for logging)
|
|
94
|
+
* @returns Array of toolsets to enable
|
|
95
|
+
*/
|
|
96
|
+
async function performAutoDiscovery(flags, reason) {
|
|
97
|
+
const logger = getLogger();
|
|
98
|
+
// Working directory from --working-directory flag or SFCC_WORKING_DIRECTORY env var
|
|
99
|
+
const workingDirectory = flags.workingDirectory ?? process.cwd();
|
|
100
|
+
// Warn if working directory wasn't explicitly configured
|
|
101
|
+
if (!flags.workingDirectory) {
|
|
102
|
+
logger.warn({ cwd: workingDirectory }, 'No --working-directory flag or SFCC_WORKING_DIRECTORY env var provided. ' +
|
|
103
|
+
'MCP clients like Cursor and Claude Desktop often spawn servers from ~ instead of the project directory. ' +
|
|
104
|
+
'Set --working-directory or SFCC_WORKING_DIRECTORY for reliable auto-discovery.');
|
|
105
|
+
}
|
|
106
|
+
const detectionResult = await detectWorkspaceType(workingDirectory);
|
|
107
|
+
// Map all detected project types to MCP toolsets (union)
|
|
108
|
+
// Note: getToolsetsForProjectTypes always includes BASE_TOOLSET
|
|
109
|
+
const mappedToolsets = getToolsetsForProjectTypes(detectionResult.projectTypes);
|
|
110
|
+
logger.info({
|
|
111
|
+
reason,
|
|
112
|
+
projectTypes: detectionResult.projectTypes,
|
|
113
|
+
matchedPatterns: detectionResult.matchedPatterns,
|
|
114
|
+
enabledToolsets: mappedToolsets,
|
|
115
|
+
}, `Auto-discovery (${reason}): project types: ${detectionResult.projectTypes.join(', ') || 'none'}`);
|
|
116
|
+
return mappedToolsets;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Register tools with the MCP server based on startup flags.
|
|
120
|
+
*
|
|
121
|
+
* Tool selection logic:
|
|
122
|
+
* 1. If no valid tools result from --toolsets and --tools, perform auto-discovery
|
|
123
|
+
* 2. Start with all tools from --toolsets (or auto-discovered toolsets)
|
|
124
|
+
* 3. Add individual tools from --tools (can be from any toolset)
|
|
125
|
+
*
|
|
126
|
+
* Auto-discovery always enables at least the BASE_TOOLSET (SCAPI), even if no
|
|
127
|
+
* project types are detected in the workspace.
|
|
128
|
+
*
|
|
129
|
+
* Example:
|
|
130
|
+
* --toolsets STOREFRONTNEXT,MRT --tools cartridge_deploy
|
|
131
|
+
* This enables STOREFRONTNEXT and MRT toolsets, plus adds cartridge_deploy from CARTRIDGES.
|
|
132
|
+
*
|
|
133
|
+
* @param flags - Startup flags from CLI
|
|
134
|
+
* @param server - B2CDxMcpServer instance
|
|
135
|
+
* @param services - Services instance
|
|
136
|
+
*/
|
|
137
|
+
export async function registerToolsets(flags, server, services) {
|
|
138
|
+
const toolsets = flags.toolsets ?? [];
|
|
139
|
+
const individualTools = flags.tools ?? [];
|
|
140
|
+
const allowNonGaTools = flags.allowNonGaTools ?? false;
|
|
141
|
+
const logger = getLogger();
|
|
142
|
+
// Create the tool registry (all available tools)
|
|
143
|
+
const toolRegistry = createToolRegistry(services);
|
|
144
|
+
// Build flat list of all tools for lookup
|
|
145
|
+
const allTools = Object.values(toolRegistry).flat();
|
|
146
|
+
const allToolsByName = new Map(allTools.map((tool) => [tool.name, tool]));
|
|
147
|
+
const existingToolNames = new Set(allToolsByName.keys());
|
|
148
|
+
// Determine valid individual tools
|
|
149
|
+
const invalidTools = individualTools.filter((name) => !existingToolNames.has(name));
|
|
150
|
+
const validIndividualTools = individualTools.filter((name) => existingToolNames.has(name));
|
|
151
|
+
// Warn about invalid --tools names (but continue with valid ones)
|
|
152
|
+
if (invalidTools.length > 0) {
|
|
153
|
+
logger.warn({ invalidTools, validTools: [...existingToolNames] }, `Ignoring invalid tool name(s): "${invalidTools.join('", "')}"`);
|
|
154
|
+
}
|
|
155
|
+
// Warn about invalid --toolsets names (but continue with valid ones)
|
|
156
|
+
const invalidToolsets = toolsets.filter((t) => !VALID_TOOLSET_NAMES.includes(t));
|
|
157
|
+
if (invalidToolsets.length > 0) {
|
|
158
|
+
logger.warn({ invalidToolsets, validToolsets: VALID_TOOLSET_NAMES }, `Ignoring invalid toolset(s): "${invalidToolsets.join('", "')}"`);
|
|
159
|
+
}
|
|
160
|
+
// Determine which toolsets to enable
|
|
161
|
+
const validToolsets = toolsets.filter((t) => TOOLSETS.includes(t));
|
|
162
|
+
const toolsetsToEnable = new Set(toolsets.includes(ALL_TOOLSETS) ? TOOLSETS : validToolsets);
|
|
163
|
+
// Auto-discovery: If no valid toolsets AND no valid individual tools, detect workspace type.
|
|
164
|
+
// This handles both: (1) no flags provided, and (2) all provided flags are invalid.
|
|
165
|
+
// Auto-discovery enables appropriate toolsets based on workspace type,
|
|
166
|
+
// or at minimum BASE_TOOLSET if no project types are detected.
|
|
167
|
+
if (toolsetsToEnable.size === 0 && validIndividualTools.length === 0) {
|
|
168
|
+
const discoveredToolsets = await performAutoDiscovery(flags, 'no valid toolsets or tools');
|
|
169
|
+
for (const toolset of discoveredToolsets) {
|
|
170
|
+
toolsetsToEnable.add(toolset);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Build the set of tools to register:
|
|
174
|
+
// 1. Start with tools from enabled toolsets
|
|
175
|
+
// 2. Add individual tools from --tools
|
|
176
|
+
const toolsToRegister = [];
|
|
177
|
+
const registeredToolNames = new Set();
|
|
178
|
+
// Step 1: Add tools from enabled toolsets
|
|
179
|
+
for (const toolset of toolsetsToEnable) {
|
|
180
|
+
for (const tool of toolRegistry[toolset]) {
|
|
181
|
+
if (!registeredToolNames.has(tool.name)) {
|
|
182
|
+
toolsToRegister.push(tool);
|
|
183
|
+
registeredToolNames.add(tool.name);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Step 2: Add individual tools from --tools (can be from any toolset)
|
|
188
|
+
for (const toolName of validIndividualTools) {
|
|
189
|
+
const tool = allToolsByName.get(toolName);
|
|
190
|
+
if (tool && !registeredToolNames.has(toolName)) {
|
|
191
|
+
toolsToRegister.push(tool);
|
|
192
|
+
registeredToolNames.add(toolName);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Register all selected tools
|
|
196
|
+
await registerTools(toolsToRegister, server, allowNonGaTools);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Register a list of tools with the server.
|
|
200
|
+
*/
|
|
201
|
+
async function registerTools(tools, server, allowNonGaTools) {
|
|
202
|
+
for (const tool of tools) {
|
|
203
|
+
// Skip non-GA tools if not allowed
|
|
204
|
+
if (tool.isGA === false && !allowNonGaTools) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
// Register the tool
|
|
208
|
+
// TODO: Telemetry - Tool registration includes timing/error tracking
|
|
209
|
+
server.addTool(tool.name, tool.description, tool.inputSchema, async (args) => tool.handler(args));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=registry.js.map
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { CallToolResult, Implementation } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import type { ServerOptions } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
+
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
5
|
+
import type { ZodRawShape } from 'zod';
|
|
6
|
+
import type { Telemetry } from '@salesforce/b2c-tooling-sdk/telemetry';
|
|
7
|
+
/**
|
|
8
|
+
* Extended server options.
|
|
9
|
+
*/
|
|
10
|
+
export interface B2CDxMcpServerOptions extends ServerOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Telemetry instance for tracking server and tool events.
|
|
13
|
+
* If not provided, telemetry is disabled.
|
|
14
|
+
*/
|
|
15
|
+
telemetry?: Telemetry;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A server implementation that extends the base MCP server.
|
|
19
|
+
*
|
|
20
|
+
* @augments {McpServer}
|
|
21
|
+
*/
|
|
22
|
+
export declare class B2CDxMcpServer extends McpServer {
|
|
23
|
+
private telemetry?;
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new B2CDxMcpServer instance
|
|
26
|
+
*
|
|
27
|
+
* @param serverInfo - The server implementation details
|
|
28
|
+
* @param options - Optional server configuration
|
|
29
|
+
*/
|
|
30
|
+
constructor(serverInfo: Implementation, options?: B2CDxMcpServerOptions);
|
|
31
|
+
/**
|
|
32
|
+
* Register a tool with the server.
|
|
33
|
+
*
|
|
34
|
+
* This method provides a convenient way to register tools.
|
|
35
|
+
*
|
|
36
|
+
* @param name - Tool name
|
|
37
|
+
* @param description - Tool description
|
|
38
|
+
* @param inputSchema - Zod schema for input validation
|
|
39
|
+
* @param handler - Function to handle tool invocations
|
|
40
|
+
*/
|
|
41
|
+
addTool(name: string, description: string, inputSchema: ZodRawShape, handler: (args: Record<string, unknown>) => Promise<CallToolResult>): void;
|
|
42
|
+
/**
|
|
43
|
+
* Connect to a transport.
|
|
44
|
+
*/
|
|
45
|
+
connect(transport: Transport): Promise<void>;
|
|
46
|
+
}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2
|
|
4
|
+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
+
/**
|
|
8
|
+
* A server implementation that extends the base MCP server.
|
|
9
|
+
*
|
|
10
|
+
* @augments {McpServer}
|
|
11
|
+
*/
|
|
12
|
+
export class B2CDxMcpServer extends McpServer {
|
|
13
|
+
telemetry;
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new B2CDxMcpServer instance
|
|
16
|
+
*
|
|
17
|
+
* @param serverInfo - The server implementation details
|
|
18
|
+
* @param options - Optional server configuration
|
|
19
|
+
*/
|
|
20
|
+
constructor(serverInfo, options) {
|
|
21
|
+
super(serverInfo, options);
|
|
22
|
+
this.telemetry = options?.telemetry;
|
|
23
|
+
// Set up oninitialized handler
|
|
24
|
+
this.server.oninitialized = () => {
|
|
25
|
+
const clientInfo = this.server.getClientVersion();
|
|
26
|
+
if (clientInfo) {
|
|
27
|
+
this.telemetry?.addAttributes({
|
|
28
|
+
clientName: clientInfo.name,
|
|
29
|
+
clientVersion: clientInfo.version,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Register a tool with the server.
|
|
36
|
+
*
|
|
37
|
+
* This method provides a convenient way to register tools.
|
|
38
|
+
*
|
|
39
|
+
* @param name - Tool name
|
|
40
|
+
* @param description - Tool description
|
|
41
|
+
* @param inputSchema - Zod schema for input validation
|
|
42
|
+
* @param handler - Function to handle tool invocations
|
|
43
|
+
*/
|
|
44
|
+
addTool(name, description, inputSchema, handler) {
|
|
45
|
+
const wrappedHandler = async (args, _extra) => {
|
|
46
|
+
const startTime = Date.now();
|
|
47
|
+
try {
|
|
48
|
+
const result = await handler(args);
|
|
49
|
+
const runTimeMs = Date.now() - startTime;
|
|
50
|
+
await this.telemetry
|
|
51
|
+
?.sendEventAndFlush('TOOL_CALLED', {
|
|
52
|
+
toolName: name,
|
|
53
|
+
runTimeMs,
|
|
54
|
+
isError: result.isError ?? false,
|
|
55
|
+
})
|
|
56
|
+
.catch(() => { });
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
const runTimeMs = Date.now() - startTime;
|
|
61
|
+
await this.telemetry
|
|
62
|
+
?.sendEventAndFlush('TOOL_CALLED', {
|
|
63
|
+
toolName: name,
|
|
64
|
+
runTimeMs,
|
|
65
|
+
isError: true,
|
|
66
|
+
})
|
|
67
|
+
.catch(() => { });
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
// Use the new registerTool API (tool() is deprecated)
|
|
72
|
+
this.registerTool(name, { description, inputSchema }, wrappedHandler);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Connect to a transport.
|
|
76
|
+
*/
|
|
77
|
+
async connect(transport) {
|
|
78
|
+
try {
|
|
79
|
+
await super.connect(transport);
|
|
80
|
+
const statusPromise = this.isConnected()
|
|
81
|
+
? this.telemetry?.sendEventAndFlush('SERVER_STATUS', { status: 'started' })
|
|
82
|
+
: this.telemetry?.sendEventAndFlush('SERVER_STATUS', {
|
|
83
|
+
status: 'error',
|
|
84
|
+
errorMessage: 'Server not connected after connect() call',
|
|
85
|
+
});
|
|
86
|
+
await (statusPromise ?? Promise.resolve()).catch(() => { });
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
const errorPromise = this.telemetry?.sendEventAndFlush('SERVER_STATUS', {
|
|
90
|
+
status: 'error',
|
|
91
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
92
|
+
});
|
|
93
|
+
await (errorPromise ?? Promise.resolve()).catch(() => { });
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Services module providing dependency injection for MCP tools.
|
|
3
|
+
*
|
|
4
|
+
* The {@link Services} class is the central dependency container for tools,
|
|
5
|
+
* providing:
|
|
6
|
+
* - Pre-resolved B2CInstance for WebDAV/OCAPI operations
|
|
7
|
+
* - Pre-resolved MRT authentication for Managed Runtime operations
|
|
8
|
+
* - MRT project/environment configuration
|
|
9
|
+
* - File system utilities for local operations
|
|
10
|
+
*
|
|
11
|
+
* ## Creating Services
|
|
12
|
+
*
|
|
13
|
+
* Use {@link Services.fromResolvedConfig} with an already-resolved configuration:
|
|
14
|
+
*
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // In a command that extends BaseCommand
|
|
17
|
+
* const services = Services.fromResolvedConfig(this.resolvedConfig);
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* ## Resolution Pattern
|
|
21
|
+
*
|
|
22
|
+
* Both B2CInstance and MRT auth are resolved once at server startup (not on each tool call).
|
|
23
|
+
* This provides fail-fast behavior and consistent performance.
|
|
24
|
+
*
|
|
25
|
+
* **B2C Instance** (for WebDAV/OCAPI tools):
|
|
26
|
+
* - Flags (highest priority) merged with dw.json (auto-discovered or via --config)
|
|
27
|
+
*
|
|
28
|
+
* **MRT Auth** (for Managed Runtime tools):
|
|
29
|
+
* 1. `--api-key` flag (oclif also checks `SFCC_MRT_API_KEY` env var)
|
|
30
|
+
* 2. `~/.mobify` config file (or `~/.mobify--[hostname]` if `--cloud-origin` is set)
|
|
31
|
+
*
|
|
32
|
+
* **MRT Origin** (for Managed Runtime API URL):
|
|
33
|
+
* 1. `--cloud-origin` flag (oclif also checks `SFCC_MRT_CLOUD_ORIGIN` env var)
|
|
34
|
+
* 2. `mrtOrigin` field in dw.json
|
|
35
|
+
* 3. Default: `https://cloud.mobify.com`
|
|
36
|
+
*
|
|
37
|
+
* @module services
|
|
38
|
+
*/
|
|
39
|
+
import fs from 'node:fs';
|
|
40
|
+
import type { B2CInstance } from '@salesforce/b2c-tooling-sdk';
|
|
41
|
+
import type { AuthStrategy } from '@salesforce/b2c-tooling-sdk/auth';
|
|
42
|
+
import type { ResolvedB2CConfig } from '@salesforce/b2c-tooling-sdk/config';
|
|
43
|
+
/**
|
|
44
|
+
* MRT (Managed Runtime) configuration.
|
|
45
|
+
* Groups auth, project, environment, and origin settings.
|
|
46
|
+
*/
|
|
47
|
+
export interface MrtConfig {
|
|
48
|
+
/** Pre-resolved auth strategy for MRT API operations */
|
|
49
|
+
auth?: AuthStrategy;
|
|
50
|
+
/** MRT project slug from --project flag or SFCC_MRT_PROJECT env var */
|
|
51
|
+
project?: string;
|
|
52
|
+
/** MRT environment from --environment flag or SFCC_MRT_ENVIRONMENT env var */
|
|
53
|
+
environment?: string;
|
|
54
|
+
/** MRT API origin URL from --cloud-origin flag, SFCC_MRT_CLOUD_ORIGIN env var, or mrtOrigin in dw.json */
|
|
55
|
+
origin?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Options for Services constructor (internal).
|
|
59
|
+
*/
|
|
60
|
+
export interface ServicesOptions {
|
|
61
|
+
/** Pre-resolved B2C instance (if configured) */
|
|
62
|
+
b2cInstance?: B2CInstance;
|
|
63
|
+
/** Pre-resolved MRT configuration (auth, project, environment) */
|
|
64
|
+
mrtConfig?: MrtConfig;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Services class that provides utilities for MCP tools.
|
|
68
|
+
*
|
|
69
|
+
* Use the static `Services.fromResolvedConfig()` factory method to create
|
|
70
|
+
* an instance from an already-resolved configuration.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* // In a command that extends BaseCommand
|
|
75
|
+
* const services = Services.fromResolvedConfig(this.resolvedConfig);
|
|
76
|
+
*
|
|
77
|
+
* // Access resolved config
|
|
78
|
+
* services.b2cInstance; // B2CInstance | undefined
|
|
79
|
+
* services.mrtConfig.auth; // AuthStrategy | undefined
|
|
80
|
+
* services.mrtConfig.project; // string | undefined
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare class Services {
|
|
84
|
+
/**
|
|
85
|
+
* Pre-resolved B2C instance for WebDAV/OCAPI operations.
|
|
86
|
+
* Resolved once at server startup from InstanceCommand flags and dw.json.
|
|
87
|
+
* Undefined if no B2C instance configuration was available.
|
|
88
|
+
*/
|
|
89
|
+
readonly b2cInstance?: B2CInstance;
|
|
90
|
+
/**
|
|
91
|
+
* Pre-resolved MRT configuration (auth, project, environment, origin).
|
|
92
|
+
* Resolved once at server startup from MrtCommand flags and ~/.mobify.
|
|
93
|
+
*/
|
|
94
|
+
readonly mrtConfig: MrtConfig;
|
|
95
|
+
constructor(opts?: ServicesOptions);
|
|
96
|
+
/**
|
|
97
|
+
* Creates a Services instance from an already-resolved configuration.
|
|
98
|
+
*
|
|
99
|
+
* @param config - Already-resolved configuration from BaseCommand.resolvedConfig
|
|
100
|
+
* @returns Services instance with resolved config
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```typescript
|
|
104
|
+
* // In a command that extends BaseCommand
|
|
105
|
+
* const services = Services.fromResolvedConfig(this.resolvedConfig);
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
static fromResolvedConfig(config: ResolvedB2CConfig): Services;
|
|
109
|
+
/**
|
|
110
|
+
* Check if a file or directory exists.
|
|
111
|
+
*
|
|
112
|
+
* @param targetPath - Path to check
|
|
113
|
+
* @returns True if exists, false otherwise
|
|
114
|
+
*/
|
|
115
|
+
exists(targetPath: string): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Get the current working directory.
|
|
118
|
+
*/
|
|
119
|
+
getCwd(): string;
|
|
120
|
+
/**
|
|
121
|
+
* Get the user's home directory.
|
|
122
|
+
*/
|
|
123
|
+
getHomeDir(): string;
|
|
124
|
+
/**
|
|
125
|
+
* Get OS platform information.
|
|
126
|
+
*/
|
|
127
|
+
getPlatform(): NodeJS.Platform;
|
|
128
|
+
/**
|
|
129
|
+
* Get system temporary directory.
|
|
130
|
+
*/
|
|
131
|
+
getTmpDir(): string;
|
|
132
|
+
/**
|
|
133
|
+
* Join path segments.
|
|
134
|
+
*
|
|
135
|
+
* @param segments - Path segments to join
|
|
136
|
+
* @returns Joined path
|
|
137
|
+
*/
|
|
138
|
+
joinPath(...segments: string[]): string;
|
|
139
|
+
/**
|
|
140
|
+
* List directory contents.
|
|
141
|
+
*
|
|
142
|
+
* @param dirPath - Directory path to list
|
|
143
|
+
* @returns Array of directory entries
|
|
144
|
+
*/
|
|
145
|
+
listDirectory(dirPath: string): fs.Dirent[];
|
|
146
|
+
/**
|
|
147
|
+
* Read a file from the filesystem.
|
|
148
|
+
*
|
|
149
|
+
* @param filePath - Path to the file
|
|
150
|
+
* @param encoding - File encoding (default: utf8)
|
|
151
|
+
* @returns File contents as a string
|
|
152
|
+
*/
|
|
153
|
+
readFile(filePath: string, encoding?: 'ascii' | 'base64' | 'hex' | 'latin1' | 'utf8'): string;
|
|
154
|
+
/**
|
|
155
|
+
* Resolve a path relative to the current working directory.
|
|
156
|
+
*
|
|
157
|
+
* @param segments - Path segments to join and resolve
|
|
158
|
+
* @returns Absolute path
|
|
159
|
+
*/
|
|
160
|
+
resolvePath(...segments: string[]): string;
|
|
161
|
+
/**
|
|
162
|
+
* Get file or directory stats.
|
|
163
|
+
*
|
|
164
|
+
* @param targetPath - Path to get stats for
|
|
165
|
+
* @returns File stats object
|
|
166
|
+
*/
|
|
167
|
+
stat(targetPath: string): fs.Stats;
|
|
168
|
+
}
|