Skip to content

@W-20926594 MCP Server Flag Configuration and SDK Refactoring#65

Merged
yhsieh1 merged 7 commits intomainfrom
t/commerce/W-20926594/refactor-fix-lookup-config
Jan 26, 2026
Merged

@W-20926594 MCP Server Flag Configuration and SDK Refactoring#65
yhsieh1 merged 7 commits intomainfrom
t/commerce/W-20926594/refactor-fix-lookup-config

Conversation

@yhsieh1
Copy link
Copy Markdown
Contributor

@yhsieh1 yhsieh1 commented Jan 21, 2026

Summary

This PR refactors the SDK's flag extraction logic into reusable helpers, enabling consistent configuration handling between CLI commands and the MCP server. Previously, flag-to-config mapping was duplicated across OAuthCommand, InstanceCommand, and MrtCommand. Now, shared helpers (extractOAuthFlags, extractInstanceFlags, extractMrtFlags) provide a single source of truth that both CLI commands and McpServerCommand use.

A new startDir option was added to LoadConfigOptions to specify where config file search begins. This is essential for MCP servers since clients (Cursor, Claude Desktop) spawn servers from ~ rather than the project directory—without startDir, dw.json discovery would fail.

Additionally, this PR improves auto-discovery behavior to gracefully handle invalid toolset/tool names by falling back to auto-discovery instead of registering zero tools.

Changes

MCP Server (packages/b2c-dx-mcp)

Registry Improvements (src/registry.ts)

  • Auto-discovery fallback: Auto-discovery now triggers when no valid tools result from --toolsets and --tools (not just when no flags are provided)
  • Extracted performAutoDiscovery() helper: Reusable function for workspace type detection with logging
  • Storefront Next toolsets: Added CARTRIDGES to storefront-next project type mapping (['STOREFRONTNEXT', 'MRT', 'CARTRIDGES'])
  • Simplified registerToolsets(): Removed redundant auto-discovery check, unified into single fallback

Auto-Discovery Behavior

Scenario Before After
No --toolsets or --tools provided Auto-discovery Auto-discovery
All --toolsets invalid (e.g., typos) 0 tools registered Auto-discovery fallback
All --tools invalid 0 tools registered Auto-discovery fallback
Valid --toolsets or --tools Uses provided flags Uses provided flags (no change)

Other Changes

  • Add loadConfiguration() override to McpServerCommand to extract B2C instance and MRT flags
  • Updated test cases in test/registry.test.ts to reflect new auto-discovery behavior

SDK Flag Extraction Refactoring (packages/b2c-tooling-sdk)

Problem

The existing command classes (OAuthCommand, InstanceCommand, MrtCommand) each contained inline flag-to-config mapping logic. This duplication meant:

  • Same parsing logic repeated across multiple files
  • Harder to maintain consistency when flag names change
  • MCP server command couldn't easily reuse the same extraction logic
  • Risk of drift between CLI commands and MCP server configuration

Solution: Extract Reusable Helpers

Refactored flag extraction into dedicated helper functions in src/cli/config.ts:

Helper Purpose Flags Extracted
extractOAuthFlags() OAuth credential extraction --client-id, --client-secret, --short-code, --auth-methods, --account-manager-host, --scope
extractInstanceFlags() B2C instance config (includes OAuth) --server, --webdav-server, --code-version, --username, --password + OAuth flags
extractMrtFlags() MRT/Managed Runtime config --api-key, --project, --environment, --cloud-origin

