Skip to content

Commit 55397bf

Browse files
Add telemetry service (#68)
1 parent ec6fe68 commit 55397bf

21 files changed

Lines changed: 3925 additions & 34 deletions

File tree

packages/b2c-cli/bin/dev.cmd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
@echo off
22

3+
@REM Disable telemetry in development mode to avoid polluting production data
4+
if not defined SFCC_DISABLE_TELEMETRY set SFCC_DISABLE_TELEMETRY=true
5+
36
node --import tsx "%~dp0\dev" %*

packages/b2c-cli/bin/dev.js

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

8+
// Disable telemetry in development mode to avoid polluting production data
9+
process.env.SFCC_DISABLE_TELEMETRY = process.env.SFCC_DISABLE_TELEMETRY || 'true';
10+
811
// Load .env file if present (Node.js native support)
912
try {
1013
process.loadEnvFile();

packages/b2c-cli/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@
7878
"bin": "b2c",
7979
"dirname": "b2c",
8080
"commands": "./dist/commands",
81+
"telemetry": {
82+
"connectionString": "InstrumentationKey=6fcc215f-0b11-4864-ad5c-3945ae19e2f3;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/;ApplicationId=a60f17ec-265a-4dfc-b8df-03a64695697d"
83+
},
8184
"plugins": [
8285
"@oclif/plugin-help",
8386
"@oclif/plugin-plugins",

packages/b2c-cli/test/commands/ecdn/security/get.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ describe('ecdn security get', () => {
9898
}),
9999
});
100100

101-
const result = (await runSilent(() => command.run())) as {settings: {securityLevel: string; wafEnabled: boolean}};
101+
const result = (await runSilent(() => command.run())) as {
102+
settings: {securityLevel: string; wafEnabled: boolean};
103+
};
102104

103105
expect(result.settings.securityLevel).to.equal('high');
104106
expect(result.settings.wafEnabled).to.be.true;

packages/b2c-cli/test/commands/ecdn/zones/list.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ describe('ecdn zones list', () => {
129129
}),
130130
});
131131

132-
const result = (await runSilent(() => command.run())) as {total: number; zones: Array<{name: string}>};
132+
const result = (await runSilent(() => command.run())) as {
133+
total: number;
134+
zones: Array<{name: string}>;
135+
};
133136

134137
expect(result).to.have.property('total', 1);
135138
expect(result.zones).to.have.lengthOf(1);

packages/b2c-dx-mcp/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,43 @@ Storefront Next development tools for building modern storefronts.
298298

299299
> **Note:** Some tools appear in multiple toolsets (e.g., `mrt_bundle_push`, `scapi_discovery`). When using multiple toolsets, tools are automatically deduplicated.
300300
301+
## Telemetry
302+
303+
The MCP server collects anonymous usage telemetry to help improve the developer experience. Telemetry is enabled by default.
304+
305+
**Development mode**: Telemetry is automatically disabled when using `bin/dev.js`, so local development and testing won't pollute production data.
306+
307+
### Disabling Telemetry
308+
309+
Set one of these environment variables to disable telemetry:
310+
311+
```bash
312+
# Salesforce CLI standard (recommended)
313+
SF_DISABLE_TELEMETRY=true
314+
315+
# Or SFCC-specific
316+
SFCC_DISABLE_TELEMETRY=true
317+
```
318+
319+
You can also override the telemetry connection string for testing:
320+
321+
```bash
322+
SFCC_APP_INSIGHTS_KEY=your-connection-string
323+
```
324+
325+
### What We Collect
326+
327+
- **Server lifecycle events**: When the server starts, stops, or encounters errors
328+
- **Tool usage**: Which tools are called and their execution time (not the arguments or results)
329+
- **Command metrics**: Command duration and success/failure status
330+
- **Environment info**: Platform, architecture, Node.js version, and package version
331+
332+
### What We Don't Collect
333+
334+
- **No credentials**: No API keys, passwords, or secrets
335+
- **No business data**: No product data, customer information, or site content
336+
- **No tool arguments**: No input parameters or output results from tool calls
337+
- **No file contents**: No source code, configuration files, or project data
301338

302339
## Development
303340

packages/b2c-dx-mcp/bin/dev.cmd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
@echo off
22

3+
@REM Disable telemetry in development mode to avoid polluting production data
4+
if not defined SFCC_DISABLE_TELEMETRY set SFCC_DISABLE_TELEMETRY=true
5+
36
node --conditions development --import tsx "%~dp0\dev" %*
47

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

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

