Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/mcp/mcpController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { createMCPConnectionErrorHandler } from './mcpConnectionErrorHandler';
import { getMCPConfigFromVSCodeSettings } from './mcpConfig';
import { DEFAULT_TELEMETRY_APP_NAME } from '../connectionController';
import formatError from '../utils/formatError';
import { TelemetryService } from '../telemetry';
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

TelemetryService is only used as a type here, but it's imported as a value. In this codebase, type-only imports are typically written with import type (e.g., src/connectionController.ts:25). Consider switching this to a type-only import to avoid an unnecessary runtime dependency and keep imports consistent.

Suggested change
import { TelemetryService } from '../telemetry';
import type { TelemetryService } from '../telemetry';

Copilot uses AI. Check for mistakes.

export type MCPServerStartupConfig =
| 'prompt'
Expand Down Expand Up @@ -52,12 +53,14 @@ type MCPControllerConfig = {
context: vscode.ExtensionContext;
connectionController: ConnectionController;
getTelemetryAnonymousId: () => string;
telemetryService: TelemetryService;
};

export class MCPController {
private context: vscode.ExtensionContext;
private connectionController: ConnectionController;
private getTelemetryAnonymousId: () => string;
private telemetryService: TelemetryService;
private mcpConnectionManagers: MCPConnectionManager[] = [];

private didChangeEmitter = new vscode.EventEmitter<void>();
Expand All @@ -67,10 +70,12 @@ export class MCPController {
context,
connectionController,
getTelemetryAnonymousId,
telemetryService,
}: MCPControllerConfig) {
this.context = context;
this.connectionController = connectionController;
this.getTelemetryAnonymousId = getTelemetryAnonymousId;
this.telemetryService = telemetryService;
}

public async activate(): Promise<void> {
Expand Down Expand Up @@ -253,6 +258,9 @@ export class MCPController {
loggers: Array.from(
new Set(['mcp', ...(configFromSettings.loggers ?? [])]),
),
telemetry: this.telemetryService.isTelemetryFeatureEnabled()
? 'enabled'
: 'disabled',
};

return UserConfigSchema.parse(vsCodeConfig);
Expand Down
1 change: 1 addition & 0 deletions src/mdbExtensionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ export default class MDBExtensionController implements vscode.Disposable {
connectionController: this._connectionController,
getTelemetryAnonymousId: (): string =>
this._connectionStorage.getUserAnonymousId(),
telemetryService: this._telemetryService,
});
}

Expand Down
4 changes: 2 additions & 2 deletions src/telemetry/telemetryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export class TelemetryService {

// Checks user settings and extension running mode
// to determine whether or not we should track telemetry.
_isTelemetryFeatureEnabled(): boolean {
isTelemetryFeatureEnabled(): boolean {
// If tests run the extension we do not track telemetry.
Comment on lines 133 to 136
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

PR description mentions passing TelemetryService.isTelemetryEnabled, but the implementation introduces/uses isTelemetryFeatureEnabled() instead. Please align the wording (or method naming) so it’s clear which API is intended and to avoid confusion for future maintainers.

Copilot uses AI. Check for mistakes.
if (this._shouldTrackTelemetry !== true) {
return false;
Expand All @@ -152,7 +152,7 @@ export class TelemetryService {
}

_segmentAnalyticsTrack(segmentProperties: SegmentProperties): void {
if (!this._isTelemetryFeatureEnabled()) {
if (!this.isTelemetryFeatureEnabled()) {
return;
}

Expand Down
26 changes: 25 additions & 1 deletion src/test/suite/mcp/mcpController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ suite('MCPController test suite', function () {
this.timeout(10_000);
let connectionController: ConnectionController;
let mcpController: MCPController;
let testTelemetryService: TelemetryService;

let mcpAutoStartValue: string | null | undefined;
let getConfigurationStub: SinonStub;
Expand All @@ -72,7 +73,7 @@ suite('MCPController test suite', function () {
beforeEach(() => {
const extensionContext = new ExtensionContextStub();
const testStorageController = new StorageController(extensionContext);
const testTelemetryService = new TelemetryService(
testTelemetryService = new TelemetryService(
testStorageController,
extensionContext,
);
Expand All @@ -86,6 +87,7 @@ suite('MCPController test suite', function () {
context: extensionContext,
connectionController: connectionController,
getTelemetryAnonymousId: (): string => '1FOO',
telemetryService: testTelemetryService,
});

// GetConfiguration Stubs
Expand Down Expand Up @@ -839,6 +841,28 @@ suite('MCPController test suite', function () {
});
});

suite('MCP server telemetry configuration', function () {
test('passes telemetry "enabled" to MCP server config when telemetry is enabled', function () {
sandbox
.stub(testTelemetryService, 'isTelemetryFeatureEnabled')
.returns(true);
const config = (mcpController as any).getMCPServerConfig({
authorization: 'Bearer test',
});
expect(config.telemetry).to.equal('enabled');
});

test('passes telemetry "disabled" to MCP server config when telemetry is disabled', function () {
sandbox
.stub(testTelemetryService, 'isTelemetryFeatureEnabled')
.returns(false);
const config = (mcpController as any).getMCPServerConfig({
authorization: 'Bearer test',
});
expect(config.telemetry).to.equal('disabled');
});
});

suite('#openServerConfig', function () {
suite('when the server is not running', function () {
test('should notify that server is not running', async function () {
Expand Down
20 changes: 20 additions & 0 deletions src/test/suite/mdbExtensionController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,26 @@ suite('MDBExtensionController Test Suite', function () {
});
});

suite('MCP server telemetry', function () {
test('MCPController uses the same telemetry service as the extension controller', function () {
const extensionController = mdbTestExtension.testExtensionController;
expect(extensionController._mcpController['telemetryService']).to.equal(
extensionController._telemetryService,
);
});

test('MCP server is configured with telemetry disabled when extension telemetry is disabled', function () {
const extensionController = mdbTestExtension.testExtensionController;
// In test mode shouldTrackTelemetry is false, so telemetry is disabled
expect(extensionController._telemetryService.isTelemetryFeatureEnabled())
.to.be.false;
const mcpServerConfig = (
extensionController._mcpController as any
).getMCPServerConfig({ authorization: 'Bearer test' });
expect(mcpServerConfig.telemetry).to.equal('disabled');
});
});

suite('when not connected', function () {
let showErrorMessageStub: SinonSpy;

Expand Down
2 changes: 1 addition & 1 deletion src/test/suite/telemetry/telemetryService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ suite('Telemetry Controller Test Suite', function () {
sandbox.stub(vscode.window, 'showInformationMessage');
sandbox.replace(
testTelemetryService,
'_isTelemetryFeatureEnabled',
'isTelemetryFeatureEnabled',
sandbox.fake.returns(true),
);
});
Expand Down
Loading