Skip to content

Commit c80c3c3

Browse files
committed
@W-20591366 add tool adapter layer
1 parent 0659d4c commit c80c3c3

17 files changed

Lines changed: 1822 additions & 219 deletions

File tree

packages/b2c-dx-mcp/README.md

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ Since the package is not yet published to npm, see the [Development](#developmen
2222
| `--tools` | Comma-separated individual tools to enable (case-insensitive) |
2323
| `--allow-non-ga-tools` | Enable experimental (non-GA) tools |
2424

25+
#### Auth Flags
26+
27+
| Flag | Env Variable | Description |
28+
|------|--------------|-------------|
29+
| `--mrt-api-key` | `SFCC_MRT_API_KEY` | MRT API key for Managed Runtime operations |
30+
| `--mrt-cloud-origin` | `SFCC_MRT_CLOUD_ORIGIN` | MRT cloud origin URL (default: https://cloud.mobify.com). See [Environment-Specific Config Files](#environment-specific-config-files) |
31+
2532
#### Global Flags (inherited from SDK)
2633

2734
| Flag | Description |
@@ -48,6 +55,13 @@ Since the package is not yet published to npm, see the [Development](#developmen
4855
// Explicit config file path
4956
"args": ["--toolsets", "all", "--config", "/path/to/dw.json"]
5057

58+
// MRT tools with API key
59+
"args": ["--toolsets", "MRT", "--mrt-api-key", "your-api-key"]
60+
61+
// Or use environment variable in mcp.json
62+
"args": ["--toolsets", "MRT"],
63+
"env": { "SFCC_MRT_API_KEY": "your-api-key" }
64+
5165
// Enable experimental tools (required for placeholder tools)
5266
"args": ["--toolsets", "all", "--allow-non-ga-tools"]
5367

@@ -211,7 +225,20 @@ Configure your IDE to use the local MCP server. Add this to your IDE's MCP confi
211225
}
212226
```
213227

214-
> **Note:** Restart the MCP server in your IDE to pick up code changes.
228+
**Production Mode** (uses compiled JavaScript - run `pnpm run build` first):
229+
230+
```json
231+
{
232+
"mcpServers": {
233+
"b2c-dx-local": {
234+
"command": "node",
235+
"args": ["/full/path/to/packages/b2c-dx-mcp/bin/run.js", "--toolsets", "all", "--allow-non-ga-tools"]
236+
}
237+
}
238+
}
239+
```
240+
241+
> **Note:** For production mode, run `pnpm run build` after code changes and restart your IDE. Development mode picks up changes automatically.
215242
216243
#### 3. JSON-RPC via stdin
217244

@@ -267,6 +294,76 @@ Create a `dw.json` file in your project root (auto-discovered by searching upwar
267294

268295
> **Note:** Environment variables take precedence over `dw.json` values.
269296
297+
#### MRT API Key
298+
299+
MRT (Managed Runtime) operations require an API key from the [Runtime Admin](https://runtime.commercecloud.com/) dashboard.
300+
301+
**Priority order** (highest to lowest):
302+
303+
1. `--mrt-api-key` flag
304+
2. `SFCC_MRT_API_KEY` environment variable
305+
3. `~/.mobify` config file (or `~/.mobify--[hostname]` if `--mrt-cloud-origin` is set)
306+
307+
**Option A: Flag or environment variable**
308+
309+
```json
310+
// mcp.json - using flag
311+
{
312+
"mcpServers": {
313+
"b2c-dx": {
314+
"command": "b2c-dx-mcp",
315+
"args": ["--toolsets", "MRT", "--mrt-api-key", "your-api-key"]
316+
}
317+
}
318+
}
319+
320+
// mcp.json - using env var
321+
{
322+
"mcpServers": {
323+
"b2c-dx": {
324+
"command": "b2c-dx-mcp",
325+
"args": ["--toolsets", "MRT"],
326+
"env": {
327+
"SFCC_MRT_API_KEY": "your-api-key"
328+
}
329+
}
330+
}
331+
}
332+
```
333+
334+
**Option B: ~/.mobify file (legacy)**
335+
336+
If you already use the `b2c` CLI for MRT operations, you may have a `~/.mobify` file configured:
337+
338+
```json
339+
{
340+
"username": "your.email@example.com",
341+
"api_key": "your-api-key"
342+
}
343+
```
344+
345+
The MCP server will automatically use this file as a fallback if no flag or environment variable is set.
346+
347+
##### Environment-Specific Config Files
348+
349+
When using `~/.mobify` config files (i.e., no `--mrt-api-key` flag or `SFCC_MRT_API_KEY` env var), you can use `--mrt-cloud-origin` to select an environment-specific config file:
350+
351+
```bash
352+
# Uses ~/.mobify--cloud-staging.mobify.com for API key
353+
b2c-dx-mcp --toolsets MRT --mrt-cloud-origin https://cloud-staging.mobify.com
354+
355+
# Or via environment variable
356+
SFCC_MRT_CLOUD_ORIGIN=https://cloud-staging.mobify.com b2c-dx-mcp --toolsets MRT
357+
```
358+
359+
| Cloud Origin | Config File |
360+
|--------------|-------------|
361+
| (default) | `~/.mobify` |
362+
| `https://cloud-staging.mobify.com` | `~/.mobify--cloud-staging.mobify.com` |
363+
| `https://cloud-dev.mobify.com` | `~/.mobify--cloud-dev.mobify.com` |
364+
365+
> **Note:** `--mrt-cloud-origin` is only relevant when the API key is resolved from a config file. If `--mrt-api-key` or `SFCC_MRT_API_KEY` is provided, this flag is ignored.
366+
270367
## License
271368

272369
Apache-2.0

packages/b2c-dx-mcp/bin/run.js

100644100755
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
* - Uses compiled JavaScript from dist/
1414
* - Loads .env file if present for local configuration
1515
*
16-
* Run directly: ./bin/run.js mcp --toolsets all
17-
* Or with node: node bin/run.js mcp --toolsets all
1816
*/
1917

2018
// Load .env file if present (Node.js native support)

packages/b2c-dx-mcp/src/commands/mcp.ts

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
* | `--tools` | Comma-separated individual tools to enable (case-insensitive) |
2121
* | `--allow-non-ga-tools` | Enable experimental/non-GA tools |
2222
*
23+
* ### Auth Flags
24+
* | Flag | Description |
25+
* |------|-------------|
26+
* | `--mrt-api-key` | MRT API key for Managed Runtime operations |
27+
*
2328
* ### Global Flags (inherited from BaseCommand)
2429
* | Flag | Description |
2530
* |------|-------------|
@@ -32,10 +37,16 @@
3237
*
3338
* ## Configuration Priority
3439
*
40+
* ### B2C Instance Configuration (dw.json)
3541
* 1. Environment variables (SFCC_*) - highest priority, override dw.json
3642
* 2. dw.json file (explicit path via --config, or auto-discovered)
3743
* 3. Auto-discovery (searches upward from cwd)
3844
*
45+
* ### MRT API Key
46+
* 1. `--mrt-api-key` flag (highest priority)
47+
* 2. `SFCC_MRT_API_KEY` environment variable
48+
* 3. `~/.mobify` config file (or `~/.mobify--[hostname]` if `--mrt-cloud-origin` is set)
49+
*
3950
* ## Toolset Validation
4051
*
4152
* - Invalid toolsets are ignored with a warning (server still starts)
@@ -66,6 +77,11 @@
6677
* b2c-dx-mcp --toolsets all --config /path/to/dw.json
6778
* ```
6879
*
80+
* @example Start MRT tools with API key
81+
* ```bash
82+
* b2c-dx-mcp --toolsets MRT --mrt-api-key your-api-key
83+
* ```
84+
*
6985
* @example Enable debug logging
7086
* ```bash
7187
* b2c-dx-mcp --toolsets all --debug
@@ -74,6 +90,7 @@
7490

7591
import {Flags} from '@oclif/core';
7692
import {BaseCommand} from '@salesforce/b2c-tooling-sdk/cli';
93+
import {DEFAULT_MRT_ORIGIN} from '@salesforce/b2c-tooling-sdk/clients';
7794
import {StdioServerTransport} from '@modelcontextprotocol/sdk/server/stdio.js';
7895
import {B2CDxMcpServer} from '../server.js';
7996
import {Services} from '../services.js';
@@ -116,6 +133,18 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
116133
parse: async (input) => input.toLowerCase(),
117134
}),
118135