8+
// Disable telemetry in development mode to avoid polluting production data
9+
process.env.SFCC_DISABLE_TELEMETRY = process.env.SFCC_DISABLE_TELEMETRY || 'true';
10+
811
// Load .env file if present (Node.js native support)
912
try {
1013
process.loadEnvFile();

packages/b2c-dx-mcp/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@
3434
"strategy": "single",
3535
"target": "./dist/commands/mcp.js"
3636
},
37-
"topicSeparator": " "
37+
"topicSeparator": " ",
38+
"telemetry": {
39+
"connectionString": "InstrumentationKey=6fcc215f-0b11-4864-ad5c-3945ae19e2f3;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/;ApplicationId=a60f17ec-265a-4dfc-b8df-03a64695697d"
40+
}
3841
},
3942
"files": [
4043
"bin",
@@ -102,6 +105,7 @@
102105
"@types/chai": "^4",
103106
"@types/mocha": "^10",
104107
"@types/node": "^22.16.5",
108+
"@types/sinon": "^21.0.0",
105109
"chai": "^4",
106110
"eslint": "^9",
107111
"eslint-config-oclif": "^6",
@@ -112,6 +116,7 @@
112116
"oclif": "^4",
113117
"prettier": "^3.6.2",
114118
"shx": "^0.3.3",
119+
"sinon": "^21.0.1",
115120
"tsx": "^4",
116121
"typescript": "^5",
117122
"typescript-eslint": "^8"

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

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@
2020
* | `--tools` | `SFCC_TOOLS` | Comma-separated individual tools to enable (case-insensitive) |
2121
* | `--allow-non-ga-tools` | `SFCC_ALLOW_NON_GA_TOOLS` | Enable experimental/non-GA tools |
2222
*
23+
* ### Environment Variables for Telemetry
24+
* | Env Variable | Description |
25+
* |--------------|-------------|
26+
* | `SF_DISABLE_TELEMETRY` | Set to `true` to disable telemetry (sf CLI standard) |
27+
* | `SFCC_DISABLE_TELEMETRY` | Set to `true` to disable telemetry |
28+
* | `SFCC_APP_INSIGHTS_KEY` | Override connection string from package.json |
29+
*
2330
* ### MRT Flags (from MrtCommand.baseFlags)
2431
* | Flag | Env Variable | Description |
2532
* |------|--------------|-------------|
@@ -152,6 +159,7 @@ import {TOOLSETS, type StartupFlags} from '../utils/index.js';
152159
* - Global flags for config, logging, and debugging
153160
* - Structured pino logging via `this.logger`
154161
* - Automatic dw.json loading via `this.resolvedConfig`
162+
* - Automatic telemetry initialization via `this.telemetry`
155163
* - `this.config` - package.json metadata and standard config paths
156164
*/
157165
export default class McpServerCommand extends BaseCommand<typeof McpServerCommand> {
@@ -247,9 +255,9 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
247255
* Main entry point - starts the MCP server.
248256
*
249257
* Execution flow:
250-
* 1. BaseCommand.init() parses flags and loads config
258+
* 1. BaseCommand.init() parses flags, loads config, and initializes telemetry
251259
* 2. Filter and validate toolsets (invalid ones are skipped with warning)
252-
* 3. Create B2CDxMcpServer instance
260+
* 3. Create B2CDxMcpServer instance with telemetry from BaseCommand
253261
* 4. Create Services via Services.fromResolvedConfig() using already-resolved config
254262
* 5. Register tools based on --toolsets and --tools flags
255263
* 6. Connect to stdio transport (JSON-RPC over stdin/stdout)
@@ -261,6 +269,7 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
261269
* - `this.flags` - Parsed flags including global flags (config, debug, log-level, etc.)
262270
* - `this.resolvedConfig` - Loaded dw.json configuration
263271
* - `this.logger` - Structured pino logger
272+
* - `this.telemetry` - Telemetry instance (auto-initialized from package.json config)
264273
*
265274
* oclif provides standard config paths via `this.config`:
266275
* - `this.config.configDir` - User config (~/.config/b2c-dx-mcp)
@@ -281,21 +290,12 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
281290
workingDirectory: this.flags['working-directory'],
282291
};
283292

284-
// TODO: Telemetry - Initialize telemetry unless disabled
285-
// if (!flags["no-telemetry"]) {
286-
// telemetry = new Telemetry({
287-
// toolsets: (startupFlags.toolsets ?? []).join(", "),
288-
// configDir,
289-
// version: this.config.version,
290-
// });
291-
// await telemetry.start();
292-
// process.stdin.on("close", (err) => {
293-
// telemetry?.sendEvent(err ? "SERVER_STOPPED_ERROR" : "SERVER_STOPPED_SUCCESS");
294-
// telemetry?.stop();
295-
// });
296-
// }
293+
// Add toolsets to telemetry attributes
294+
if (this.telemetry && startupFlags.toolsets) {
295+
this.telemetry.addAttributes({toolsets: startupFlags.toolsets.join(', ')});
296+
}
297297

298-
// Create MCP server
298+
// Create MCP server with telemetry from BaseCommand
299299
const server = new B2CDxMcpServer(
300300
{
301301
name: this.config.name,
@@ -306,6 +306,7 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
306306
resources: {},
307307
tools: {},
308308
},
309+
telemetry: this.telemetry,
309310
},
310311
);
311312

@@ -319,6 +320,13 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
319320
const transport = new StdioServerTransport();
320321
await server.connect(transport);
321322

323+
// Track server stop when stdin closes (MCP client disconnects)
324+
// Note: The 'close' event has no arguments - it's just a signal that the stream closed
325+
process.stdin.on('close', () => {
326+
this.telemetry?.sendEvent('SERVER_STOPPED');
327+
// Don't call stop() here - let finally() handle telemetry cleanup
328+
});
329+
322330
// Log startup message using the structured logger
323331
this.logger.info({version: this.config.version}, 'MCP Server running on stdio');
324332
}

0 commit comments

Comments
 (0)