@salesforce/b2c-dx-mcp 1.10.1 → 2.0.0
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/dist/commands/mcp.d.ts +13 -7
- package/dist/commands/mcp.js +52 -11
- package/dist/registry.d.ts +3 -2
- package/dist/server-context.d.ts +1 -1
- package/dist/server-context.js +1 -1
- package/dist/services.d.ts +9 -1
- package/dist/services.js +11 -1
- package/dist/tools/adapter.d.ts +8 -1
- package/dist/tools/adapter.js +10 -4
- package/dist/tools/cartridges/index.js +4 -1
- package/dist/tools/diagnostics/config-inspect.js +3 -2
- package/dist/tools/diagnostics/debug-list-sessions.js +0 -1
- package/dist/tools/diagnostics/debug-start-session.js +10 -8
- package/dist/tools/diagnostics/session-registry.js +2 -2
- package/dist/tools/mrt/index.js +9 -3
- package/dist/tools/project-context.d.ts +22 -0
- package/dist/tools/project-context.js +22 -0
- package/dist/tools/scapi/metrics-get.js +1 -0
- package/dist/tools/scapi/scapi-custom-api-generate-scaffold.d.ts +4 -1
- package/dist/tools/scapi/scapi-custom-api-generate-scaffold.js +16 -2
- package/dist/tools/scapi/scapi-custom-apis-get-status.js +1 -0
- package/dist/tools/storefrontnext/figma/figma-to-component/index.d.ts +3 -0
- package/dist/tools/storefrontnext/figma/figma-to-component/index.js +9 -3
- package/dist/tools/storefrontnext/figma/generate-component/index.d.ts +3 -0
- package/dist/tools/storefrontnext/figma/generate-component/index.js +4 -1
- package/dist/tools/storefrontnext/figma/map-tokens/index.d.ts +3 -0
- package/dist/tools/storefrontnext/figma/map-tokens/index.js +9 -2
- package/dist/tools/storefrontnext/page-designer-decorator/index.d.ts +8 -1
- package/dist/tools/storefrontnext/page-designer-decorator/index.js +7 -2
- package/dist/tools/storefrontnext/site-theming/index.js +6 -1
- package/dist/tools/storefrontnext/site-theming/theming-store.d.ts +2 -0
- package/dist/tools/storefrontnext/site-theming/theming-store.js +1 -1
- package/dist/tools/storefrontnext/site-theming/types.d.ts +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +2 -2
package/dist/commands/mcp.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BaseCommand } from '@salesforce/b2c-tooling-sdk/cli';
|
|
2
2
|
import type { ResolvedB2CConfig } from '@salesforce/b2c-tooling-sdk/config';
|
|
3
3
|
import { Services } from '../services.js';
|
|
4
|
+
import type { ProjectContextInput } from '../tools/project-context.js';
|
|
4
5
|
/**
|
|
5
6
|
* oclif Command that starts the B2C DX MCP server.
|
|
6
7
|
*
|
|
@@ -81,13 +82,16 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
|
|
|
81
82
|
* - extractInstanceFlags() - B2C instance flags (--server, --username, etc.)
|
|
82
83
|
* - extractMrtFlags() - MRT flags (--api-key, --project, etc.) and loading options
|
|
83
84
|
*
|
|
84
|
-
*
|
|
85
|
-
* 1.
|
|
86
|
-
* 2.
|
|
87
|
-
* 3.
|
|
88
|
-
* 4.
|
|
85
|
+
* Configuration file selection (highest to lowest):
|
|
86
|
+
* 1. Per-call configPath
|
|
87
|
+
* 2. Startup --config / SFCC_CONFIG
|
|
88
|
+
* 3. SFCC_CONFIG from the selected project's .env
|
|
89
|
+
* 4. dw.json in the selected project directory
|
|
90
|
+
*
|
|
91
|
+
* Values are then merged through the normal CLI resolver, including
|
|
92
|
+
* environment, plugin, dw.json, ~/.mobify, and package.json sources.
|
|
89
93
|
*/
|
|
90
|
-
protected loadConfiguration(): Promise<ResolvedB2CConfig>;
|
|
94
|
+
protected loadConfiguration(projectContext?: ProjectContextInput): Promise<ResolvedB2CConfig>;
|
|
91
95
|
/**
|
|
92
96
|
* Loads configuration and creates a new Services instance.
|
|
93
97
|
*
|
|
@@ -97,7 +101,7 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
|
|
|
97
101
|
*
|
|
98
102
|
* @returns A new Services instance with loaded configuration
|
|
99
103
|
*/
|
|
100
|
-
protected loadServices(): Promise<Services>;
|
|
104
|
+
protected loadServices(projectContext?: ProjectContextInput): Promise<Services>;
|
|
101
105
|
/**
|
|
102
106
|
* Main entry point - starts the MCP server.
|
|
103
107
|
*
|
|
@@ -125,4 +129,6 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
|
|
|
125
129
|
* These can be exposed to Services if needed for features like telemetry or caching.
|
|
126
130
|
*/
|
|
127
131
|
run(): Promise<void>;
|
|
132
|
+
/** Parse a project's .env without mutating the long-lived MCP process environment. */
|
|
133
|
+
private loadProjectEnvironment;
|
|
128
134
|
}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -132,8 +132,10 @@
|
|
|
132
132
|
* { "args": ["--toolsets", "all", "--allow-non-ga-tools", "--debug"] }
|
|
133
133
|
* ```
|
|
134
134
|
*/
|
|
135
|
+
import path from 'node:path';
|
|
135
136
|
import { Flags } from '@oclif/core';
|
|
136
137
|
import { BaseCommand, MrtCommand, InstanceCommand, loadConfig, extractInstanceFlags, extractMrtFlags, } from '@salesforce/b2c-tooling-sdk/cli';
|
|
138
|
+
import { EnvSource, readProjectEnvironment } from '@salesforce/b2c-tooling-sdk/config';
|
|
137
139
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
138
140
|
import { B2CDxMcpServer } from '../server.js';
|
|
139
141
|
import { Services } from '../services.js';
|
|
@@ -240,24 +242,47 @@ export default class McpServerCommand extends BaseCommand {
|
|
|
240
242
|
* - extractInstanceFlags() - B2C instance flags (--server, --username, etc.)
|
|
241
243
|
* - extractMrtFlags() - MRT flags (--api-key, --project, etc.) and loading options
|
|
242
244
|
*
|
|
243
|
-
*
|
|
244
|
-
* 1.
|
|
245
|
-
* 2.
|
|
246
|
-
* 3.
|
|
247
|
-
* 4.
|
|
245
|
+
* Configuration file selection (highest to lowest):
|
|
246
|
+
* 1. Per-call configPath
|
|
247
|
+
* 2. Startup --config / SFCC_CONFIG
|
|
248
|
+
* 3. SFCC_CONFIG from the selected project's .env
|
|
249
|
+
* 4. dw.json in the selected project directory
|
|
250
|
+
*
|
|
251
|
+
* Values are then merged through the normal CLI resolver, including
|
|
252
|
+
* environment, plugin, dw.json, ~/.mobify, and package.json sources.
|
|
248
253
|
*/
|
|
249
|
-
async loadConfiguration() {
|
|
254
|
+
async loadConfiguration(projectContext) {
|
|
250
255
|
const mrt = extractMrtFlags(this.flags);
|
|
256
|
+
const baseOptions = this.getBaseConfigOptions();
|
|
257
|
+
const effectiveProjectDirectory = projectContext?.projectDirectory ?? baseOptions.projectDirectory;
|
|
258
|
+
const projectEnvironment = this.loadProjectEnvironment(effectiveProjectDirectory);
|
|
259
|
+
const projectConfigPath = projectEnvironment?.SFCC_CONFIG;
|
|
260
|
+
const configPath = (projectContext?.configPath
|
|
261
|
+
? path.resolve(effectiveProjectDirectory ?? process.cwd(), projectContext.configPath)
|
|
262
|
+
: undefined) ??
|
|
263
|
+
baseOptions.configPath ??
|
|
264
|
+
(projectConfigPath && effectiveProjectDirectory
|
|
265
|
+
? path.isAbsolute(projectConfigPath)
|
|
266
|
+
? projectConfigPath
|
|
267
|
+
: path.resolve(effectiveProjectDirectory, projectConfigPath)
|
|
268
|
+
: undefined);
|
|
251
269
|
const options = {
|
|
252
|
-
...
|
|
270
|
+
...baseOptions,
|
|
253
271
|
...mrt.options,
|
|
272
|
+
configPath,
|
|
273
|
+
...(projectContext?.projectDirectory && {
|
|
274
|
+
projectDirectory: projectContext.projectDirectory,
|
|
275
|
+
workingDirectory: projectContext.projectDirectory,
|
|
276
|
+
}),
|
|
254
277
|
};
|
|
255
278
|
// Combine B2C instance flags and MRT config flags
|
|
256
279
|
const flagConfig = {
|
|
257
280
|
...extractInstanceFlags(this.flags),
|
|
258
281
|
...mrt.config,
|
|
259
282
|
};
|
|
260
|
-
return loadConfig(flagConfig, options
|
|
283
|
+
return loadConfig(flagConfig, options, {
|
|
284
|
+
before: projectEnvironment ? [new EnvSource(projectEnvironment)] : undefined,
|
|
285
|
+
});
|
|
261
286
|
}
|
|
262
287
|
/**
|
|
263
288
|
* Loads configuration and creates a new Services instance.
|
|
@@ -268,9 +293,11 @@ export default class McpServerCommand extends BaseCommand {
|
|
|
268
293
|
*
|
|
269
294
|
* @returns A new Services instance with loaded configuration
|
|
270
295
|
*/
|
|
271
|
-
async loadServices() {
|
|
272
|
-
const config = await this.loadConfiguration();
|
|
273
|
-
|
|
296
|
+
async loadServices(projectContext) {
|
|
297
|
+
const config = await this.loadConfiguration(projectContext);
|
|
298
|
+
const effectiveProjectDirectory = projectContext?.projectDirectory ?? this.flags?.['project-directory'];
|
|
299
|
+
const projectEnvironment = this.loadProjectEnvironment(effectiveProjectDirectory);
|
|
300
|
+
return Services.fromResolvedConfig(config, projectEnvironment);
|
|
274
301
|
}
|
|
275
302
|
/**
|
|
276
303
|
* Main entry point - starts the MCP server.
|
|
@@ -362,5 +389,19 @@ export default class McpServerCommand extends BaseCommand {
|
|
|
362
389
|
});
|
|
363
390
|
this.logger.info({ version: this.config.version }, 'MCP Server running on stdio');
|
|
364
391
|
}
|
|
392
|
+
/** Parse a project's .env without mutating the long-lived MCP process environment. */
|
|
393
|
+
loadProjectEnvironment(projectDirectory) {
|
|
394
|
+
if (!projectDirectory)
|
|
395
|
+
return undefined;
|
|
396
|
+
const envPath = path.join(projectDirectory, '.env');
|
|
397
|
+
try {
|
|
398
|
+
return readProjectEnvironment(projectDirectory);
|
|
399
|
+
}
|
|
400
|
+
catch (error) {
|
|
401
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
402
|
+
this.logger?.warn({ envPath, error: message }, '[Config] Failed to load project .env file');
|
|
403
|
+
}
|
|
404
|
+
return undefined;
|
|
405
|
+
}
|
|
365
406
|
}
|
|
366
407
|
//# sourceMappingURL=mcp.js.map
|
package/dist/registry.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { McpTool, Toolset, StartupFlags } from './utils/index.js';
|
|
|
4
4
|
import type { B2CDxMcpServer } from './server.js';
|
|
5
5
|
import type { Services } from './services.js';
|
|
6
6
|
import type { ServerContext } from './server-context.js';
|
|
7
|
+
import type { ProjectContextInput } from './tools/project-context.js';
|
|
7
8
|
/**
|
|
8
9
|
* Registry of tools organized by toolset.
|
|
9
10
|
* Tools can belong to multiple toolsets via their `toolsets` array.
|
|
@@ -17,5 +18,5 @@ export type ToolRegistry = Record<Toolset, McpTool[]>;
|
|
|
17
18
|
* @param loadServices - Function that loads configuration and returns Services instance
|
|
18
19
|
* @returns Complete tool registry
|
|
19
20
|
*/
|
|
20
|
-
export declare function createToolRegistry(loadServices: () => Promise<Services> | Services, serverContext?: ServerContext, detectedWorkspaces?: readonly ProjectType[], enabledDocCategories?: readonly DocCategory[]): ToolRegistry;
|
|
21
|
-
export declare function registerToolsets(flags: StartupFlags, server: B2CDxMcpServer, loadServices: () => Promise<Services> | Services, serverContext?: ServerContext): Promise<void>;
|
|
21
|
+
export declare function createToolRegistry(loadServices: (projectContext?: ProjectContextInput) => Promise<Services> | Services, serverContext?: ServerContext, detectedWorkspaces?: readonly ProjectType[], enabledDocCategories?: readonly DocCategory[]): ToolRegistry;
|
|
22
|
+
export declare function registerToolsets(flags: StartupFlags, server: B2CDxMcpServer, loadServices: (projectContext?: ProjectContextInput) => Promise<Services> | Services, serverContext?: ServerContext): Promise<void>;
|
package/dist/server-context.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { DebugSessionRegistry } from './tools/diagnostics/session-registry.js';
|
|
|
18
18
|
* client would also share the same context. Tools that mutate registries
|
|
19
19
|
* (like the debug tools) should not assume single-tenant access.
|
|
20
20
|
*
|
|
21
|
-
* The registries dedup on
|
|
21
|
+
* The registries dedup on an internal stable key (host plus MCP-owned debugger client ID, hostname for
|
|
22
22
|
* SFCC log watches, project/environment/origin for MRT log watches), so
|
|
23
23
|
* multi-agent use is functional but agents may see each other's
|
|
24
24
|
* sessions/watches via list tools.
|
package/dist/server-context.js
CHANGED
|
@@ -23,7 +23,7 @@ import { DebugSessionRegistry } from './tools/diagnostics/session-registry.js';
|
|
|
23
23
|
* client would also share the same context. Tools that mutate registries
|
|
24
24
|
* (like the debug tools) should not assume single-tenant access.
|
|
25
25
|
*
|
|
26
|
-
* The registries dedup on
|
|
26
|
+
* The registries dedup on an internal stable key (host plus MCP-owned debugger client ID, hostname for
|
|
27
27
|
* SFCC log watches, project/environment/origin for MRT log watches), so
|
|
28
28
|
* multi-agent use is functional but agents may see each other's
|
|
29
29
|
* sessions/watches via list tools.
|
package/dist/services.d.ts
CHANGED
|
@@ -65,6 +65,8 @@ export interface ServicesOptions {
|
|
|
65
65
|
mrtConfig?: MrtConfig;
|
|
66
66
|
/** Resolved configuration for access to SCAPI settings */
|
|
67
67
|
resolvedConfig: ResolvedB2CConfig;
|
|
68
|
+
/** Project-scoped environment parsed from the effective project's .env file. */
|
|
69
|
+
projectEnvironment?: Readonly<Record<string, string | undefined>>;
|
|
68
70
|
}
|
|
69
71
|
/**
|
|
70
72
|
* Services class that provides utilities for MCP tools.
|
|
@@ -100,6 +102,7 @@ export declare class Services {
|
|
|
100
102
|
* Provides access to shortCode, tenantId, and OAuth credentials.
|
|
101
103
|
* @private
|
|
102
104
|
*/
|
|
105
|
+
private readonly projectEnvironment;
|
|
103
106
|
private readonly resolvedConfig;
|
|
104
107
|
constructor(opts: ServicesOptions);
|
|
105
108
|
/**
|
|
@@ -114,7 +117,7 @@ export declare class Services {
|
|
|
114
117
|
* const services = Services.fromResolvedConfig(this.resolvedConfig);
|
|
115
118
|
* ```
|
|
116
119
|
*/
|
|
117
|
-
static fromResolvedConfig(config: ResolvedB2CConfig): Services;
|
|
120
|
+
static fromResolvedConfig(config: ResolvedB2CConfig, projectEnvironment?: Readonly<Record<string, string | undefined>>): Services;
|
|
118
121
|
/**
|
|
119
122
|
* Check if a file or directory exists.
|
|
120
123
|
*
|
|
@@ -143,6 +146,11 @@ export declare class Services {
|
|
|
143
146
|
* Get the current working directory.
|
|
144
147
|
*/
|
|
145
148
|
getCwd(): string;
|
|
149
|
+
/**
|
|
150
|
+
* Read an environment variable with the ambient process environment taking
|
|
151
|
+
* precedence over the project-scoped .env value.
|
|
152
|
+
*/
|
|
153
|
+
getEnvironmentVariable(name: string): string | undefined;
|
|
146
154
|
/**
|
|
147
155
|
* Get the user's home directory.
|
|
148
156
|
*/
|
package/dist/services.js
CHANGED
|
@@ -79,11 +79,13 @@ export class Services {
|
|
|
79
79
|
* Provides access to shortCode, tenantId, and OAuth credentials.
|
|
80
80
|
* @private
|
|
81
81
|
*/
|
|
82
|
+
projectEnvironment;
|
|
82
83
|
resolvedConfig;
|
|
83
84
|
constructor(opts) {
|
|
84
85
|
this.b2cInstance = opts.b2cInstance;
|
|
85
86
|
this.mrtConfig = opts.mrtConfig ?? {};
|
|
86
87
|
this.resolvedConfig = opts.resolvedConfig;
|
|
88
|
+
this.projectEnvironment = opts.projectEnvironment ?? {};
|
|
87
89
|
}
|
|
88
90
|
/**
|
|
89
91
|
* Creates a Services instance from an already-resolved configuration.
|
|
@@ -97,7 +99,7 @@ export class Services {
|
|
|
97
99
|
* const services = Services.fromResolvedConfig(this.resolvedConfig);
|
|
98
100
|
* ```
|
|
99
101
|
*/
|
|
100
|
-
static fromResolvedConfig(config) {
|
|
102
|
+
static fromResolvedConfig(config, projectEnvironment) {
|
|
101
103
|
// Build MRT config using factory methods
|
|
102
104
|
const mrtConfig = {
|
|
103
105
|
auth: config.hasMrtConfig() ? config.createMrtAuth() : undefined,
|
|
@@ -111,6 +113,7 @@ export class Services {
|
|
|
111
113
|
b2cInstance,
|
|
112
114
|
mrtConfig,
|
|
113
115
|
resolvedConfig: config,
|
|
116
|
+
projectEnvironment,
|
|
114
117
|
});
|
|
115
118
|
}
|
|
116
119
|
// ============================================
|
|
@@ -161,6 +164,13 @@ export class Services {
|
|
|
161
164
|
getCwd() {
|
|
162
165
|
return process.cwd();
|
|
163
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Read an environment variable with the ambient process environment taking
|
|
169
|
+
* precedence over the project-scoped .env value.
|
|
170
|
+
*/
|
|
171
|
+
getEnvironmentVariable(name) {
|
|
172
|
+
return process.env[name] ?? this.projectEnvironment[name];
|
|
173
|
+
}
|
|
164
174
|
/**
|
|
165
175
|
* Get the user's home directory.
|
|
166
176
|
*/
|
package/dist/tools/adapter.d.ts
CHANGED
|
@@ -69,6 +69,7 @@ import type { B2CInstance } from '@salesforce/b2c-tooling-sdk';
|
|
|
69
69
|
import type { McpTool, ToolResult, Toolset } from '../utils/index.js';
|
|
70
70
|
import type { Services, MrtConfig } from '../services.js';
|
|
71
71
|
import type { ServerContext } from '../server-context.js';
|
|
72
|
+
import { type ProjectContextInput } from './project-context.js';
|
|
72
73
|
/**
|
|
73
74
|
* Context provided to tool execute functions.
|
|
74
75
|
* Contains the B2CInstance and/or MRT config based on tool requirements.
|
|
@@ -125,6 +126,12 @@ export interface ToolAdapterOptions<TInput, TOutput> {
|
|
|
125
126
|
* Defaults to false.
|
|
126
127
|
*/
|
|
127
128
|
requiresMrtAuth?: boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Whether this tool resolves configuration or files relative to a project.
|
|
131
|
+
* Project-aware tools automatically expose a per-call `projectDirectory`
|
|
132
|
+
* input and use it while loading Services.
|
|
133
|
+
*/
|
|
134
|
+
usesProjectContext?: boolean;
|
|
128
135
|
/**
|
|
129
136
|
* Execute function that performs the tool's operation.
|
|
130
137
|
* Receives validated input and a context with B2CInstance and/or auth based on requirements.
|
|
@@ -212,4 +219,4 @@ export declare function jsonResult(data: unknown, indent?: number): ToolResult;
|
|
|
212
219
|
* }, loadServices);
|
|
213
220
|
* ```
|
|
214
221
|
*/
|
|
215
|
-
export declare function createToolAdapter<TInput, TOutput>(options: ToolAdapterOptions<TInput, TOutput>, loadServices: () => Promise<Services> | Services, serverContext?: ServerContext): McpTool;
|
|
222
|
+
export declare function createToolAdapter<TInput, TOutput>(options: ToolAdapterOptions<TInput, TOutput>, loadServices: (projectContext?: ProjectContextInput) => Promise<Services> | Services, serverContext?: ServerContext): McpTool;
|
package/dist/tools/adapter.js
CHANGED
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
* ```
|
|
71
71
|
*/
|
|
72
72
|
import { z } from 'zod';
|
|
73
|
+
import { projectContextInputSchema } from './project-context.js';
|
|
73
74
|
/**
|
|
74
75
|
* Creates a text-only success result.
|
|
75
76
|
*
|
|
@@ -169,13 +170,17 @@ function formatZodErrors(error) {
|
|
|
169
170
|
* ```
|
|
170
171
|
*/
|
|
171
172
|
export function createToolAdapter(options, loadServices, serverContext) {
|
|
172
|
-
const { name, description, inputSchema, toolsets, isGA = true, requiresInstance = false, requiresMrtAuth = false, execute, formatOutput, } = options;
|
|
173
|
+
const { name, description, inputSchema, toolsets, isGA = true, requiresInstance = false, requiresMrtAuth = false, usesProjectContext = false, execute, formatOutput, } = options;
|
|
174
|
+
const effectiveUsesProjectContext = usesProjectContext || requiresInstance || requiresMrtAuth;
|
|
175
|
+
const effectiveInputSchema = effectiveUsesProjectContext
|
|
176
|
+
? { ...projectContextInputSchema, ...inputSchema }
|
|
177
|
+
: inputSchema;
|
|
173
178
|
// Create Zod schema from inputSchema definition
|
|
174
|
-
const zodSchema = z.object(
|
|
179
|
+
const zodSchema = z.object(effectiveInputSchema);
|
|
175
180
|
return {
|
|
176
181
|
name,
|
|
177
182
|
description,
|
|
178
|
-
inputSchema,
|
|
183
|
+
inputSchema: effectiveInputSchema,
|
|
179
184
|
toolsets,
|
|
180
185
|
isGA,
|
|
181
186
|
async handler(rawArgs) {
|
|
@@ -187,7 +192,8 @@ export function createToolAdapter(options, loadServices, serverContext) {
|
|
|
187
192
|
const args = parseResult.data;
|
|
188
193
|
try {
|
|
189
194
|
// 2. Load Services to get fresh configuration (re-reads config files)
|
|
190
|
-
const
|
|
195
|
+
const projectContext = effectiveUsesProjectContext ? args : undefined;
|
|
196
|
+
const services = await loadServices(projectContext);
|
|
191
197
|
// 3. Get B2CInstance if required (loaded on each call)
|
|
192
198
|
let b2cInstance;
|
|
193
199
|
if (requiresInstance) {
|
|
@@ -44,6 +44,7 @@ function createCartridgeDeployTool(loadServices, injections) {
|
|
|
44
44
|
toolsets: ['CARTRIDGES'],
|
|
45
45
|
isGA: true,
|
|
46
46
|
requiresInstance: true,
|
|
47
|
+
usesProjectContext: true,
|
|
47
48
|
inputSchema: {
|
|
48
49
|
directory: z
|
|
49
50
|
.string()
|
|
@@ -87,7 +88,8 @@ function createCartridgeDeployTool(loadServices, injections) {
|
|
|
87
88
|
instance.config.codeVersion = codeVersion;
|
|
88
89
|
}
|
|
89
90
|
// Resolve directory path: relative paths are resolved relative to project directory, absolute paths are used as-is
|
|
90
|
-
const
|
|
91
|
+
const projectDirectory = context.services.resolveProjectDirectory(args.projectDirectory);
|
|
92
|
+
const directory = context.services.resolveWithProjectDirectory(args.directory, args.projectDirectory);
|
|
91
93
|
// Parse options
|
|
92
94
|
const options = {
|
|
93
95
|
include: args.cartridges,
|
|
@@ -106,6 +108,7 @@ function createCartridgeDeployTool(loadServices, injections) {
|
|
|
106
108
|
const result = await findAndDeployCartridgesFn(instance, directory, options);
|
|
107
109
|
return {
|
|
108
110
|
...result,
|
|
111
|
+
projectDirectory,
|
|
109
112
|
resolvedDirectory: directory,
|
|
110
113
|
postInstructions: CARTRIDGE_PATH_REMINDER,
|
|
111
114
|
};
|
|
@@ -20,11 +20,12 @@ export function createConfigInspectTool(loadServices) {
|
|
|
20
20
|
name: 'config_inspect',
|
|
21
21
|
description: 'Inspect the resolved B2C Commerce configuration the MCP server is using — instance hostname, auth, SCAPI, MRT, and other settings — along with which source (dw.json, environment variables, flags) provided each value. ' +
|
|
22
22
|
'Secrets (passwords, client secrets, API keys) are redacted by default. ' +
|
|
23
|
-
'
|
|
23
|
+
'Pass projectDirectory and/or configPath to inspect the same project and dw.json-format file a CLI command would use. The output includes the effective projectDirectory and source provenance, which is useful for diagnosing why the server targets the wrong instance or cannot find a project. ' +
|
|
24
24
|
'Use this first when configuration seems wrong, auth is failing, or the server appears to be operating in the wrong directory.',
|
|
25
25
|
toolsets: ['DIAGNOSTICS'],
|
|
26
26
|
isGA: true,
|
|
27
27
|
requiresInstance: false,
|
|
28
|
+
usesProjectContext: true,
|
|
28
29
|
inputSchema: {
|
|
29
30
|
unmask: z
|
|
30
31
|
.boolean()
|
|
@@ -33,7 +34,7 @@ export function createConfigInspectTool(loadServices) {
|
|
|
33
34
|
},
|
|
34
35
|
async execute(args, { services }) {
|
|
35
36
|
const resolved = services.getResolvedConfig();
|
|
36
|
-
const projectDirectory = services.resolveProjectDirectory();
|
|
37
|
+
const projectDirectory = services.resolveProjectDirectory(args.projectDirectory);
|
|
37
38
|
return {
|
|
38
39
|
config: redactConfigValues(resolved.values, { unmask: args.unmask ?? false }),
|
|
39
40
|
projectDirectory,
|
|
@@ -22,7 +22,6 @@ export function createDebugListSessionsTool(loadServices, serverContext) {
|
|
|
22
22
|
return {
|
|
23
23
|
session_id: entry.sessionId,
|
|
24
24
|
hostname: entry.hostname,
|
|
25
|
-
client_id: entry.clientId,
|
|
26
25
|
halted_threads: entry.manager
|
|
27
26
|
.getKnownThreads()
|
|
28
27
|
.filter((t) => t.status === 'halted')
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2
|
|
4
4
|
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
|
|
5
5
|
*/
|
|
6
|
+
import { randomUUID } from 'node:crypto';
|
|
6
7
|
import { z } from 'zod';
|
|
7
8
|
import { createToolAdapter, jsonResult } from '../adapter.js';
|
|
8
9
|
import { DebugSessionManager, createSourceMapper, } from '@salesforce/b2c-tooling-sdk/operations/debug';
|
|
@@ -12,19 +13,17 @@ export function createDebugStartSessionTool(loadServices, serverContext) {
|
|
|
12
13
|
return createToolAdapter({
|
|
13
14
|
name: 'debug_start_session',
|
|
14
15
|
description: 'Start a script debugger session on a B2C Commerce instance to debug SFRA controllers, custom API scripts, hooks, jobs, or any server-side script. ' +
|
|
16
|
+
'Uses projectDirectory to load project configuration and discover cartridges. cartridgeDirectory may override only the cartridge discovery/source-mapping root. ' +
|
|
15
17
|
'Returns a session_id for use with other debug tools, plus discovered cartridge mappings. ' +
|
|
16
18
|
'WARNING: Debug sessions halt remote request threads on the instance. Always call debug_end_session when finished.',
|
|
17
19
|
toolsets: ['CARTRIDGES', 'DIAGNOSTICS', 'SCAPI'],
|
|
18
20
|
inputSchema: {
|
|
19
|
-
|
|
21
|
+
cartridgeDirectory: z
|
|
20
22
|
.string()
|
|
21
23
|
.optional()
|
|
22
|
-
.describe('
|
|
23
|
-
client_id: z
|
|
24
|
-
.string()
|
|
25
|
-
.optional()
|
|
26
|
-
.describe('Client ID for the debugger API. Defaults to "b2c-cli". Use a different ID to run concurrent sessions on the same host.'),
|
|
24
|
+
.describe('Optional cartridge discovery and debugger source-mapping root. Relative paths resolve from projectDirectory. Defaults to projectDirectory.'),
|
|
27
25
|
},
|
|
26
|
+
usesProjectContext: true,
|
|
28
27
|
async execute(args, context) {
|
|
29
28
|
const registry = getRegistry(context);
|
|
30
29
|
const credentials = context.services.getBasicAuthCredentials();
|
|
@@ -33,8 +32,9 @@ export function createDebugStartSessionTool(loadServices, serverContext) {
|
|
|
33
32
|
'Set via SFCC_SERVER/SFCC_USERNAME/SFCC_PASSWORD env vars, or dw.json.');
|
|
34
33
|
}
|
|
35
34
|
const { hostname, username, password } = credentials;
|
|
36
|
-
const clientId =
|
|
37
|
-
const
|
|
35
|
+
const clientId = `b2c-dx-mcp-${randomUUID()}`;
|
|
36
|
+
const projectDirectory = context.services.resolveProjectDirectory(args.projectDirectory);
|
|
37
|
+
const cartridgeDir = context.services.resolveWithProjectDirectory(args.cartridgeDirectory, args.projectDirectory);
|
|
38
38
|
const cartridges = findCartridges(cartridgeDir);
|
|
39
39
|
const warnings = [];
|
|
40
40
|
if (cartridges.length === 0) {
|
|
@@ -70,6 +70,8 @@ export function createDebugStartSessionTool(loadServices, serverContext) {
|
|
|
70
70
|
cartridge_mappings: cartridgeMappings,
|
|
71
71
|
session_cookie: dwsid ? { name: 'dwsid', value: dwsid } : null,
|
|
72
72
|
warnings,
|
|
73
|
+
projectDirectory,
|
|
74
|
+
cartridgeDirectory: cartridgeDir,
|
|
73
75
|
};
|
|
74
76
|
},
|
|
75
77
|
formatOutput: (output) => jsonResult(output),
|
|
@@ -67,9 +67,9 @@ export class DebugSessionRegistry {
|
|
|
67
67
|
const { hostname, clientId, manager, sourceMapper, cartridges } = opts;
|
|
68
68
|
const existing = this.findByHostAndClientId(hostname, clientId);
|
|
69
69
|
if (existing) {
|
|
70
|
-
throw new Error(`A debug session already exists for ${hostname}
|
|
70
|
+
throw new Error(`A debug session already exists for ${hostname} ` +
|
|
71
71
|
`(session_id: "${existing.sessionId}"). ` +
|
|
72
|
-
`End it with debug_end_session first
|
|
72
|
+
`End it with debug_end_session first.`);
|
|
73
73
|
}
|
|
74
74
|
const sessionId = randomUUID();
|
|
75
75
|
const now = Date.now();
|
package/dist/tools/mrt/index.js
CHANGED
|
@@ -127,6 +127,7 @@ function createMrtBundlePushTool(loadServices, injections) {
|
|
|
127
127
|
isGA: true,
|
|
128
128
|
// MRT operations use ApiKeyStrategy from MRT_API_KEY or ~/.mobify
|
|
129
129
|
requiresMrtAuth: true,
|
|
130
|
+
usesProjectContext: true,
|
|
130
131
|
inputSchema: {
|
|
131
132
|
buildDirectory: z
|
|
132
133
|
.string()
|
|
@@ -167,12 +168,13 @@ function createMrtBundlePushTool(loadServices, injections) {
|
|
|
167
168
|
// Get origin from --cloud-origin flag or mrtOrigin config (optional)
|
|
168
169
|
const origin = context.mrtConfig?.origin;
|
|
169
170
|
// Detect project type and get project-type-aware defaults
|
|
170
|
-
const
|
|
171
|
+
const projectDirectory = context.services.resolveProjectDirectory(args.projectDirectory);
|
|
172
|
+
const projectDir = projectDirectory.path;
|
|
171
173
|
const { projectTypes } = await detectWorkspaceTypeFn(projectDir);
|
|
172
174
|
const defaults = getDefaultsForProjectTypes(projectTypes);
|
|
173
175
|
const ssrOnly = args.ssrOnly ? parseGlobPatterns(args.ssrOnly) : defaults.ssrOnly;
|
|
174
176
|
const ssrShared = args.ssrShared ? parseGlobPatterns(args.ssrShared) : defaults.ssrShared;
|
|
175
|
-
const buildDirectory = context.services.resolveWithProjectDirectory(args.buildDirectory ?? defaults.buildDirectory);
|
|
177
|
+
const buildDirectory = context.services.resolveWithProjectDirectory(args.buildDirectory ?? defaults.buildDirectory, args.projectDirectory);
|
|
176
178
|
// Log all computed variables before pushing bundle
|
|
177
179
|
const logger = getLogger();
|
|
178
180
|
logger.debug({
|
|
@@ -196,7 +198,11 @@ function createMrtBundlePushTool(loadServices, injections) {
|
|
|
196
198
|
target: environment,
|
|
197
199
|
origin, // MRT API origin URL (optional, defaults to https://cloud.mobify.com)
|
|
198
200
|
}, context.mrtConfig.auth);
|
|
199
|
-
return
|
|
201
|
+
return {
|
|
202
|
+
...result,
|
|
203
|
+
projectDirectory,
|
|
204
|
+
resolvedBuildDirectory: buildDirectory,
|
|
205
|
+
};
|
|
200
206
|
},
|
|
201
207
|
formatOutput: (output) => jsonResult(output),
|
|
202
208
|
}, loadServices);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Input shared by MCP tools that resolve files or configuration from a project. */
|
|
3
|
+
export interface ProjectContextInput {
|
|
4
|
+
/** Per-call project directory override. */
|
|
5
|
+
projectDirectory?: string;
|
|
6
|
+
/** Per-call explicit dw.json-format configuration path. */
|
|
7
|
+
configPath?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Effective project directory and the source that selected it. */
|
|
10
|
+
export interface ProjectDirectoryInfo {
|
|
11
|
+
path: string;
|
|
12
|
+
source: 'argument' | 'config' | 'cwd';
|
|
13
|
+
}
|
|
14
|
+
/** Shared schema field injected into every project-aware MCP tool. */
|
|
15
|
+
export declare const projectDirectoryInput: z.ZodOptional<z.ZodString>;
|
|
16
|
+
/** Shared explicit dw.json path field injected into every project-aware MCP tool. */
|
|
17
|
+
export declare const configPathInput: z.ZodOptional<z.ZodString>;
|
|
18
|
+
/** Shared schema fields injected into every project-aware MCP tool. */
|
|
19
|
+
export declare const projectContextInputSchema: {
|
|
20
|
+
projectDirectory: z.ZodOptional<z.ZodString>;
|
|
21
|
+
configPath: z.ZodOptional<z.ZodString>;
|
|
22
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
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 { z } from 'zod';
|
|
7
|
+
/** Shared schema field injected into every project-aware MCP tool. */
|
|
8
|
+
export const projectDirectoryInput = z
|
|
9
|
+
.string()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe('Absolute project directory for this call. Overrides --project-directory / SFCC_PROJECT_DIRECTORY and the MCP process working directory. Also controls project-local configuration discovery.');
|
|
12
|
+
/** Shared explicit dw.json path field injected into every project-aware MCP tool. */
|
|
13
|
+
export const configPathInput = z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe('Explicit path to a dw.json-format configuration file for this call. Overrides startup --config / SFCC_CONFIG and project .env SFCC_CONFIG. Relative paths resolve from projectDirectory.');
|
|
17
|
+
/** Shared schema fields injected into every project-aware MCP tool. */
|
|
18
|
+
export const projectContextInputSchema = {
|
|
19
|
+
projectDirectory: projectDirectoryInput,
|
|
20
|
+
configPath: configPathInput,
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=project-context.js.map
|
|
@@ -63,6 +63,7 @@ Retrieve observability metrics time-series for a B2C Commerce tenant. Returns me
|
|
|
63
63
|
toolsets: ['SCAPI'],
|
|
64
64
|
isGA: false,
|
|
65
65
|
requiresInstance: false, // SCAPI uses OAuth directly
|
|
66
|
+
usesProjectContext: true,
|
|
66
67
|
inputSchema: {
|
|
67
68
|
category: z
|
|
68
69
|
.enum(['overall', 'sales', 'ecdn', 'third-party', 'scapi', 'scapi-hooks', 'mrt', 'controller', 'ocapi'])
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Services } from '../../services.js';
|
|
2
2
|
import type { McpTool } from '../../utils/index.js';
|
|
3
|
+
import type { ProjectContextInput, ProjectDirectoryInfo } from '../project-context.js';
|
|
3
4
|
import type { Scaffold, ResolvedParameters, ResolveParametersOptions } from '@salesforce/b2c-tooling-sdk/scaffold';
|
|
4
5
|
/** Optional overrides for testing (scaffold not found, missing required). */
|
|
5
6
|
export interface ScaffoldCustomApiExecuteOverrides {
|
|
@@ -12,7 +13,7 @@ export interface ScaffoldCustomApiExecuteOverrides {
|
|
|
12
13
|
* Input schema for scapi_custom_api_generate_scaffold tool.
|
|
13
14
|
* Parameters match the custom-api scaffold: apiName, apiType, cartridgeName, etc.
|
|
14
15
|
*/
|
|
15
|
-
interface ScaffoldCustomApiInput {
|
|
16
|
+
interface ScaffoldCustomApiInput extends ProjectContextInput {
|
|
16
17
|
/** API name (kebab-case, e.g. my-products). Required. */
|
|
17
18
|
apiName: string;
|
|
18
19
|
/** Cartridge name that will contain the API. Optional; defaults to first cartridge found in project. */
|
|
@@ -40,6 +41,8 @@ interface ScaffoldCustomApiOutput {
|
|
|
40
41
|
}>;
|
|
41
42
|
postInstructions?: string;
|
|
42
43
|
error?: string;
|
|
44
|
+
projectDirectory: ProjectDirectoryInfo;
|
|
45
|
+
projectRoot: string;
|
|
43
46
|
}
|
|
44
47
|
/**
|
|
45
48
|
* Core execute logic for the custom API scaffold tool.
|
|
@@ -21,7 +21,8 @@ const CUSTOM_API_SCAFFOLD_ID = 'custom-api';
|
|
|
21
21
|
* Exported for tests so we can inject getScaffold / resolveScaffoldParameters and cover error branches.
|
|
22
22
|
*/
|
|
23
23
|
export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
24
|
-
const
|
|
24
|
+
const projectDirectory = services.resolveProjectDirectory(args.projectDirectory);
|
|
25
|
+
const projectRoot = services.resolveWithProjectDirectory(args.projectRoot, args.projectDirectory);
|
|
25
26
|
const getScaffold = overrides?.getScaffold ??
|
|
26
27
|
(async (id, opts) => {
|
|
27
28
|
const registry = createScaffoldRegistry();
|
|
@@ -34,6 +35,8 @@ export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
|
34
35
|
outputDir: projectRoot,
|
|
35
36
|
dryRun: false,
|
|
36
37
|
files: [],
|
|
38
|
+
projectDirectory,
|
|
39
|
+
projectRoot,
|
|
37
40
|
error: `Scaffold not found: ${CUSTOM_API_SCAFFOLD_ID}. Ensure @salesforce/b2c-tooling-sdk is installed.`,
|
|
38
41
|
};
|
|
39
42
|
}
|
|
@@ -44,6 +47,8 @@ export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
|
44
47
|
outputDir: projectRoot,
|
|
45
48
|
dryRun: false,
|
|
46
49
|
files: [],
|
|
50
|
+
projectDirectory,
|
|
51
|
+
projectRoot,
|
|
47
52
|
error: 'No cartridges found in project. Custom API scaffold requires an existing cartridge. Create a cartridge first: use `b2c scaffold cartridge --name app_custom`, or manually create a directory with a `.project` file (e.g., cartridges/app_custom/.project).',
|
|
48
53
|
};
|
|
49
54
|
}
|
|
@@ -73,6 +78,8 @@ export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
|
73
78
|
outputDir: projectRoot,
|
|
74
79
|
dryRun: false,
|
|
75
80
|
files: [],
|
|
81
|
+
projectDirectory,
|
|
82
|
+
projectRoot,
|
|
76
83
|
error: `Parameter validation failed: ${message}`,
|
|
77
84
|
};
|
|
78
85
|
}
|
|
@@ -83,6 +90,8 @@ export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
|
83
90
|
outputDir: projectRoot,
|
|
84
91
|
dryRun: false,
|
|
85
92
|
files: [],
|
|
93
|
+
projectDirectory,
|
|
94
|
+
projectRoot,
|
|
86
95
|
error: `Missing required parameter: ${missingRequired[0].name}. For cartridgeName, ensure the cartridge exists in the project (under projectRoot).`,
|
|
87
96
|
};
|
|
88
97
|
}
|
|
@@ -108,6 +117,8 @@ export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
|
108
117
|
skipReason: f.skipReason,
|
|
109
118
|
})),
|
|
110
119
|
postInstructions: result.postInstructions,
|
|
120
|
+
projectDirectory,
|
|
121
|
+
projectRoot,
|
|
111
122
|
};
|
|
112
123
|
}
|
|
113
124
|
catch (error) {
|
|
@@ -117,6 +128,8 @@ export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
|
117
128
|
outputDir,
|
|
118
129
|
dryRun: false,
|
|
119
130
|
files: [],
|
|
131
|
+
projectDirectory,
|
|
132
|
+
projectRoot,
|
|
120
133
|
error: `Scaffold generation failed: ${message}`,
|
|
121
134
|
};
|
|
122
135
|
}
|
|
@@ -140,6 +153,7 @@ apiDescription, projectRoot, outputDir.`,
|
|
|
140
153
|
toolsets: ['PWAV3', 'SCAPI', 'STOREFRONTNEXT'],
|
|
141
154
|
isGA: true,
|
|
142
155
|
requiresInstance: false,
|
|
156
|
+
usesProjectContext: true,
|
|
143
157
|
inputSchema: {
|
|
144
158
|
apiName: z
|
|
145
159
|
.string()
|
|
@@ -158,7 +172,7 @@ apiDescription, projectRoot, outputDir.`,
|
|
|
158
172
|
projectRoot: z
|
|
159
173
|
.string()
|
|
160
174
|
.nullish()
|
|
161
|
-
.describe('
|
|
175
|
+
.describe('Optional cartridge discovery/output root, resolved relative to projectDirectory. Defaults to projectDirectory.'),
|
|
162
176
|
outputDir: z.string().optional().describe('Output directory override. Default: project root'),
|
|
163
177
|
},
|
|
164
178
|
async execute(args, { services }) {
|
|
@@ -94,6 +94,7 @@ CLI: b2c scapi custom status`,
|
|
|
94
94
|
toolsets: ['PWAV3', 'SCAPI', 'STOREFRONTNEXT'],
|
|
95
95
|
isGA: true,
|
|
96
96
|
requiresInstance: false,
|
|
97
|
+
usesProjectContext: true,
|
|
97
98
|
inputSchema: {
|
|
98
99
|
status: z.enum(['active', 'not_registered']).optional().describe('Filter by status. Omit for all.'),
|
|
99
100
|
groupBy: z.enum(['site', 'type']).optional().describe('Group by siteId or type (Admin/Shopper).'),
|
|
@@ -12,11 +12,14 @@ import type { Services } from '../../../../services.js';
|
|
|
12
12
|
export declare const figmaToComponentSchema: z.ZodObject<{
|
|
13
13
|
figmaUrl: z.ZodString;
|
|
14
14
|
workflowFilePath: z.ZodOptional<z.ZodString>;
|
|
15
|
+
projectDirectory: z.ZodOptional<z.ZodString>;
|
|
15
16
|
}, "strict", z.ZodTypeAny, {
|
|
16
17
|
figmaUrl: string;
|
|
18
|
+
projectDirectory?: string | undefined;
|
|
17
19
|
workflowFilePath?: string | undefined;
|
|
18
20
|
}, {
|
|
19
21
|
figmaUrl: string;
|
|
22
|
+
projectDirectory?: string | undefined;
|
|
20
23
|
workflowFilePath?: string | undefined;
|
|
21
24
|
}>;
|
|
22
25
|
export type FigmaToComponentInput = z.infer<typeof figmaToComponentSchema>;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import { z } from 'zod';
|
|
15
15
|
import { readFileSync, existsSync } from 'node:fs';
|
|
16
16
|
import { createToolAdapter, textResult } from '../../../adapter.js';
|
|
17
|
+
import { projectDirectoryInput } from '../../../project-context.js';
|
|
17
18
|
import { parseFigmaUrl } from './figma-url-parser.js';
|
|
18
19
|
// prettier-ignore
|
|
19
20
|
const DEFAULT_WORKFLOW_CONTENT = `---
|
|
@@ -169,7 +170,8 @@ export const figmaToComponentSchema = z
|
|
|
169
170
|
workflowFilePath: z
|
|
170
171
|
.string()
|
|
171
172
|
.optional()
|
|
172
|
-
.describe('Optional
|
|
173
|
+
.describe('Optional path to a custom workflow .md file, resolved relative to projectDirectory when needed. If omitted, uses the default built-in workflow.'),
|
|
174
|
+
projectDirectory: projectDirectoryInput,
|
|
173
175
|
})
|
|
174
176
|
.strict();
|
|
175
177
|
function extractWorkflowContent(content) {
|
|
@@ -316,9 +318,13 @@ export function createFigmaToComponentTool(loadServices) {
|
|
|
316
318
|
toolsets: ['STOREFRONTNEXT_DEPRECATED'],
|
|
317
319
|
isGA: false,
|
|
318
320
|
requiresInstance: false,
|
|
321
|
+
usesProjectContext: true,
|
|
319
322
|
inputSchema: figmaToComponentSchema.shape,
|
|
320
|
-
async execute(args) {
|
|
321
|
-
|
|
323
|
+
async execute(args, context) {
|
|
324
|
+
const workflowFilePath = args.workflowFilePath
|
|
325
|
+
? context.services.resolveWithProjectDirectory(args.workflowFilePath, args.projectDirectory)
|
|
326
|
+
: undefined;
|
|
327
|
+
return generateWorkflowResponse(args.figmaUrl, workflowFilePath);
|
|
322
328
|
},
|
|
323
329
|
formatOutput: (output) => textResult(output),
|
|
324
330
|
}, loadServices);
|
|
@@ -48,6 +48,7 @@ export declare const generateComponentSchema: z.ZodObject<{
|
|
|
48
48
|
matchType: "name" | "structure" | "visual";
|
|
49
49
|
}>, "many">;
|
|
50
50
|
workspacePath: z.ZodOptional<z.ZodString>;
|
|
51
|
+
projectDirectory: z.ZodOptional<z.ZodString>;
|
|
51
52
|
}, "strict", z.ZodTypeAny, {
|
|
52
53
|
figmaMetadata: string;
|
|
53
54
|
figmaCode: string;
|
|
@@ -59,6 +60,7 @@ export declare const generateComponentSchema: z.ZodObject<{
|
|
|
59
60
|
similarity: number;
|
|
60
61
|
matchType: "name" | "structure" | "visual";
|
|
61
62
|
}[];
|
|
63
|
+
projectDirectory?: string | undefined;
|
|
62
64
|
workspacePath?: string | undefined;
|
|
63
65
|
}, {
|
|
64
66
|
figmaMetadata: string;
|
|
@@ -71,6 +73,7 @@ export declare const generateComponentSchema: z.ZodObject<{
|
|
|
71
73
|
similarity: number;
|
|
72
74
|
matchType: "name" | "structure" | "visual";
|
|
73
75
|
}[];
|
|
76
|
+
projectDirectory?: string | undefined;
|
|
74
77
|
workspacePath?: string | undefined;
|
|
75
78
|
}>;
|
|
76
79
|
export type GenerateComponentInput = z.infer<typeof generateComponentSchema>;
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { z } from 'zod';
|
|
14
14
|
import { createToolAdapter, textResult } from '../../../adapter.js';
|
|
15
|
+
import { projectDirectoryInput } from '../../../project-context.js';
|
|
15
16
|
import { analyzeComponentDifferences, determineAction } from './decision.js';
|
|
16
17
|
import { formatRecommendation } from './formatter.js';
|
|
17
18
|
const discoveredComponentSchema = z.object({
|
|
@@ -33,6 +34,7 @@ export const generateComponentSchema = z
|
|
|
33
34
|
.string()
|
|
34
35
|
.optional()
|
|
35
36
|
.describe('Optional workspace root path. Defaults to the MCP server project directory.'),
|
|
37
|
+
projectDirectory: projectDirectoryInput,
|
|
36
38
|
})
|
|
37
39
|
.strict();
|
|
38
40
|
function analyzeComponent(input) {
|
|
@@ -86,11 +88,12 @@ export function createGenerateComponentTool(loadServices) {
|
|
|
86
88
|
toolsets: ['STOREFRONTNEXT_DEPRECATED'],
|
|
87
89
|
isGA: false,
|
|
88
90
|
requiresInstance: false,
|
|
91
|
+
usesProjectContext: true,
|
|
89
92
|
inputSchema: generateComponentSchema.shape,
|
|
90
93
|
async execute(args, context) {
|
|
91
94
|
return generateComponentRecommendation({
|
|
92
95
|
...args,
|
|
93
|
-
workspacePath:
|
|
96
|
+
workspacePath: context.services.resolveWithProjectDirectory(args.workspacePath, args.projectDirectory),
|
|
94
97
|
});
|
|
95
98
|
},
|
|
96
99
|
formatOutput: (output) => textResult(output),
|
|
@@ -26,6 +26,7 @@ export declare const mapTokensToThemeSchema: z.ZodObject<{
|
|
|
26
26
|
description?: string | undefined;
|
|
27
27
|
}>, "many">;
|
|
28
28
|
themeFilePath: z.ZodOptional<z.ZodString>;
|
|
29
|
+
projectDirectory: z.ZodOptional<z.ZodString>;
|
|
29
30
|
}, "strict", z.ZodTypeAny, {
|
|
30
31
|
figmaTokens: {
|
|
31
32
|
type: "color" | "fontFamily" | "fontSize" | "opacity" | "other" | "radius" | "spacing";
|
|
@@ -33,6 +34,7 @@ export declare const mapTokensToThemeSchema: z.ZodObject<{
|
|
|
33
34
|
value: string;
|
|
34
35
|
description?: string | undefined;
|
|
35
36
|
}[];
|
|
37
|
+
projectDirectory?: string | undefined;
|
|
36
38
|
themeFilePath?: string | undefined;
|
|
37
39
|
}, {
|
|
38
40
|
figmaTokens: {
|
|
@@ -41,6 +43,7 @@ export declare const mapTokensToThemeSchema: z.ZodObject<{
|
|
|
41
43
|
value: string;
|
|
42
44
|
description?: string | undefined;
|
|
43
45
|
}[];
|
|
46
|
+
projectDirectory?: string | undefined;
|
|
44
47
|
themeFilePath?: string | undefined;
|
|
45
48
|
}>;
|
|
46
49
|
export type MapTokensToThemeInput = z.infer<typeof mapTokensToThemeSchema>;
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { z } from 'zod';
|
|
14
14
|
import { createToolAdapter, textResult } from '../../../adapter.js';
|
|
15
|
+
import { projectDirectoryInput } from '../../../project-context.js';
|
|
15
16
|
import { parseThemeFile } from './css-parser.js';
|
|
16
17
|
import { matchTokens } from './token-matcher.js';
|
|
17
18
|
export const mapTokensToThemeSchema = z
|
|
@@ -29,7 +30,8 @@ export const mapTokensToThemeSchema = z
|
|
|
29
30
|
themeFilePath: z
|
|
30
31
|
.string()
|
|
31
32
|
.optional()
|
|
32
|
-
.describe('Optional
|
|
33
|
+
.describe('Optional path to the theme CSS file, resolved relative to projectDirectory when needed. If omitted, searches for app.css in common locations.'),
|
|
34
|
+
projectDirectory: projectDirectoryInput,
|
|
33
35
|
})
|
|
34
36
|
.strict();
|
|
35
37
|
function formatTokenMatch(match) {
|
|
@@ -225,9 +227,14 @@ export function createMapTokensToThemeTool(loadServices) {
|
|
|
225
227
|
toolsets: ['STOREFRONTNEXT_DEPRECATED'],
|
|
226
228
|
isGA: false,
|
|
227
229
|
requiresInstance: false,
|
|
230
|
+
usesProjectContext: true,
|
|
228
231
|
inputSchema: mapTokensToThemeSchema.shape,
|
|
229
232
|
async execute(args, context) {
|
|
230
|
-
|
|
233
|
+
const workspaceRoot = context.services.resolveWithProjectDirectory(undefined, args.projectDirectory);
|
|
234
|
+
const themeFilePath = args.themeFilePath
|
|
235
|
+
? context.services.resolveWithProjectDirectory(args.themeFilePath, args.projectDirectory)
|
|
236
|
+
: undefined;
|
|
237
|
+
return mapFigmaTokensToTheme({ ...args, themeFilePath }, workspaceRoot);
|
|
231
238
|
},
|
|
232
239
|
formatOutput: (output) => textResult(output),
|
|
233
240
|
}, loadServices);
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { McpTool } from '../../../utils/index.js';
|
|
3
3
|
import type { Services } from '../../../services.js';
|
|
4
|
+
import { type ProjectContextInput } from '../../project-context.js';
|
|
4
5
|
export declare const pageDesignerDecoratorSchema: z.ZodObject<{
|
|
6
|
+
projectDirectory: z.ZodOptional<z.ZodString>;
|
|
7
|
+
configPath: z.ZodOptional<z.ZodString>;
|
|
5
8
|
component: z.ZodString;
|
|
6
9
|
searchPaths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
7
10
|
autoMode: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -167,6 +170,8 @@ export declare const pageDesignerDecoratorSchema: z.ZodObject<{
|
|
|
167
170
|
}>>;
|
|
168
171
|
}, "strict", z.ZodTypeAny, {
|
|
169
172
|
component: string;
|
|
173
|
+
projectDirectory?: string | undefined;
|
|
174
|
+
configPath?: string | undefined;
|
|
170
175
|
searchPaths?: string[] | undefined;
|
|
171
176
|
autoMode?: boolean | undefined;
|
|
172
177
|
componentId?: string | undefined;
|
|
@@ -205,6 +210,8 @@ export declare const pageDesignerDecoratorSchema: z.ZodObject<{
|
|
|
205
210
|
} | undefined;
|
|
206
211
|
}, {
|
|
207
212
|
component: string;
|
|
213
|
+
projectDirectory?: string | undefined;
|
|
214
|
+
configPath?: string | undefined;
|
|
208
215
|
searchPaths?: string[] | undefined;
|
|
209
216
|
autoMode?: boolean | undefined;
|
|
210
217
|
componentId?: string | undefined;
|
|
@@ -249,4 +256,4 @@ export type PageDesignerDecoratorInput = z.infer<typeof pageDesignerDecoratorSch
|
|
|
249
256
|
* @param loadServices - Function that loads configuration and returns Services instance
|
|
250
257
|
* @returns The configured MCP tool
|
|
251
258
|
*/
|
|
252
|
-
export declare function createPageDesignerDecoratorTool(loadServices: () => Promise<Services> | Services): McpTool;
|
|
259
|
+
export declare function createPageDesignerDecoratorTool(loadServices: (projectContext?: ProjectContextInput) => Promise<Services> | Services): McpTool;
|
|
@@ -7,6 +7,7 @@ import { z } from 'zod';
|
|
|
7
7
|
import { componentAnalyzer, generateTypeSuggestions, resolveComponent } from './analyzer.js';
|
|
8
8
|
import { generateDecoratorCode } from './templates/decorator-generator.js';
|
|
9
9
|
import { pageDesignerDecoratorRules } from './rules.js';
|
|
10
|
+
import { projectContextInputSchema } from '../../project-context.js';
|
|
10
11
|
// ============================================================================
|
|
11
12
|
// SCHEMA DEFINITION
|
|
12
13
|
// ============================================================================
|
|
@@ -93,6 +94,7 @@ export const pageDesignerDecoratorSchema = z
|
|
|
93
94
|
})
|
|
94
95
|
.optional()
|
|
95
96
|
.describe('Conversation state for multi-turn interaction'),
|
|
97
|
+
...projectContextInputSchema,
|
|
96
98
|
})
|
|
97
99
|
.strict();
|
|
98
100
|
// ============================================================================
|
|
@@ -543,8 +545,11 @@ export function createPageDesignerDecoratorTool(loadServices) {
|
|
|
543
545
|
const validatedArgs = pageDesignerDecoratorSchema.parse(args);
|
|
544
546
|
// Use projectDirectory from services to ensure we search in the correct project directory
|
|
545
547
|
// This prevents searches in the home folder when MCP clients spawn servers from ~
|
|
546
|
-
const services = await loadServices(
|
|
547
|
-
|
|
548
|
+
const services = await loadServices({
|
|
549
|
+
projectDirectory: validatedArgs.projectDirectory,
|
|
550
|
+
configPath: validatedArgs.configPath,
|
|
551
|
+
});
|
|
552
|
+
const workspaceRoot = services.resolveWithProjectDirectory(undefined, validatedArgs.projectDirectory);
|
|
548
553
|
if (validatedArgs.autoMode === undefined && !validatedArgs.conversationContext) {
|
|
549
554
|
const fullPath = resolveComponent(validatedArgs.component, workspaceRoot, validatedArgs.searchPaths);
|
|
550
555
|
const componentInfo = componentAnalyzer.analyzeComponent(fullPath);
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { z } from 'zod';
|
|
15
15
|
import { createToolAdapter, textResult, errorResult } from '../../adapter.js';
|
|
16
|
+
import { projectDirectoryInput } from '../../project-context.js';
|
|
16
17
|
import { siteThemingStore } from './theming-store.js';
|
|
17
18
|
import { mergeGuidance } from './guidance-merger.js';
|
|
18
19
|
import { generateResponse } from './response-builder.js';
|
|
@@ -42,7 +43,9 @@ export function createSiteThemingTool(loadServices) {
|
|
|
42
43
|
toolsets: ['STOREFRONTNEXT_DEPRECATED'],
|
|
43
44
|
isGA: false,
|
|
44
45
|
requiresInstance: false,
|
|
46
|
+
usesProjectContext: true,
|
|
45
47
|
inputSchema: {
|
|
48
|
+
projectDirectory: projectDirectoryInput,
|
|
46
49
|
fileKeys: z
|
|
47
50
|
.array(z.string())
|
|
48
51
|
.optional()
|
|
@@ -63,7 +66,9 @@ export function createSiteThemingTool(loadServices) {
|
|
|
63
66
|
.describe('Context from previous conversation rounds'),
|
|
64
67
|
},
|
|
65
68
|
async execute(args, context) {
|
|
66
|
-
siteThemingStore.initialize(context.services.resolveWithProjectDirectory()
|
|
69
|
+
siteThemingStore.initialize(context.services.resolveWithProjectDirectory(undefined, args.projectDirectory), {
|
|
70
|
+
themingFiles: context.services.getEnvironmentVariable('THEMING_FILES'),
|
|
71
|
+
});
|
|
67
72
|
const defaultFileKeys = ['theming-questions', 'theming-validation', 'theming-accessibility'];
|
|
68
73
|
let fileKeys;
|
|
69
74
|
if (args.fileKeys && args.fileKeys.length > 0) {
|
|
@@ -41,6 +41,8 @@ export interface ThemingGuidance {
|
|
|
41
41
|
export interface InitializeOptions {
|
|
42
42
|
/** Override content directory for default files (used in tests). */
|
|
43
43
|
contentDirOverride?: string;
|
|
44
|
+
/** Project-scoped THEMING_FILES value. */
|
|
45
|
+
themingFiles?: string;
|
|
44
46
|
}
|
|
45
47
|
declare class ThemingStore {
|
|
46
48
|
private initializedForRoot;
|
|
@@ -365,7 +365,7 @@ class ThemingStore {
|
|
|
365
365
|
}
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
|
-
const themingFilesEnv = process.env.THEMING_FILES;
|
|
368
|
+
const themingFilesEnv = options?.themingFiles ?? process.env.THEMING_FILES;
|
|
369
369
|
if (themingFilesEnv) {
|
|
370
370
|
try {
|
|
371
371
|
this.loadThemingFilesFromEnv(themingFilesEnv, root);
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/b2c-dx-mcp",
|
|
3
3
|
"description": "MCP server for B2C Commerce developer experience tools",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "2.0.0",
|
|
5
5
|
"author": "Salesforce",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": "SalesforceCommerceCloud/b2c-developer-tooling",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"yaml": "2.9.0",
|
|
81
81
|
"postcss": "8.5.15",
|
|
82
82
|
"zod": "3.25.76",
|
|
83
|
-
"@salesforce/b2c-tooling-sdk": "1.
|
|
83
|
+
"@salesforce/b2c-tooling-sdk": "1.24.0"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@eslint/compat": "^1",
|