Skip to content

Commit e75c0a3

Browse files
committed
Add MCP config management
1 parent 9f2003a commit e75c0a3

File tree

10 files changed

+342
-74
lines changed

10 files changed

+342
-74
lines changed

β€ŽREADME.mdβ€Ž

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,20 @@
1-
# Digma Continuous Feedback
1+
# Digma agentic AI SRE
22

3-
Digma is VS Code extension for automatically identifying and fixing performance issues in your code. It enables developers to find the root cause of bottlenecks, scaling problems and query issues in the code.
4-
5-
## Example of issues Digma detects automatically
6-
7-
- Bottlenecks and concurrency anti-patterns
8-
- Query inefficiencies
9-
- Scaling problems
10-
- N+1 Selects
11-
- Performance regressions
3+
Autonomous identification, root cause analysis and remediation of code and infrastructure issues
124

135
For more info check out our [website](https://digma.ai)
146

157
## Extension settings
168

179
This extension contributes the following settings:
1810

19-
| Key | Type | Default | Description |
20-
| ---------------- | ------ | ------------------------ | ------------------- |
21-
| `digma.apiUrl` | string | `https://localhost:5051` | Digma API URL |
22-
| `digma.apiToken` | string | - | Digma API token |
23-
| `digma.login` | string | - | Digma user login |
24-
| `digma.password` | string | - | Digma user password |
11+
| Key | Type | Default | Description |
12+
| ------------------------- | ------- | ------------------------ | --------------------------- |
13+
| `digma.url` | string | `https://localhost:5051` | API URL |
14+
| `digma.token` | string | - | API token |
15+
| `digma.login` | string | - | User login |
16+
| `digma.password` | string | - | User password |
17+
| `digma.copySettingsToMcp` | boolean | false | Copy settings to MCP server |
2518

2619
## Build
2720

β€Žpackage-lock.jsonβ€Ž

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žpackage.jsonβ€Ž

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"name": "digma",
3-
"displayName": "Digma Continuous Feedback",
4-
"description": "Code insights and Observability for OpenTelemetry. .NET, Python, more coming soon.",
5-
"version": "0.5.48",
3+
"displayName": "Digma agentic AI SRE",
4+
"description": "Autonomous identification, root cause analysis and remediation of code and infrastructure issues",
5+
"version": "0.6.0",
66
"publisher": "digma",
77
"icon": "digma.png",
88
"engines": {
@@ -73,23 +73,35 @@
7373
"contributes": {
7474
"configuration": {
7575
"properties": {
76-
"digma.apiUrl": {
76+
"digma.url": {
7777
"type": "string",
78+
"title": "URL",
7879
"default": "https://localhost:5051",
79-
"description": "Digma API URL"
80+
"description": "API URL",
81+
"order": 0
8082
},
81-
"digma.apiToken": {
83+
"digma.token": {
8284
"type": "string",
8385
"default": "",
84-
"description": "Digma API token"
86+
"description": "API token",
87+
"order": 1
8588
},
8689
"digma.login": {
8790
"type": "string",
88-
"description": "Digma user login"
91+
"description": "User login",
92+
"order": 2
8993
},
9094
"digma.password": {
9195
"type": "string",
92-
"description": "Digma user password"
96+
"description": "User password",
97+
"order": 3
98+
},
99+
"digma.copySettingsToMcp": {
100+
"type": "boolean",
101+
"title": "Copy settings to MCP",
102+
"default": false,
103+
"description": "Copy settings to MCP server",
104+
"order": 4
93105
}
94106
}
95107
}

β€Žsrc/SettingsManager.tsβ€Ž

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import vscode from "vscode";
2+
import type { PackageJSON } from "./types";
3+
4+
export interface SettingDefinition {
5+
key: string;
6+
secret: boolean;
7+
}
8+
9+
export type Settings = Record<string, string | undefined>;
10+
11+
export class SettingsManager {
12+
private static readonly SETTING_DEFINITIONS: SettingDefinition[] = [
13+
{ key: "url", secret: false },
14+
{ key: "token", secret: false },
15+
{ key: "login", secret: false },
16+
{ key: "password", secret: false },
17+
{ key: "copySettingsToMcp", secret: false }
18+
];
19+
20+
private context: vscode.ExtensionContext;
21+
private extensionName: string;
22+
23+
constructor(context: vscode.ExtensionContext) {
24+
this.context = context;
25+
this.extensionName = (context.extension.packageJSON as PackageJSON).name;
26+
}
27+
28+
async getSetting<T>(key: string): Promise<T | undefined> {
29+
const settingDef = SettingsManager.SETTING_DEFINITIONS.find(
30+
(s) => s.key === key
31+
);
32+
33+
if (!settingDef) {
34+
throw new Error(`Unknown setting: ${key}`);
35+
}
36+
37+
if (settingDef.secret) {
38+
const value = await this.context.secrets.get(
39+
`${this.extensionName}.${key}`
40+
);
41+
return value ? (JSON.parse(value) as T) : undefined;
42+
} else {
43+
const config = vscode.workspace.getConfiguration(this.extensionName);
44+
return config.get<T>(key);
45+
}
46+
}
47+
48+
async setSetting(key: string, value: unknown): Promise<void> {
49+
const settingDef = SettingsManager.SETTING_DEFINITIONS.find(
50+
(s) => s.key === key
51+
);
52+
53+
if (!settingDef) {
54+
throw new Error(`Unknown setting: ${key}`);
55+
}
56+
57+
if (settingDef.secret) {
58+
await this.context.secrets.store(
59+
`${this.extensionName}.${key}`,
60+
JSON.stringify(value)
61+
);
62+
} else {
63+
const config = vscode.workspace.getConfiguration(this.extensionName);
64+
await config.update(key, value);
65+
}
66+
}
67+
}

β€Žsrc/extension.tsβ€Ž

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import express from "express";
22
import net from "net";
33
import vscode from "vscode";
44
import { DigmaApiClient } from "./api/DigmaApiClient";
5-
import { getExtensionSettings } from "./settings";
5+
import { registerMcpServer } from "./registerMcpServer";
6+
import { SettingsManager } from "./SettingsManager";
67
import type { PackageJSON } from "./types";
78
import { attachIncidentFileToChatContext } from "./uris/handlers/context";
89
import { UriRouter } from "./uris/UriRouter";
@@ -11,6 +12,7 @@ const START_PORT = 33100;
1112
const END_PORT = 33199;
1213

1314
let digmaClient: DigmaApiClient | null = null;
15+
// let mcpServerDisposable: vscode.Disposable | null = null;
1416

1517
const findAvailablePort = async (
1618
start: number,
@@ -37,35 +39,22 @@ const isPortAvailable = (port: number): Promise<boolean> => {
3739
async function initializeClient(
3840
context: vscode.ExtensionContext
3941
): Promise<void> {
40-
const { apiUrl, apiToken, login, password } = getExtensionSettings(context);
42+
const settingsManager = new SettingsManager(context);
4143

42-
if (!apiUrl) {
43-
vscode.window.showErrorMessage(
44-
"Digma API URL is not configured. Please set it in the extension settings."
45-
);
46-
return;
47-
}
48-
49-
if (!apiToken) {
50-
vscode.window.showWarningMessage(
51-
"API token is not configured. Please set it in the extension settings."
52-
);
53-
return;
54-
}
44+
const url = await settingsManager.getSetting<string>("url");
45+
const token = await settingsManager.getSetting<string>("token");
46+
const login = await settingsManager.getSetting<string>("login");
47+
const password = await settingsManager.getSetting<string>("password");
5548

56-
if (!login || !password) {
57-
vscode.window.showErrorMessage(
58-
"Digma login credentials are not configured. Please set them in the extension settings."
59-
);
49+
if (!token || !url || !login || !password) {
6050
return;
6151
}
6252

6353
// Initialize the client
64-
digmaClient = new DigmaApiClient(apiUrl, apiToken);
54+
digmaClient = new DigmaApiClient(url, token);
6555

6656
try {
67-
await digmaClient.login({ username: login, password });
68-
vscode.window.showInformationMessage("Successfully logged in to Digma.");
57+
await digmaClient.login({ username: login, password: password });
6958
} catch (error) {
7059
// eslint-disable-next-line no-console
7160
console.error("Digma login failed:", error);
@@ -92,9 +81,36 @@ export async function activate(context: vscode.ExtensionContext) {
9281
const configChangeListener = vscode.workspace.onDidChangeConfiguration(
9382
async (event) => {
9483
const extensionName = (context.extension.packageJSON as PackageJSON).name;
95-
if (event.affectsConfiguration(extensionName)) {
84+
if (
85+
event.affectsConfiguration(`${extensionName}.url`) ||
86+
event.affectsConfiguration(`${extensionName}.token`) ||
87+
event.affectsConfiguration(`${extensionName}.login`) ||
88+
event.affectsConfiguration(`${extensionName}.password`)
89+
) {
90+
const settingsManager = new SettingsManager(context);
91+
await settingsManager.setSetting("copySettingsToMcp", false);
92+
9693
await initializeClient(context);
9794
}
95+
96+
// Update MCP server configuration
97+
if (event.affectsConfiguration(`${extensionName}.copySettingsToMcp`)) {
98+
const settingsManager = new SettingsManager(context);
99+
const url = await settingsManager.getSetting<string>("url");
100+
const token = await settingsManager.getSetting<string>("token");
101+
const copySettingsToMcp =
102+
await settingsManager.getSetting<boolean>("copySettingsToMcp");
103+
104+
if (copySettingsToMcp && url && token) {
105+
try {
106+
registerMcpServer(url, token);
107+
} catch (error) {
108+
// eslint-disable-next-line no-console
109+
console.error("MCP server registration failed:", error);
110+
vscode.window.showErrorMessage("Failed to register MCP server.");
111+
}
112+
}
113+
}
98114
}
99115
);
100116

@@ -165,6 +181,11 @@ export function deactivate() {
165181
if (digmaClient) {
166182
digmaClient = null;
167183
}
184+
185+
// if (mcpServerDisposable) {
186+
// mcpServerDisposable.dispose();
187+
// mcpServerDisposable = null;
188+
// }
168189
}
169190

170191
export function getDigmaClient(): DigmaApiClient {

β€Žsrc/ides/getIdeFolderUri.tsβ€Ž

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import vscode from "vscode";
2+
3+
export const getIdeFolderUri = (ideName: string): vscode.Uri | undefined => {
4+
if (
5+
!vscode.workspace.workspaceFolders ||
6+
vscode.workspace.workspaceFolders.length === 0
7+
) {
8+
throw new Error("No workspace found");
9+
}
10+
11+
const workspaceFolder = vscode.workspace.workspaceFolders[0];
12+
13+
switch (ideName) {
14+
case "Visual Studio Code":
15+
return vscode.Uri.joinPath(workspaceFolder.uri, ".vscode");
16+
case "Cursor":
17+
return vscode.Uri.joinPath(workspaceFolder.uri, ".cursor");
18+
default:
19+
throw new Error(`Unsupported IDE: ${ideName}`);
20+
}
21+
};
File renamed without changes.

0 commit comments

Comments
Β (0)