55 */
66
77import { getLogger } from '@salesforce/b2c-tooling-sdk/logging' ;
8+ import { detectWorkspaceType , type ProjectType } from '@salesforce/b2c-tooling-sdk/discovery' ;
89import type { McpTool , Toolset , StartupFlags } from './utils/index.js' ;
910import { ALL_TOOLSETS , TOOLSETS , VALID_TOOLSET_NAMES } from './utils/index.js' ;
1011import type { B2CDxMcpServer } from './server.js' ;
@@ -15,6 +16,55 @@ import {createPwav3Tools} from './tools/pwav3/index.js';
1516import { createScapiTools } from './tools/scapi/index.js' ;
1617import { createStorefrontNextTools } from './tools/storefrontnext/index.js' ;
1718
19+ /**
20+ * Base toolset that is always enabled.
21+ * Provides SCAPI discovery and custom API scaffolding tools.
22+ */
23+ const BASE_TOOLSET : Toolset = 'SCAPI' ;
24+
25+ /**
26+ * Toolset mapping by project type.
27+ * Each project type enables specific toolsets IN ADDITION to the base toolset.
28+ */
29+ const PROJECT_TYPE_TOOLSETS : Record < ProjectType , Toolset [ ] > = {
30+ cartridges : [ 'CARTRIDGES' ] ,
31+ 'pwa-kit-v3' : [ 'PWAV3' , 'MRT' ] ,
32+ 'storefront-next' : [ 'STOREFRONTNEXT' , 'MRT' ] ,
33+ } ;
34+
35+ /**
36+ * Gets toolsets for a project type, always including the base toolset.
37+ */
38+ function getToolsetsForProjectType ( projectType : ProjectType ) : Toolset [ ] {
39+ const additionalToolsets = PROJECT_TYPE_TOOLSETS [ projectType ] ?? [ ] ;
40+ return [ ...additionalToolsets , BASE_TOOLSET ] ;
41+ }
42+
43+ /**
44+ * Maps multiple detected project types to a union of MCP toolsets.
45+ *
46+ * Combines toolsets from all matched project types, enabling hybrid
47+ * project support (e.g., cartridges + pwa-kit-v3 gets CARTRIDGES + PWAV3 + MRT + SCAPI).
48+ *
49+ * @param projectTypes - Array of detected project types
50+ * @returns Union of all toolsets for the detected project types (always includes base toolset)
51+ */
52+ function getToolsetsForProjectTypes ( projectTypes : ProjectType [ ] ) : Toolset [ ] {
53+ const toolsetSet = new Set < Toolset > ( ) ;
54+
55+ // Always include base toolset
56+ toolsetSet . add ( BASE_TOOLSET ) ;
57+
58+ // Add toolsets for each detected project type
59+ for ( const projectType of projectTypes ) {
60+ for ( const toolset of getToolsetsForProjectType ( projectType ) ) {
61+ toolsetSet . add ( toolset ) ;
62+ }
63+ }
64+
65+ return [ ...toolsetSet ] ;
66+ }
67+
1868/**
1969 * Registry of tools organized by toolset.
2070 * Tools can belong to multiple toolsets via their `toolsets` array.
@@ -61,8 +111,9 @@ export function createToolRegistry(services: Services): ToolRegistry {
61111 * Register tools with the MCP server based on startup flags.
62112 *
63113 * Tool selection logic:
64- * 1. Start with all tools from --toolsets
65- * 2. Add individual tools from --tools (can be from any toolset)
114+ * 1. If neither --toolsets nor --tools are provided, perform auto-discovery
115+ * 2. Start with all tools from --toolsets (or auto-discovered toolsets)
116+ * 3. Add individual tools from --tools (can be from any toolset)
66117 *
67118 * Example:
68119 * --toolsets STOREFRONTNEXT,MRT --tools cartridge_deploy
@@ -73,12 +124,43 @@ export function createToolRegistry(services: Services): ToolRegistry {
73124 * @param services - Services instance
74125 */
75126export async function registerToolsets ( flags : StartupFlags , server : B2CDxMcpServer , services : Services ) : Promise < void > {
76- const toolsets = flags . toolsets ?? [ ] ;
127+ let toolsets = flags . toolsets ?? [ ] ;
77128 const individualTools = flags . tools ?? [ ] ;
78129 const allowNonGaTools = flags . allowNonGaTools ?? false ;
130+ const logger = getLogger ( ) ;
131+
132+ // Auto-discovery: When no --toolsets or --tools flags are provided,
133+ // detect project type and enable appropriate toolsets automatically.
134+ if ( toolsets . length === 0 && individualTools . length === 0 ) {
135+ // Working directory from --working-directory flag or SFCC_WORKING_DIRECTORY env var
136+ const workingDirectory = flags . workingDirectory ?? process . cwd ( ) ;
137+
138+ // Warn if working directory wasn't explicitly configured
139+ if ( ! flags . workingDirectory ) {
140+ logger . warn (
141+ { cwd : workingDirectory } ,
142+ 'No --working-directory flag or SFCC_WORKING_DIRECTORY env var provided. ' +
143+ 'MCP clients like Cursor and Claude Desktop often spawn servers from ~ instead of the project directory. ' +
144+ 'Set --working-directory or SFCC_WORKING_DIRECTORY for reliable auto-discovery.' ,
145+ ) ;
146+ }
79147
80- // NOTE: When no --toolsets or --tools flags are provided, auto-discovery
81- // will detect project type and enable appropriate toolsets automatically.
148+ const detectionResult = await detectWorkspaceType ( workingDirectory ) ;
149+
150+ // Map all detected project types to MCP toolsets (union)
151+ const mappedToolsets = getToolsetsForProjectTypes ( detectionResult . projectTypes ) ;
152+
153+ logger . info (
154+ {
155+ projectTypes : detectionResult . projectTypes ,
156+ matchedPatterns : detectionResult . matchedPatterns ,
157+ enabledToolsets : mappedToolsets ,
158+ } ,
159+ `Auto-discovered project types: ${ detectionResult . projectTypes . join ( ', ' ) || 'none' } ` ,
160+ ) ;
161+
162+ toolsets = mappedToolsets ;
163+ }
82164
83165 // Create the tool registry (all available tools)
84166 const toolRegistry = createToolRegistry ( services ) ;
@@ -88,8 +170,6 @@ export async function registerToolsets(flags: StartupFlags, server: B2CDxMcpServ
88170 const allToolsByName = new Map ( allTools . map ( ( tool ) => [ tool . name , tool ] ) ) ;
89171 const existingToolNames = new Set ( allToolsByName . keys ( ) ) ;
90172
91- const logger = getLogger ( ) ;
92-
93173 // Warn about invalid --tools names (but continue with valid ones)
94174 const invalidTools = individualTools . filter ( ( name ) => ! existingToolNames . has ( name ) ) ;
95175 if ( invalidTools . length > 0 ) {
0 commit comments