136+
// Auth flags
137+
'mrt-api-key': Flags.string({
138+
description: 'MRT API key for Managed Runtime operations',
139+
env: 'SFCC_MRT_API_KEY',
140+
helpGroup: 'AUTH',
141+
}),
142+
'mrt-cloud-origin': Flags.string({
143+
description: `MRT cloud origin URL (default: ${DEFAULT_MRT_ORIGIN})`,
144+
env: 'SFCC_MRT_CLOUD_ORIGIN',
145+
helpGroup: 'AUTH',
146+
}),
147+
119148
// Feature flags
120149
'allow-non-ga-tools': Flags.boolean({
121150
description: 'Enable non-GA (experimental) tools',
@@ -131,7 +160,7 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
131160
* 1. BaseCommand.init() parses flags and loads config
132161
* 2. Filter and validate toolsets (invalid ones are skipped with warning)
133162
* 3. Create B2CDxMcpServer instance
134-
* 4. Create Services for dependency injection (config, file system access)
163+
* 4. Create Services via Services.create() which resolves MRT auth from flags/env/config
135164
* 5. Register tools based on --toolsets and --tools flags
136165
* 6. Connect to stdio transport (JSON-RPC over stdin/stdout)
137166
* 7. Log startup message to stderr
@@ -188,10 +217,11 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
188217
},
189218
);
190219

