@salesforce/b2c-dx-mcp 0.0.1 → 0.3.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/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
package/dist/services.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
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
|
+
/**
|
|
7
|
+
* Services module providing dependency injection for MCP tools.
|
|
8
|
+
*
|
|
9
|
+
* The {@link Services} class is the central dependency container for tools,
|
|
10
|
+
* providing:
|
|
11
|
+
* - Pre-resolved B2CInstance for WebDAV/OCAPI operations
|
|
12
|
+
* - Pre-resolved MRT authentication for Managed Runtime operations
|
|
13
|
+
* - MRT project/environment configuration
|
|
14
|
+
* - File system utilities for local operations
|
|
15
|
+
*
|
|
16
|
+
* ## Creating Services
|
|
17
|
+
*
|
|
18
|
+
* Use {@link Services.fromResolvedConfig} with an already-resolved configuration:
|
|
19
|
+
*
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // In a command that extends BaseCommand
|
|
22
|
+
* const services = Services.fromResolvedConfig(this.resolvedConfig);
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* ## Resolution Pattern
|
|
26
|
+
*
|
|
27
|
+
* Both B2CInstance and MRT auth are resolved once at server startup (not on each tool call).
|
|
28
|
+
* This provides fail-fast behavior and consistent performance.
|
|
29
|
+
*
|
|
30
|
+
* **B2C Instance** (for WebDAV/OCAPI tools):
|
|
31
|
+
* - Flags (highest priority) merged with dw.json (auto-discovered or via --config)
|
|
32
|
+
*
|
|
33
|
+
* **MRT Auth** (for Managed Runtime tools):
|
|
34
|
+
* 1. `--api-key` flag (oclif also checks `SFCC_MRT_API_KEY` env var)
|
|
35
|
+
* 2. `~/.mobify` config file (or `~/.mobify--[hostname]` if `--cloud-origin` is set)
|
|
36
|
+
*
|
|
37
|
+
* **MRT Origin** (for Managed Runtime API URL):
|
|
38
|
+
* 1. `--cloud-origin` flag (oclif also checks `SFCC_MRT_CLOUD_ORIGIN` env var)
|
|
39
|
+
* 2. `mrtOrigin` field in dw.json
|
|
40
|
+
* 3. Default: `https://cloud.mobify.com`
|
|
41
|
+
*
|
|
42
|
+
* @module services
|
|
43
|
+
*/
|
|
44
|
+
import fs from 'node:fs';
|
|
45
|
+
import path from 'node:path';
|
|
46
|
+
import os from 'node:os';
|
|
47
|
+
/**
|
|
48
|
+
* Services class that provides utilities for MCP tools.
|
|
49
|
+
*
|
|
50
|
+
* Use the static `Services.fromResolvedConfig()` factory method to create
|
|
51
|
+
* an instance from an already-resolved configuration.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* // In a command that extends BaseCommand
|
|
56
|
+
* const services = Services.fromResolvedConfig(this.resolvedConfig);
|
|
57
|
+
*
|
|
58
|
+
* // Access resolved config
|
|
59
|
+
* services.b2cInstance; // B2CInstance | undefined
|
|
60
|
+
* services.mrtConfig.auth; // AuthStrategy | undefined
|
|
61
|
+
* services.mrtConfig.project; // string | undefined
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export class Services {
|
|
65
|
+
/**
|
|
66
|
+
* Pre-resolved B2C instance for WebDAV/OCAPI operations.
|
|
67
|
+
* Resolved once at server startup from InstanceCommand flags and dw.json.
|
|
68
|
+
* Undefined if no B2C instance configuration was available.
|
|
69
|
+
*/
|
|
70
|
+
b2cInstance;
|
|
71
|
+
/**
|
|
72
|
+
* Pre-resolved MRT configuration (auth, project, environment, origin).
|
|
73
|
+
* Resolved once at server startup from MrtCommand flags and ~/.mobify.
|
|
74
|
+
*/
|
|
75
|
+
mrtConfig;
|
|
76
|
+
constructor(opts = {}) {
|
|
77
|
+
this.b2cInstance = opts.b2cInstance;
|
|
78
|
+
this.mrtConfig = opts.mrtConfig ?? {};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Creates a Services instance from an already-resolved configuration.
|
|
82
|
+
*
|
|
83
|
+
* @param config - Already-resolved configuration from BaseCommand.resolvedConfig
|
|
84
|
+
* @returns Services instance with resolved config
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* // In a command that extends BaseCommand
|
|
89
|
+
* const services = Services.fromResolvedConfig(this.resolvedConfig);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
static fromResolvedConfig(config) {
|
|
93
|
+
// Build MRT config using factory methods
|
|
94
|
+
const mrtConfig = {
|
|
95
|
+
auth: config.hasMrtConfig() ? config.createMrtAuth() : undefined,
|
|
96
|
+
project: config.values.mrtProject,
|
|
97
|
+
environment: config.values.mrtEnvironment,
|
|
98
|
+
origin: config.values.mrtOrigin,
|
|
99
|
+
};
|
|
100
|
+
// Build B2C instance using factory method
|
|
101
|
+
const b2cInstance = config.hasB2CInstanceConfig() ? config.createB2CInstance() : undefined;
|
|
102
|
+
return new Services({
|
|
103
|
+
b2cInstance,
|
|
104
|
+
mrtConfig,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
// ============================================
|
|
108
|
+
// Internal OS Resource Access Methods
|
|
109
|
+
// These are for internal use by tools, not exposed to AI assistants
|
|
110
|
+
// ============================================
|
|
111
|
+
/**
|
|
112
|
+
* Check if a file or directory exists.
|
|
113
|
+
*
|
|
114
|
+
* @param targetPath - Path to check
|
|
115
|
+
* @returns True if exists, false otherwise
|
|
116
|
+
*/
|
|
117
|
+
exists(targetPath) {
|
|
118
|
+
return fs.existsSync(targetPath);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get the current working directory.
|
|
122
|
+
*/
|
|
123
|
+
getCwd() {
|
|
124
|
+
return process.cwd();
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get the user's home directory.
|
|
128
|
+
*/
|
|
129
|
+
getHomeDir() {
|
|
130
|
+
return os.homedir();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get OS platform information.
|
|
134
|
+
*/
|
|
135
|
+
getPlatform() {
|
|
136
|
+
return os.platform();
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get system temporary directory.
|
|
140
|
+
*/
|
|
141
|
+
getTmpDir() {
|
|
142
|
+
return os.tmpdir();
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Join path segments.
|
|
146
|
+
*
|
|
147
|
+
* @param segments - Path segments to join
|
|
148
|
+
* @returns Joined path
|
|
149
|
+
*/
|
|
150
|
+
joinPath(...segments) {
|
|
151
|
+
return path.join(...segments);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* List directory contents.
|
|
155
|
+
*
|
|
156
|
+
* @param dirPath - Directory path to list
|
|
157
|
+
* @returns Array of directory entries
|
|
158
|
+
*/
|
|
159
|
+
listDirectory(dirPath) {
|
|
160
|
+
return fs.readdirSync(dirPath, { withFileTypes: true });
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Read a file from the filesystem.
|
|
164
|
+
*
|
|
165
|
+
* @param filePath - Path to the file
|
|
166
|
+
* @param encoding - File encoding (default: utf8)
|
|
167
|
+
* @returns File contents as a string
|
|
168
|
+
*/
|
|
169
|
+
readFile(filePath, encoding = 'utf8') {
|
|
170
|
+
return fs.readFileSync(filePath, { encoding });
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Resolve a path relative to the current working directory.
|
|
174
|
+
*
|
|
175
|
+
* @param segments - Path segments to join and resolve
|
|
176
|
+
* @returns Absolute path
|
|
177
|
+
*/
|
|
178
|
+
resolvePath(...segments) {
|
|
179
|
+
return path.resolve(...segments);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get file or directory stats.
|
|
183
|
+
*
|
|
184
|
+
* @param targetPath - Path to get stats for
|
|
185
|
+
* @returns File stats object
|
|
186
|
+
*/
|
|
187
|
+
stat(targetPath) {
|
|
188
|
+
return fs.statSync(targetPath);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=services.js.map
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Adapter for wrapping b2c-tooling-sdk functions as MCP tools.
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities for creating standardized MCP tools that:
|
|
5
|
+
* - Validate input using Zod schemas
|
|
6
|
+
* - Inject pre-resolved B2CInstance for WebDAV/OCAPI operations (requiresInstance)
|
|
7
|
+
* - Inject pre-resolved MRT auth for MRT API operations (requiresMrtAuth)
|
|
8
|
+
* - Format output consistently (textResult, jsonResult, errorResult)
|
|
9
|
+
*
|
|
10
|
+
* ## Configuration Resolution
|
|
11
|
+
*
|
|
12
|
+
* Both B2C instance and MRT auth are resolved once at server startup via
|
|
13
|
+
* {@link Services.fromResolvedConfig} and reused for all tool calls:
|
|
14
|
+
*
|
|
15
|
+
* - **B2CInstance**: Resolved from flags + dw.json. Available when `requiresInstance: true`.
|
|
16
|
+
* - **MRT Auth**: Resolved from --api-key → SFCC_MRT_API_KEY → ~/.mobify. Available when `requiresMrtAuth: true`.
|
|
17
|
+
*
|
|
18
|
+
* This "resolve eagerly at startup" pattern provides:
|
|
19
|
+
* - Fail-fast behavior (configuration errors surface at startup)
|
|
20
|
+
* - Consistent mental model (both resolved the same way)
|
|
21
|
+
* - Better performance (no resolution on each tool call)
|
|
22
|
+
*
|
|
23
|
+
* @module tools/adapter
|
|
24
|
+
*
|
|
25
|
+
* @example B2C Instance tool (WebDAV/OCAPI)
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const myTool = createToolAdapter({
|
|
28
|
+
* name: 'my_tool',
|
|
29
|
+
* description: 'Does something useful',
|
|
30
|
+
* toolsets: ['CARTRIDGES'],
|
|
31
|
+
* requiresInstance: true,
|
|
32
|
+
* inputSchema: {
|
|
33
|
+
* cartridgeName: z.string().describe('Name of the cartridge'),
|
|
34
|
+
* },
|
|
35
|
+
* execute: async (args, { b2cInstance }) => {
|
|
36
|
+
* const result = await b2cInstance.webdav.get(`Cartridges/${args.cartridgeName}`);
|
|
37
|
+
* return result;
|
|
38
|
+
* },
|
|
39
|
+
* formatOutput: (output) => textResult(`Fetched: ${output}`),
|
|
40
|
+
* }, services);
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example MRT tool (MRT API)
|
|
44
|
+
* ```typescript
|
|
45
|
+
* // Services created from already-resolved config at startup
|
|
46
|
+
* const services = Services.fromResolvedConfig(this.resolvedConfig);
|
|
47
|
+
*
|
|
48
|
+
* const mrtTool = createToolAdapter({
|
|
49
|
+
* name: 'mrt_bundle_push',
|
|
50
|
+
* description: 'Push bundle to MRT',
|
|
51
|
+
* toolsets: ['MRT'],
|
|
52
|
+
* requiresMrtAuth: true,
|
|
53
|
+
* inputSchema: {
|
|
54
|
+
* projectSlug: z.string().describe('MRT project slug'),
|
|
55
|
+
* },
|
|
56
|
+
* execute: async (args, { mrtAuth }) => {
|
|
57
|
+
* const result = await pushBundle({ projectSlug: args.projectSlug }, mrtAuth);
|
|
58
|
+
* return result;
|
|
59
|
+
* },
|
|
60
|
+
* formatOutput: (output) => jsonResult(output),
|
|
61
|
+
* }, services);
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
import { type ZodRawShape } from 'zod';
|
|
65
|
+
import type { B2CInstance } from '@salesforce/b2c-tooling-sdk';
|
|
66
|
+
import type { McpTool, ToolResult, Toolset } from '../utils/index.js';
|
|
67
|
+
import type { Services, MrtConfig } from '../services.js';
|
|
68
|
+
/**
|
|
69
|
+
* Context provided to tool execute functions.
|
|
70
|
+
* Contains the B2CInstance and/or MRT config based on tool requirements.
|
|
71
|
+
*/
|
|
72
|
+
export interface ToolExecutionContext {
|
|
73
|
+
/**
|
|
74
|
+
* B2CInstance configured with authentication from dw.json and flags.
|
|
75
|
+
* Provides access to typed API clients (webdav, ocapi).
|
|
76
|
+
* Only available when requiresInstance is true.
|
|
77
|
+
*/
|
|
78
|
+
b2cInstance?: B2CInstance;
|
|
79
|
+
/**
|
|
80
|
+
* MRT configuration (auth, project, environment, origin).
|
|
81
|
+
* Pre-resolved at server startup.
|
|
82
|
+
* Only populated when requiresMrtAuth is true.
|
|
83
|
+
*/
|
|
84
|
+
mrtConfig?: MrtConfig;
|
|
85
|
+
/**
|
|
86
|
+
* Services instance for file system access and other utilities.
|
|
87
|
+
*/
|
|
88
|
+
services: Services;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Options for creating a tool adapter.
|
|
92
|
+
*
|
|
93
|
+
* @template TInput - The validated input type (inferred from inputSchema)
|
|
94
|
+
* @template TOutput - The output type from the execute function
|
|
95
|
+
*/
|
|
96
|
+
export interface ToolAdapterOptions<TInput, TOutput> {
|
|
97
|
+
/** Tool name (used in MCP protocol) */
|
|
98
|
+
name: string;
|
|
99
|
+
/** Human-readable description */
|
|
100
|
+
description: string;
|
|
101
|
+
/** Zod schema for input validation */
|
|
102
|
+
inputSchema: ZodRawShape;
|
|
103
|
+
/** Toolsets this tool belongs to */
|
|
104
|
+
toolsets: Toolset[];
|
|
105
|
+
/** Whether this tool is GA (generally available). Defaults to true. */
|
|
106
|
+
isGA?: boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Whether this tool requires a B2CInstance.
|
|
109
|
+
* Set to false for tools that don't need B2C instance connectivity (e.g., local scaffolding tools).
|
|
110
|
+
* Defaults to false.
|
|
111
|
+
*/
|
|
112
|
+
requiresInstance?: boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Whether this tool requires MRT API authentication.
|
|
115
|
+
* When true, creates an ApiKeyStrategy from SFCC_MRT_API_KEY environment variable.
|
|
116
|
+
* Defaults to false.
|
|
117
|
+
*/
|
|
118
|
+
requiresMrtAuth?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Execute function that performs the tool's operation.
|
|
121
|
+
* Receives validated input and a context with B2CInstance and/or auth based on requirements.
|
|
122
|
+
*/
|
|
123
|
+
execute: (args: TInput, context: ToolExecutionContext) => Promise<TOutput>;
|
|
124
|
+
/**
|
|
125
|
+
* Format function that converts the execute output to a ToolResult.
|
|
126
|
+
* Use textResult(), jsonResult(), or errorResult() helpers.
|
|
127
|
+
*/
|
|
128
|
+
formatOutput: (output: TOutput) => ToolResult;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Creates a text-only success result.
|
|
132
|
+
*
|
|
133
|
+
* @param text - The text content to return
|
|
134
|
+
* @returns A ToolResult with text content
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* return textResult('Operation completed successfully');
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export declare function textResult(text: string): ToolResult;
|
|
142
|
+
/**
|
|
143
|
+
* Creates an error result.
|
|
144
|
+
*
|
|
145
|
+
* @param message - The error message
|
|
146
|
+
* @returns A ToolResult marked as an error
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* return errorResult('Failed to connect to instance');
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
export declare function errorResult(message: string): ToolResult;
|
|
154
|
+
/**
|
|
155
|
+
* Creates a JSON result with formatted output.
|
|
156
|
+
*
|
|
157
|
+
* @param data - The data to serialize as JSON
|
|
158
|
+
* @param indent - Number of spaces for indentation (default: 2)
|
|
159
|
+
* @returns A ToolResult with JSON-formatted text content
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```typescript
|
|
163
|
+
* return jsonResult({ status: 'success', items: ['a', 'b', 'c'] });
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
export declare function jsonResult(data: unknown, indent?: number): ToolResult;
|
|
167
|
+
/**
|
|
168
|
+
* Creates an MCP tool from a b2c-tooling function.
|
|
169
|
+
*
|
|
170
|
+
* This adapter provides:
|
|
171
|
+
* - Input validation via Zod schemas
|
|
172
|
+
* - B2CInstance creation from dw.json with environment variable overrides
|
|
173
|
+
* - Consistent error handling
|
|
174
|
+
* - Output formatting utilities
|
|
175
|
+
*
|
|
176
|
+
* @template TInput - The validated input type (inferred from inputSchema)
|
|
177
|
+
* @template TOutput - The output type from the execute function
|
|
178
|
+
* @param options - Tool adapter configuration
|
|
179
|
+
* @param services - Services instance for dependency injection
|
|
180
|
+
* @returns An McpTool ready for registration
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* import { z } from 'zod';
|
|
185
|
+
* import { createToolAdapter, jsonResult, errorResult } from './adapter.js';
|
|
186
|
+
*
|
|
187
|
+
* const listCodeVersionsTool = createToolAdapter({
|
|
188
|
+
* name: 'code_version_list',
|
|
189
|
+
* description: 'List all code versions on the instance',
|
|
190
|
+
* toolsets: ['CARTRIDGES'],
|
|
191
|
+
* inputSchema: {},
|
|
192
|
+
* execute: async (_args, { instance }) => {
|
|
193
|
+
* const result = await instance.ocapi.GET('/code_versions', {});
|
|
194
|
+
* if (result.error) throw new Error(result.error.message);
|
|
195
|
+
* return result.data;
|
|
196
|
+
* },
|
|
197
|
+
* formatOutput: (data) => jsonResult(data),
|
|
198
|
+
* }, services);
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
export declare function createToolAdapter<TInput, TOutput>(options: ToolAdapterOptions<TInput, TOutput>, services: Services): McpTool;
|
|
@@ -0,0 +1,220 @@
|
|
|
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
|
+
/**
|
|
7
|
+
* Tool Adapter for wrapping b2c-tooling-sdk functions as MCP tools.
|
|
8
|
+
*
|
|
9
|
+
* This module provides utilities for creating standardized MCP tools that:
|
|
10
|
+
* - Validate input using Zod schemas
|
|
11
|
+
* - Inject pre-resolved B2CInstance for WebDAV/OCAPI operations (requiresInstance)
|
|
12
|
+
* - Inject pre-resolved MRT auth for MRT API operations (requiresMrtAuth)
|
|
13
|
+
* - Format output consistently (textResult, jsonResult, errorResult)
|
|
14
|
+
*
|
|
15
|
+
* ## Configuration Resolution
|
|
16
|
+
*
|
|
17
|
+
* Both B2C instance and MRT auth are resolved once at server startup via
|
|
18
|
+
* {@link Services.fromResolvedConfig} and reused for all tool calls:
|
|
19
|
+
*
|
|
20
|
+
* - **B2CInstance**: Resolved from flags + dw.json. Available when `requiresInstance: true`.
|
|
21
|
+
* - **MRT Auth**: Resolved from --api-key → SFCC_MRT_API_KEY → ~/.mobify. Available when `requiresMrtAuth: true`.
|
|
22
|
+
*
|
|
23
|
+
* This "resolve eagerly at startup" pattern provides:
|
|
24
|
+
* - Fail-fast behavior (configuration errors surface at startup)
|
|
25
|
+
* - Consistent mental model (both resolved the same way)
|
|
26
|
+
* - Better performance (no resolution on each tool call)
|
|
27
|
+
*
|
|
28
|
+
* @module tools/adapter
|
|
29
|
+
*
|
|
30
|
+
* @example B2C Instance tool (WebDAV/OCAPI)
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const myTool = createToolAdapter({
|
|
33
|
+
* name: 'my_tool',
|
|
34
|
+
* description: 'Does something useful',
|
|
35
|
+
* toolsets: ['CARTRIDGES'],
|
|
36
|
+
* requiresInstance: true,
|
|
37
|
+
* inputSchema: {
|
|
38
|
+
* cartridgeName: z.string().describe('Name of the cartridge'),
|
|
39
|
+
* },
|
|
40
|
+
* execute: async (args, { b2cInstance }) => {
|
|
41
|
+
* const result = await b2cInstance.webdav.get(`Cartridges/${args.cartridgeName}`);
|
|
42
|
+
* return result;
|
|
43
|
+
* },
|
|
44
|
+
* formatOutput: (output) => textResult(`Fetched: ${output}`),
|
|
45
|
+
* }, services);
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @example MRT tool (MRT API)
|
|
49
|
+
* ```typescript
|
|
50
|
+
* // Services created from already-resolved config at startup
|
|
51
|
+
* const services = Services.fromResolvedConfig(this.resolvedConfig);
|
|
52
|
+
*
|
|
53
|
+
* const mrtTool = createToolAdapter({
|
|
54
|
+
* name: 'mrt_bundle_push',
|
|
55
|
+
* description: 'Push bundle to MRT',
|
|
56
|
+
* toolsets: ['MRT'],
|
|
57
|
+
* requiresMrtAuth: true,
|
|
58
|
+
* inputSchema: {
|
|
59
|
+
* projectSlug: z.string().describe('MRT project slug'),
|
|
60
|
+
* },
|
|
61
|
+
* execute: async (args, { mrtAuth }) => {
|
|
62
|
+
* const result = await pushBundle({ projectSlug: args.projectSlug }, mrtAuth);
|
|
63
|
+
* return result;
|
|
64
|
+
* },
|
|
65
|
+
* formatOutput: (output) => jsonResult(output),
|
|
66
|
+
* }, services);
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
import { z } from 'zod';
|
|
70
|
+
/**
|
|
71
|
+
* Creates a text-only success result.
|
|
72
|
+
*
|
|
73
|
+
* @param text - The text content to return
|
|
74
|
+
* @returns A ToolResult with text content
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* return textResult('Operation completed successfully');
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export function textResult(text) {
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: 'text', text }],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Creates an error result.
|
|
88
|
+
*
|
|
89
|
+
* @param message - The error message
|
|
90
|
+
* @returns A ToolResult marked as an error
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* return errorResult('Failed to connect to instance');
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export function errorResult(message) {
|
|
98
|
+
return {
|
|
99
|
+
content: [{ type: 'text', text: message }],
|
|
100
|
+
isError: true,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Creates a JSON result with formatted output.
|
|
105
|
+
*
|
|
106
|
+
* @param data - The data to serialize as JSON
|
|
107
|
+
* @param indent - Number of spaces for indentation (default: 2)
|
|
108
|
+
* @returns A ToolResult with JSON-formatted text content
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* return jsonResult({ status: 'success', items: ['a', 'b', 'c'] });
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export function jsonResult(data, indent = 2) {
|
|
116
|
+
return {
|
|
117
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, indent) }],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Formats Zod validation errors into a human-readable string.
|
|
122
|
+
*
|
|
123
|
+
* @param error - The Zod error object
|
|
124
|
+
* @returns Formatted error message
|
|
125
|
+
*/
|
|
126
|
+
function formatZodErrors(error) {
|
|
127
|
+
return error.errors.map((e) => `${e.path.join('.') || 'input'}: ${e.message}`).join('; ');
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Creates an MCP tool from a b2c-tooling function.
|
|
131
|
+
*
|
|
132
|
+
* This adapter provides:
|
|
133
|
+
* - Input validation via Zod schemas
|
|
134
|
+
* - B2CInstance creation from dw.json with environment variable overrides
|
|
135
|
+
* - Consistent error handling
|
|
136
|
+
* - Output formatting utilities
|
|
137
|
+
*
|
|
138
|
+
* @template TInput - The validated input type (inferred from inputSchema)
|
|
139
|
+
* @template TOutput - The output type from the execute function
|
|
140
|
+
* @param options - Tool adapter configuration
|
|
141
|
+
* @param services - Services instance for dependency injection
|
|
142
|
+
* @returns An McpTool ready for registration
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* import { z } from 'zod';
|
|
147
|
+
* import { createToolAdapter, jsonResult, errorResult } from './adapter.js';
|
|
148
|
+
*
|
|
149
|
+
* const listCodeVersionsTool = createToolAdapter({
|
|
150
|
+
* name: 'code_version_list',
|
|
151
|
+
* description: 'List all code versions on the instance',
|
|
152
|
+
* toolsets: ['CARTRIDGES'],
|
|
153
|
+
* inputSchema: {},
|
|
154
|
+
* execute: async (_args, { instance }) => {
|
|
155
|
+
* const result = await instance.ocapi.GET('/code_versions', {});
|
|
156
|
+
* if (result.error) throw new Error(result.error.message);
|
|
157
|
+
* return result.data;
|
|
158
|
+
* },
|
|
159
|
+
* formatOutput: (data) => jsonResult(data),
|
|
160
|
+
* }, services);
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
export function createToolAdapter(options, services) {
|
|
164
|
+
const { name, description, inputSchema, toolsets, isGA = true, requiresInstance = false, requiresMrtAuth = false, execute, formatOutput, } = options;
|
|
165
|
+
// Create Zod schema from inputSchema definition
|
|
166
|
+
const zodSchema = z.object(inputSchema);
|
|
167
|
+
return {
|
|
168
|
+
name,
|
|
169
|
+
description,
|
|
170
|
+
inputSchema,
|
|
171
|
+
toolsets,
|
|
172
|
+
isGA,
|
|
173
|
+
async handler(rawArgs) {
|
|
174
|
+
// 1. Validate input with Zod
|
|
175
|
+
const parseResult = zodSchema.safeParse(rawArgs);
|
|
176
|
+
if (!parseResult.success) {
|
|
177
|
+
return errorResult(`Invalid input: ${formatZodErrors(parseResult.error)}`);
|
|
178
|
+
}
|
|
179
|
+
const args = parseResult.data;
|
|
180
|
+
try {
|
|
181
|
+
// 2. Get B2CInstance if required (pre-resolved at startup)
|
|
182
|
+
let b2cInstance;
|
|
183
|
+
if (requiresInstance) {
|
|
184
|
+
if (!services.b2cInstance) {
|
|
185
|
+
return errorResult('B2C instance error: Instance configuration required. Provide --server flag, set SFCC_SERVER environment variable, or configure dw.json');
|
|
186
|
+
}
|
|
187
|
+
b2cInstance = services.b2cInstance;
|
|
188
|
+
}
|
|
189
|
+
// 3. Get MRT config if required (pre-resolved at startup)
|
|
190
|
+
let mrtConfig;
|
|
191
|
+
if (requiresMrtAuth) {
|
|
192
|
+
if (!services.mrtConfig.auth) {
|
|
193
|
+
return errorResult('MRT auth error: MRT API key required. Provide --api-key, set SFCC_MRT_API_KEY environment variable, or configure ~/.mobify');
|
|
194
|
+
}
|
|
195
|
+
mrtConfig = {
|
|
196
|
+
auth: services.mrtConfig.auth,
|
|
197
|
+
project: services.mrtConfig.project,
|
|
198
|
+
environment: services.mrtConfig.environment,
|
|
199
|
+
origin: services.mrtConfig.origin,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
// 4. Execute the operation
|
|
203
|
+
const context = {
|
|
204
|
+
b2cInstance,
|
|
205
|
+
mrtConfig,
|
|
206
|
+
services,
|
|
207
|
+
};
|
|
208
|
+
const output = await execute(args, context);
|
|
209
|
+
// 5. Format output
|
|
210
|
+
return formatOutput(output);
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
// Handle execution errors
|
|
214
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
215
|
+
return errorResult(`Execution error: ${message}`);
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { McpTool } from '../../utils/index.js';
|
|
2
|
+
import type { Services } from '../../services.js';
|
|
3
|
+
import type { DeployResult, DeployOptions } from '@salesforce/b2c-tooling-sdk/operations/code';
|
|
4
|
+
import type { B2CInstance } from '@salesforce/b2c-tooling-sdk';
|
|
5
|
+
/**
|
|
6
|
+
* Optional dependency injections for testing.
|
|
7
|
+
*/
|
|
8
|
+
interface CartridgeToolInjections {
|
|
9
|
+
/** Mock findAndDeployCartridges function for testing */
|
|
10
|
+
findAndDeployCartridges?: (instance: B2CInstance, directory: string, options: DeployOptions) => Promise<DeployResult>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates all tools for the CARTRIDGES toolset.
|
|
14
|
+
*
|
|
15
|
+
* @param services - MCP services
|
|
16
|
+
* @param injections - Optional dependency injections for testing
|
|
17
|
+
* @returns Array of MCP tools
|
|
18
|
+
*/
|
|
19
|
+
export declare function createCartridgesTools(services: Services, injections?: CartridgeToolInjections): McpTool[];
|
|
20
|
+
export {};
|