Changes

  • New helpers: Added extractOAuthFlags(), extractInstanceFlags(), extractMrtFlags() to src/cli/config.ts
  • New startDir option: Added startDir to LoadConfigOptions for specifying the starting directory when searching for config files (e.g., dw.json). Why needed for MCP: MCP clients (Cursor, Claude Desktop) typically spawn servers from ~ (home directory) rather than the project directory. Without startDir, config file search starts from ~ and won't find the project's dw.json. The --working-directory flag or SFCC_WORKING_DIRECTORY env var tells the config loader where to look.
  • New getBaseConfigOptions() and getPluginSources() methods: Added to BaseCommand to centralize common config options. Subclasses spread this.getBaseConfigOptions() to automatically inherit base options like startDir, preventing bugs when new options are added.
  • Refactored commands: Updated OAuthCommand, InstanceCommand, MrtCommand to use helpers and spread base options
  • MCP integration: McpServerCommand.loadConfiguration() now uses the same helpers, ensuring consistent flag handling
  • New tests: Added unit tests for all three helper functions in test/cli/config.test.ts

Benefits

  • DRY: Single source of truth for flag-to-config mapping
  • Maintainability: Change flag name in one place, all commands update
  • Consistency: CLI commands and MCP server use identical extraction logic
  • Testability: Helpers can be unit tested independently

Configuration Priority

B2C Instance

  1. CLI flags (--server, --username, --password, etc.)
  2. Environment variables (SFCC_SERVER, SFCC_USERNAME, etc.)
  3. dw.json file

MRT

  1. CLI flags (--api-key, --project, --environment)
  2. Environment variables (SFCC_MRT_API_KEY, SFCC_MRT_PROJECT, etc.)
  3. dw.json file
  4. ~/.mobify file

Test Plan

Toolset Selection Tests (Section 1)

Test Purpose
1.5a Invalid Toolset - Auto-discovery Fallback Verify auto-discovery triggers when all toolsets invalid
1.5b Invalid Tools - Auto-discovery Fallback Verify auto-discovery triggers when all tools invalid

Auto-Discovery Tests (Section 2)

Test Purpose
2.3 Storefront Next Detection Verify STOREFRONTNEXT, MRT, CARTRIDGES, SCAPI enabled

B2C Instance Configuration Tests (Section 3)

Test Purpose
3.1 Config via Flags - Basic Auth Verify --server, --username, --password flags work
3.2 Config via Flags - OAuth Verify --client-id, --client-secret flags work
3.3 Config via Environment Variables Verify SFCC_SERVER, SFCC_USERNAME, SFCC_PASSWORD env vars work
3.4 Config via dw.json (--config) Verify explicit config file path works
3.5 Config via dw.json Auto-Discovery Verify dw.json is discovered via --working-directory (tests startDir option)
3.6 Precedence: Flags > Env Vars Verify flags take precedence over env vars
3.7 Precedence: Env Vars > dw.json Verify env vars take precedence over dw.json
3.8 Missing B2C Instance Config Error Verify error when no config provided

MRT Configuration Tests (Section 4)

Test Purpose
4.1 Full MRT Config via Flags Verify --project, --environment, --api-key flags work
4.2 MRT Config via Env Vars Verify SFCC_MRT_* env vars work
4.3 MRT Auth via ~/.mobify Verify fallback to ~/.mobify for API key
4.4 MRT Auth via --cloud-origin Verify environment-specific config selection
4.5 Missing MRT Project Error Verify error when project not provided
4.6 Missing MRT Auth Error Verify error when API key not provided

  • Tests pass (pnpm test)
  • Code is formatted (pnpm run format)

@yhsieh1 yhsieh1 requested a review from clavery as a code owner January 21, 2026 20:20
@yhsieh1 yhsieh1 requested a review from allison-grady January 21, 2026 20:28
Comment thread packages/b2c-dx-mcp/README.md Outdated
When `--config` is not provided, the MCP server searches for `dw.json` starting from the `--working-directory` path (or `SFCC_WORKING_DIRECTORY` env var).

> **Note:** Auto-discovery starts from the home directory, so it won't find project-level `dw.json` files. Use `--config` with an explicit path instead.
> **Important:** MCP clients like Cursor and Claude Desktop often spawn servers from the home directory (`~`) rather than the project directory. Always set `--working-directory` for reliable `dw.json` auto-discovery.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not be mentioning dw.json in most places. The config load is complex and dw.json is just one part of it. We should be more general: "reliable configuration loading and auto-discovery", etc