191-
// Create services for dependency injection
192-
// Pass the config path for tools that need to load configuration
193-
const services = new Services({
220+
// Create services with MRT auth resolved from flags/env/config
221+
const services = Services.create({
194222
configPath: this.flags.config,
223+
mrtApiKey: this.flags['mrt-api-key'],
224+
mrtCloudOrigin: this.flags['mrt-cloud-origin'],
195225
});
196226

197227
// Register toolsets
@@ -202,7 +232,6 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
202232
await server.connect(transport);
203233

204234
// Log startup message using the structured logger
205-
this.logger.info({version: this.config.version, toolsets: TOOLSETS}, 'MCP Server running on stdio');
206-
this.logger.info({enabled: startupFlags.toolsets ?? []}, 'Enabled toolsets');
235+
this.logger.info({version: this.config.version}, 'MCP Server running on stdio');
207236
}
208237
}

packages/b2c-dx-mcp/src/registry.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
55
*/
66

7-
import {EOL} from 'node:os';
7+
import {getLogger} from '@salesforce/b2c-tooling-sdk/logging';
88
import type {McpTool, Toolset, StartupFlags} from './utils/index.js';
99
import {ALL_TOOLSETS, TOOLSETS, VALID_TOOLSET_NAMES} from './utils/index.js';
1010
import type {B2CDxMcpServer} from './server.js';
@@ -83,28 +83,30 @@ export async function registerToolsets(flags: StartupFlags, server: B2CDxMcpServ
8383
// Create the tool registry (all available tools)
8484
const toolRegistry = createToolRegistry(services);
8585

86-
// Build flat list of all tools for validation and lookup
86+
// Build flat list of all tools for lookup
8787
const allTools = Object.values(toolRegistry).flat();
8888
const allToolsByName = new Map(allTools.map((tool) => [tool.name, tool]));
8989
const existingToolNames = new Set(allToolsByName.keys());
9090

91+
const logger = getLogger();
92+
9193
// Warn about invalid --tools names (but continue with valid ones)
9294
const invalidTools = individualTools.filter((name) => !existingToolNames.has(name));
9395
if (invalidTools.length > 0) {
94-
console.error(
95-
`⚠️ Ignoring invalid tool name(s): "${invalidTools.join('", "')}"${EOL}` +
96-
` Valid tools: ${[...existingToolNames].join(', ')}`,
96+
logger.warn(
97+
{invalidTools, validTools: [...existingToolNames]},
98+
`Ignoring invalid tool name(s): "${invalidTools.join('", "')}"`,
9799
);
98100
}
99101

100-
// Validate --toolsets names
102+
// Warn about invalid --toolsets names (but continue with valid ones)
101103
const invalidToolsets = toolsets.filter(
102104
(t) => !VALID_TOOLSET_NAMES.includes(t as (typeof VALID_TOOLSET_NAMES)[number]),
103105
);
104106
if (invalidToolsets.length > 0) {
105-
console.error(
106-
`⚠️ Ignoring invalid toolset(s): "${invalidToolsets.join('", "')}"\n` +
107-
` Valid toolsets: ${VALID_TOOLSET_NAMES.join(', ')}`,
107+
logger.warn(
108+
{invalidToolsets, validToolsets: VALID_TOOLSET_NAMES},
109+
`Ignoring invalid toolset(s): "${invalidToolsets.join('", "')}"`,
108110
);
109111
}
110112

packages/b2c-dx-mcp/src/server.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ export class B2CDxMcpServer extends McpServer {
6767
args: Record<string, unknown>,
6868
_extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
6969
): Promise<CallToolResult> => {
70-
const startTime = Date.now();
70+
// TODO: Telemetry - Track timing and send TOOL_CALLED event
71+
// const startTime = Date.now();
7172
const result = await handler(args);
72-
// TODO: Telemetry - Send TOOL_CALLED event with { name, _runtimeMs, isError: result.isError }
73-
// @ts-expect-error Ignore unused variable
74-
const _runtimeMs = Date.now() - startTime;
73+
// const runtimeMs = Date.now() - startTime;
74+
// telemetry.sendEvent('TOOL_CALLED', { name, runtimeMs, isError: result.isError });
7575

7676
return result;
7777
};

0 commit comments

Comments
 (0)