Skip to content
Open
1 change: 1 addition & 0 deletions packages/mcp-provider-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export {
type Services,
type TelemetryService,
type TelemetryEvent,
type PdpEvent,
type OrgService,
type ConfigService,
type StartupFlags
Expand Down
8 changes: 8 additions & 0 deletions packages/mcp-provider-api/src/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@ export interface Services {

export interface TelemetryService {
sendEvent(eventName: string, event: TelemetryEvent): void;
sendPdpEvent(event: PdpEvent): void;
}

export type TelemetryEvent = {
[key: string]: string | number | boolean | null | undefined;
};

export type PdpEvent = {
eventName: `${string}.${string}`;
productFeatureId: `aJC${string}`;
componentId?: string;
eventVolume?: number;
};


export interface OrgService {
getAllowedOrgUsernames(): Promise<Set<string>>;
Expand Down
2 changes: 1 addition & 1 deletion packages/mcp-provider-code-analyzer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@salesforce/code-analyzer-pmd-engine": "^0.37.0",
"@salesforce/code-analyzer-regex-engine": "^0.33.0",
"@salesforce/code-analyzer-retirejs-engine": "^0.32.0",
"@salesforce/mcp-provider-api": "^0.4.1",
"@salesforce/mcp-provider-api": "^0.6.0",
"fast-xml-parser": "^5.5.3",
"zod": "^3.25.76"
},
Expand Down
3 changes: 3 additions & 0 deletions packages/mcp-provider-code-analyzer/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
export const TelemetryEventName = "code-analyzer"
export const TelemetrySource = "MCP"

// Product Feature ID for PFT (Product Feedback Telemetry) events
export const CODE_ANALYZER_PRODUCT_FEATURE_ID = "aJCEE0000000mDK4AY"

export const McpTelemetryEvents = {
ENGINE_SELECTION: 'engine_selection',
ENGINE_EXECUTION: 'engine_execution',
Expand Down
6 changes: 3 additions & 3 deletions packages/mcp-provider-code-analyzer/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ export class CodeAnalyzerMcpProvider extends McpProvider {
configFactory,
enginePluginsFactory,
telemetryService: services.getTelemetryService()
})),
}), services.getTelemetryService()),
new CodeAnalyzerDescribeRuleMcpTool(new DescribeRuleActionImpl({
configFactory,
enginePluginsFactory,
telemetryService: services.getTelemetryService()
})),
}), services.getTelemetryService()),
new CodeAnalyzerListRulesMcpTool(new ListRulesActionImpl({
configFactory,
enginePluginsFactory,
telemetryService: services.getTelemetryService()
})),
}), services.getTelemetryService()),
new CodeAnalyzerQueryResultsMcpTool(new QueryResultsActionImpl(), services.getTelemetryService()),
new GenerateXpathPromptMcpTool(new GetAstNodesActionImpl(), services.getTelemetryService()),
new CreateCustomRuleMcpTool(new CreateXpathCustomRuleActionImpl(), services.getTelemetryService())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ export class CreateCustomRuleMcpTool extends McpTool<InputArgsShape, OutputArgsS
rulesetPath: output.rulesetPath,
configPath: output.configPath
});
// Send PFT event for product analytics
this.telemetryService.sendPdpEvent({
eventName: 'codeAnalyzer.createCustomRule',
productFeatureId: Constants.CODE_ANALYZER_PRODUCT_FEATURE_ID,
componentId: CreateCustomRuleMcpTool.NAME
});
}
return {
content: [{ type: "text", text: message }],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { z } from "zod";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { McpTool, McpToolConfig, ReleaseState, Services, Toolset } from "@salesforce/mcp-provider-api";
import { McpTool, McpToolConfig, ReleaseState, Services, Toolset, TelemetryService } from "@salesforce/mcp-provider-api";
import { DescribeRuleAction, DescribeRuleActionImpl, DescribeRuleInput, DescribeRuleOutput} from "../actions/describe-rule.js";
import { CodeAnalyzerConfigFactoryImpl } from "../factories/CodeAnalyzerConfigFactory.js";
import { EnginePluginsFactoryImpl } from "../factories/EnginePluginsFactory.js";
import { getErrorMessage } from "../utils.js";
import {CodeAnalyzerRunMcpTool} from "./run_code_analyzer.js";
import * as Constants from "../constants.js";

const DESCRIPTION: string = `A tool for getting the description of a Code Analyzer rule.
This tool can return a JSON that describes the properties of a Code Analyzer rule, which may include information about
Expand Down Expand Up @@ -38,15 +39,18 @@ type OutputArgsShape = typeof outputSchema.shape;
export class CodeAnalyzerDescribeRuleMcpTool extends McpTool<InputArgsShape, OutputArgsShape> {
public static readonly NAME: string = 'describe_code_analyzer_rule';
private readonly action: DescribeRuleAction;
private readonly telemetryService?: TelemetryService;

public constructor(
action: DescribeRuleAction = new DescribeRuleActionImpl({
configFactory: new CodeAnalyzerConfigFactoryImpl(),
enginePluginsFactory: new EnginePluginsFactoryImpl()
})
}),
telemetryService?: TelemetryService
) {
super();
this.action = action;
this.telemetryService = telemetryService;
}

public getReleaseState(): ReleaseState {
Expand Down Expand Up @@ -77,6 +81,14 @@ export class CodeAnalyzerDescribeRuleMcpTool extends McpTool<InputArgsShape, Out
let output: DescribeRuleOutput;
try {
output = await this.action.exec(input);
// Send PFT event for product analytics
if (output.status === "success") {
this.telemetryService?.sendPdpEvent({
eventName: 'codeAnalyzer.describeRule',
productFeatureId: Constants.CODE_ANALYZER_PRODUCT_FEATURE_ID,
componentId: CodeAnalyzerDescribeRuleMcpTool.NAME
});
}
} catch (e) {
output = { status: getErrorMessage(e) };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ export class GenerateXpathPromptMcpTool extends McpTool<InputArgsShape, OutputAr
engine: input.engine,
language: input.language
});
// Send PFT event for product analytics
this.telemetryService.sendPdpEvent({
eventName: 'codeAnalyzer.generateXpathPrompt',
productFeatureId: Constants.CODE_ANALYZER_PRODUCT_FEATURE_ID,
componentId: 'get_ast_nodes_to_generate_xpath'
});
}
return buildToolResult(output);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import {z} from "zod";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import {McpTool, ReleaseState, McpToolConfig, Toolset} from "@salesforce/mcp-provider-api";
import {McpTool, ReleaseState, McpToolConfig, Toolset, TelemetryService} from "@salesforce/mcp-provider-api";
import {ListRulesAction, ListRulesInput, ListRulesOutput, ListRulesActionImpl} from "../actions/list-rules.js";
import {CodeAnalyzerConfigFactoryImpl} from "../factories/CodeAnalyzerConfigFactory.js";
import {EnginePluginsFactoryImpl} from "../factories/EnginePluginsFactory.js";
import {getErrorMessage} from "../utils.js";
import { isFullListSelector, makePolicyError } from "../policies.js";
import * as Constants from "../constants.js";
import {
ENGINE_NAMES,
SEVERITY_NUMBERS,
Expand Down Expand Up @@ -83,6 +84,7 @@ type OutputArgsShape = typeof outputSchema.shape;
export class CodeAnalyzerListRulesMcpTool extends McpTool<InputArgsShape, OutputArgsShape> {
public static readonly NAME: string = 'list_code_analyzer_rules';
private readonly action: ListRulesAction;
private readonly telemetryService?: TelemetryService;

/**
* Validates a selector string ensuring that each token (split on ',' and ':')
Expand Down Expand Up @@ -133,10 +135,12 @@ export class CodeAnalyzerListRulesMcpTool extends McpTool<InputArgsShape, Output
action: ListRulesAction = new ListRulesActionImpl({
configFactory: new CodeAnalyzerConfigFactoryImpl(),
enginePluginsFactory: new EnginePluginsFactoryImpl()
})
}),
telemetryService?: TelemetryService
) {
super();
this.action = action;
this.telemetryService = telemetryService;
}

public getReleaseState(): ReleaseState {
Expand Down Expand Up @@ -193,6 +197,14 @@ export class CodeAnalyzerListRulesMcpTool extends McpTool<InputArgsShape, Output
}
try {
output = await this.action.exec(input);
// Send PFT event for product analytics
if (output.status === "success") {
this.telemetryService?.sendPdpEvent({
eventName: 'codeAnalyzer.listRules',
productFeatureId: Constants.CODE_ANALYZER_PRODUCT_FEATURE_ID,
componentId: CodeAnalyzerListRulesMcpTool.NAME
});
}
} catch (e) {
output = { status: getErrorMessage(e) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ export class CodeAnalyzerQueryResultsMcpTool extends McpTool<InputArgsShape, Out
totalViolations: output.totalViolations ?? 0,
totalMatches: output.totalMatches ?? 0
});
// Send PFT event for product analytics
this.telemetryService?.sendPdpEvent({
eventName: 'codeAnalyzer.query',
productFeatureId: Constants.CODE_ANALYZER_PRODUCT_FEATURE_ID,
componentId: CodeAnalyzerQueryResultsMcpTool.NAME
});
const contentItems: { type: "text"; text: string }[] = [];
if (truncated) {
contentItems.push({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import fs from "node:fs";
import { z } from "zod";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { McpTool, McpToolConfig, ReleaseState, Services, Toolset } from "@salesforce/mcp-provider-api";
import { McpTool, McpToolConfig, ReleaseState, Services, Toolset, TelemetryService } from "@salesforce/mcp-provider-api";
import { getMessage } from "../messages.js";
import { getErrorMessage } from "../utils.js";
import { RunAnalyzerAction, RunAnalyzerActionImpl, RunInput, RunOutput } from "../actions/run-analyzer.js";
import { CodeAnalyzerListRulesMcpTool } from "./list_code_analyzer_rules.js";
import { CodeAnalyzerConfigFactoryImpl } from "../factories/CodeAnalyzerConfigFactory.js";
import { EnginePluginsFactoryImpl } from "../factories/EnginePluginsFactory.js";
import * as Constants from "../constants.js";

const MAX_ALLOWABLE_TARGET_COUNT = 10;

Expand Down Expand Up @@ -56,15 +57,18 @@ type OutputArgsShape = typeof outputSchema.shape;
export class CodeAnalyzerRunMcpTool extends McpTool<InputArgsShape, OutputArgsShape> {
public static readonly NAME: string = 'run_code_analyzer';
private readonly action: RunAnalyzerAction;
private readonly telemetryService?: TelemetryService;

public constructor(
action: RunAnalyzerAction = new RunAnalyzerActionImpl({
configFactory: new CodeAnalyzerConfigFactoryImpl(),
enginePluginsFactory: new EnginePluginsFactoryImpl()
})
}),
telemetryService?: TelemetryService
) {
super();
this.action = action;
this.telemetryService = telemetryService;
}

public getReleaseState(): ReleaseState {
Expand Down Expand Up @@ -106,6 +110,14 @@ export class CodeAnalyzerRunMcpTool extends McpTool<InputArgsShape, OutputArgsSh
}

const output: RunOutput = await this.action.exec(input);
// Send PFT event for product analytics
if (output.status === "success" || output.resultsFile) {
this.telemetryService?.sendPdpEvent({
eventName: 'codeAnalyzer.run',
productFeatureId: Constants.CODE_ANALYZER_PRODUCT_FEATURE_ID,
componentId: CodeAnalyzerRunMcpTool.NAME
});
}
return {
content: [{ type: "text", text: JSON.stringify(output) }],
structuredContent: output
Expand Down
5 changes: 5 additions & 0 deletions packages/mcp/src/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
Services as IServices,
TelemetryService,
TelemetryEvent,
PdpEvent,
OrgService,
SanitizedOrgAuthorization,
ConfigService,
Expand Down Expand Up @@ -70,4 +71,8 @@ class NoopTelemetryService implements TelemetryService {
public sendEvent(_eventName: string, _event: TelemetryEvent): void {
// no-op
}

public sendPdpEvent(_event: PdpEvent): void {
// no-op
}
}
Loading
Loading