Copy link
Copy Markdown
Collaborator

@clavery clavery left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good. Overall a good refactoring. A added a few nits and observations where we might not be using some of your new methods. And if we're ready we can confirm that plugins work (should be able to a plugins install sfcc-solutions-share/b2c-plugin-macos-keychain to get my keychain plugin).

And I just want to emphasize that (outside of the --config flag that points to it) the dw.json convention is an implementation detail of the SDK. That is, it's just one step in the configuration loading and that config can come from multiple places (mobify, package.json now, plugin sources and likely future out of the box sources). So it's important that the MCP behaves the same as the CLI and doesn't accidentally change the config behavior. I think we're good here as I just noticed it mentioned in documentation.

**Option E: dw.json with auto-discovery**

When `--config` is not provided, the MCP server searches upward from `~/` for a `dw.json` file.
When `--config` is not provided, the MCP server searches for `dw.json` starting from the `--working-directory` path (or `SFCC_WORKING_DIRECTORY` env var).
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the --working-directory suffice? I'm not sure we need to do a search for dw.json at all here. If the file isn't in the working-directory we won't load it. But we may load some other configuration source that is sufficient for the task. The working-directory is the important part here.

Copy link
Copy Markdown
Contributor Author

@yhsieh1 yhsieh1 Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--working-directory should be suffice but --config is also useful if user has different config setup. I will --config to be consist with CLI and de-emphasize it in the doc so that user will not be confused. I'll have a separated PR for README.md update soon to reflect this. PR #78

Comment thread packages/b2c-dx-mcp/src/commands/mcp.ts Outdated
Comment on lines +231 to +233
const options: LoadConfigOptions = {
instance: this.flags.instance,
configPath: this.flags.config,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be using your new getBaseConfigOptions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, thanks!

Comment thread packages/b2c-dx-mcp/src/commands/mcp.ts Outdated
Comment on lines +235 to +236
cloudOrigin: this.flags['cloud-origin'] as string | undefined, // MobifySource uses this to load ~/.mobify--[hostname] if set
credentialsFile: this.flags['credentials-file'] as string | undefined, // Override path to MRT credentials file
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't these two be part of the extractMrtFlags?

Comment thread packages/b2c-dx-mcp/src/commands/mcp.ts Outdated
Comment on lines +239 to +242
const pluginSources: PluginSources = {
before: this.pluginSourcesBefore,
after: this.pluginSourcesAfter,
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have everything to make the mcp server command support our plugins? Reference the b2c-cli package to ensure we do (I believe it'll just work since it's just registering hooks with oclif but want to confirm)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also should this be getPluginSources which you added to base command?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think MCP should not support plugins to keep it simple since the plugin needs separated installation. I removed it to avoid confusion.

Copy link
Copy Markdown
Collaborator

@clavery clavery Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely DO want MCP to support plugins. Yes they do need to install it (via npx for instance) but it's crucial to support alternative config sources.

It's ok if that's a separate task to get it working.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I will add a task to support plugin.

Keep refactored loadConfiguration() using extractOAuthFlags helper
instead of verbose inline flag extraction from main.
@yhsieh1 yhsieh1 requested a review from clavery January 26, 2026 15:55
The tenant-id flag was defined in OAuthCommand.baseFlags but not
extracted in extractOAuthFlags(), causing SLAS client commands to
fail when tenant-id was provided via flags.
Copy link
Copy Markdown
Collaborator

@clavery clavery left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We DO want to support b2c-cli plugins. But it doesn't have to be this PRs job to validate that

@yhsieh1 yhsieh1 merged commit 20e2512 into main Jan 26, 2026
3 checks passed
@clavery clavery deleted the t/commerce/W-20926594/refactor-fix-lookup-config branch February 8, 2026 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants