@dynatrace-oss/dynatrace-mcp-server 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,7 +25,7 @@ Bring real-time observability data directly into your development workflow.
25
25
 
26
26
  **Work in progress**
27
27
 
28
- You can add this MCP server (using STDIO) to your MCP Client like VS Code, Claude, Cursor, Windsurf Github Copilot via the package `@dynatrace-oss/dynatrace-mcp-server`.
28
+ You can add this MCP server (using STDIO) to your MCP Client like VS Code, Claude, Cursor, Amazon Q Developer CLI, Windsurf Github Copilot via the package `@dynatrace-oss/dynatrace-mcp-server`.
29
29
 
30
30
  **VS Code**
31
31
 
@@ -79,7 +79,7 @@ This only works if the config is stored in the current workspaces, e.g., `<your-
79
79
 
80
80
  **Amazon Q Developer CLI**
81
81
 
82
- The [Amazon Q Developer CLI](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-chat.html) provides an interactive chat experience directly in your terminal. You can ask questions, get help with AWS services, troubleshoot issues, and generate code snippets without leaving your command line environment.
82
+ The [Amazon Q Developer CLI](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html) provides an interactive chat experience directly in your terminal. You can ask questions, get help with AWS services, troubleshoot issues, and generate code snippets without leaving your command line environment.
83
83
  ```json
84
84
  {
85
85
  "mcpServers": {
@@ -102,7 +102,7 @@ A **Dynatrace OAuth Client** is needed to communicate with your Dynatrace Enviro
102
102
  [creating an Oauth Client in Dynatrace](https://docs.dynatrace.com/docs/manage/identity-access-management/access-tokens-and-oauth-clients/oauth-clients),
103
103
  and set up the following environment variables in order for this MCP to work:
104
104
 
105
- * `DT_ENVIRONMENT` (string, e.g., https://abcd1234.apps.dynatrace.com) - URL to your Dynatrace Platform
105
+ * `DT_ENVIRONMENT` (string, e.g., https://abc12345.apps.dynatrace.com) - URL to your Dynatrace Platform (do not use Dynatrace classic URLs like `abc12345.live.dynatrace.com`)
106
106
  * `OAUTH_CLIENT_ID` (string, e.g., `dt0s02.SAMPLE`) - Dynatrace OAuth Client ID
107
107
  * `OAUTH_CLIENT_SECRET` (string, e.g., `dt0s02.SAMPLE.abcd1234`) - Dynatrace OAuth Client Secret
108
108
  * OAuth Client Scopes:
@@ -114,7 +114,6 @@ and set up the following environment variables in order for this MCP to work:
114
114
  * `environment-api:problems:read` - get problems
115
115
  * `environment-api:metrics:read` - read metrics
116
116
  * `environment-api:slo:read` - read SLOs
117
- * `settings:objects:read` - needed for reading ownership information and Guardians (SRG) from settings
118
117
  * `storage:buckets:read` - Read all system data stored on Grail
119
118
  * `storage:logs:read` - Read logs for reliability guardian validations
120
119
  * `storage:metrics:read` - Read metrics for reliability guardian validations
@@ -125,6 +124,9 @@ and set up the following environment variables in order for this MCP to work:
125
124
  * `storage:system:read` - Read System Data from Grail
126
125
  * `storage:user.events:read` - Read User events from Grail
127
126
  * `storage:user.sessions:read` - Read User sessions from Grail
127
+ * `settings:objects:read` - needed for reading ownership information and Guardians (SRG) from settings
128
+
129
+ **Note**: Please ensure that `settings:objects:read` is used, and *not* the similarly named scope `app-settings:objects:read`.
128
130
 
129
131
  In addition, depending on the features you use, the following variables can be configured:
130
132
 
@@ -172,9 +174,53 @@ Can you fetch recent events from our "production-cluster"
172
174
  to help identify what might be causing these deployment issues?
173
175
  ```
174
176
 
177
+ ## Troubleshooting
178
+
179
+ ### Authentication Issues
180
+
181
+ In most cases, something is wrong with the OAuth Client. Please ensure that you have added all scopes as requested above.
182
+ In addition, please ensure that your user also has all necessary permissions on your Dynatrace Environment.
183
+
184
+ In case of any problems, you can troubleshoot SSO/OAuth issues based on our [Dynatrace Developer Documentation](https://developer.dynatrace.com/develop/access-platform-apis-from-outside/#get-bearer-token-and-call-app-function) and providing the list of scopes.
185
+
186
+ It is recommended to try access the following API (which requires minimal scopes `app-engine:apps:run` and `app-engine:functions:run`):
187
+
188
+ 1. Use OAuth Client ID and Secret to retrieve a Bearer Token (only valid for a couple of minutes):
189
+ ```bash
190
+ curl --request POST 'https://sso.dynatrace.com/sso/oauth2/token' \
191
+ --header 'Content-Type: application/x-www-form-urlencoded' \
192
+ --data-urlencode 'grant_type=client_credentials' \
193
+ --data-urlencode 'client_id={your-client-id}' \
194
+ --data-urlencode 'client_secret={your-client-secret}' \
195
+ --data-urlencode 'scope=app-engine:apps:run app-engine:functions:run'
196
+ ```
197
+
198
+ 2. Use `access_token` from the response of the above call as the bearer-token in the next call:
199
+ ```bash
200
+ curl -X GET https://abc12345.apps.dynatrace.com/platform/management/v1/environment \
201
+ -H 'accept: application/json' \
202
+ -H 'Authorization: Bearer {your-bearer-token}'
203
+ ```
204
+
205
+ 3. You should retrieve a result like this:
206
+ ```json
207
+ {
208
+ "environmentId": "abc12345",
209
+ "createTime": "2023-01-01T00:10:57.123Z",
210
+ "blockTime": "2025-12-07T00:00:00Z",
211
+ "state": "ACTIVE"
212
+ }
213
+ ```
214
+
215
+
216
+ ### Problem accessing data on Grail
217
+
218
+ Grail has a dedicated section about permissions in the Dynatrace Docs. Please refer to https://docs.dynatrace.com/docs/discover-dynatrace/platform/grail/data-model/assign-permissions-in-grail for more details.
219
+
220
+
175
221
  ## Development
176
222
 
177
- For development purposes, you can use VSCode and GitHub Copilot.
223
+ For local development purposes, you can use VSCode and GitHub Copilot.
178
224
 
179
225
  First, enable Copilot for your Workspace `.vscode/settings.json`:
180
226
  ```json
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findMonitoredEntityByName = void 0;
4
+ const execute_dql_1 = require("./execute-dql");
5
+ const findMonitoredEntityByName = async (dtClient, entityName) => {
6
+ const dql = `fetch dt.entity.application | search "*${entityName}*" | fieldsAdd entity.type
7
+ | append [fetch dt.entity.service | search "*${entityName}*" | fieldsAdd entity.type]
8
+ | append [fetch dt.entity.host | search "*${entityName}*" | fieldsAdd entity.type]
9
+ | append [fetch dt.entity.process_group | search "*${entityName}*" | fieldsAdd entity.type]
10
+ | append [fetch dt.entity.cloud_application | search "*${entityName}*" | fieldsAdd entity.type]`;
11
+ const dqlResponse = await (0, execute_dql_1.executeDql)(dtClient, dql);
12
+ if (dqlResponse && dqlResponse.length > 0) {
13
+ let resp = 'The following monitored entities were found:\n';
14
+ // iterate over dqlResponse and create a string with the entity names
15
+ dqlResponse.forEach((entity) => {
16
+ if (entity) {
17
+ resp += `- Entity '${entity['entity.name']}' of type '${entity['entity.type']} has entity id '${entity.id}'\n`;
18
+ }
19
+ });
20
+ return resp;
21
+ }
22
+ else {
23
+ return 'No monitored entity found with the specified name.';
24
+ }
25
+ };
26
+ exports.findMonitoredEntityByName = findMonitoredEntityByName;
@@ -3,7 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.callAppFunction = exports.createOAuthClient = void 0;
4
4
  const http_client_1 = require("@dynatrace-sdk/http-client");
5
5
  const dt_app_1 = require("dt-app");
6
- /** Uses the provided oauth Client ID and Secret and requests a token */
6
+ /**
7
+ * Uses the provided oauth Client ID and Secret and requests a token
8
+ * @param clientId - OAuth Client ID for Dynatrace
9
+ * @param clientSecret - Oauth Client Secret for Dynatrace
10
+ * @param authUrl - SSO Authentication URL
11
+ * @param scopes - List of requested scopes
12
+ * @returns
13
+ */
7
14
  const requestToken = async (clientId, clientSecret, authUrl, scopes) => {
8
15
  const res = await fetch(authUrl, {
9
16
  method: 'POST',
@@ -17,9 +24,12 @@ const requestToken = async (clientId, clientSecret, authUrl, scopes) => {
17
24
  scope: scopes.join(' '),
18
25
  }),
19
26
  });
27
+ // check if the response was okay (HTTP 2xx) or not (HTTP 4xx or 5xx)
20
28
  if (!res.ok) {
29
+ // log the error
21
30
  console.error(`Failed to fetch token: ${res.status} ${res.statusText}`);
22
31
  }
32
+ // and return the JSON result, as it contains additional information
23
33
  return await res.json();
24
34
  };
25
35
  /** Create an Oauth Client based on clientId, clientSecret, environmentUrl and scopes */
@@ -39,8 +49,9 @@ const createOAuthClient = async (clientId, clientSecret, environmentUrl, scopes)
39
49
  console.error(`Using SSO auth URL: ${ssoAuthUrl}`);
40
50
  // try to request a token, just to verify that everything is set up correctly
41
51
  const tokenResponse = await requestToken(clientId, clientSecret, ssoAuthUrl, scopes);
42
- if (tokenResponse.error && tokenResponse.error_description) {
43
- throw new Error(`Failed to retrieve OAuth token: ${tokenResponse.error} - ${tokenResponse.error_description}`);
52
+ // in case we didn't get a token, or error / error_description / issueId is set, we throw an error
53
+ if (!tokenResponse.access_token || tokenResponse.error || tokenResponse.error_description || tokenResponse.issueId) {
54
+ throw new Error(`Failed to retrieve OAuth token (IssueId: ${tokenResponse.issueId}): ${tokenResponse.error} - ${tokenResponse.error_description}. Note: Your OAuth client is most likely not configured correctly.`);
44
55
  }
45
56
  console.error(`Successfully retrieved token from SSO!`);
46
57
  return new http_client_1._OAuthHttpClient({
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDynatraceEnv = getDynatraceEnv;
4
+ /**
5
+ * Reads and validates required environment variables for Dynatrace MCP.
6
+ * Throws an Error if validation fails.
7
+ */
8
+ function getDynatraceEnv(env = process.env) {
9
+ const oauthClient = env.OAUTH_CLIENT_ID;
10
+ const oauthClientSecret = env.OAUTH_CLIENT_SECRET;
11
+ const dtEnvironment = env.DT_ENVIRONMENT;
12
+ const slackConnectionId = env.SLACK_CONNECTION_ID || "fake-slack-connection-id";
13
+ if (!oauthClient || !oauthClientSecret || !dtEnvironment) {
14
+ throw new Error("Please set OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET and DT_ENVIRONMENT environment variables");
15
+ }
16
+ if (!dtEnvironment.startsWith("https://")) {
17
+ throw new Error("Please set DT_ENVIRONMENT to a valid Dynatrace Environment URL (e.g., https://<environment-id>.apps.dynatrace.com)");
18
+ }
19
+ if (!dtEnvironment.includes("apps.dynatrace.com") && !dtEnvironment.includes("apps.dynatracelabs.com")) {
20
+ throw new Error("Please set DT_ENVIRONMENT to a valid Dynatrace Platform Environment URL (e.g., https://<environment-id>.apps.dynatrace.com)");
21
+ }
22
+ return { oauthClient, oauthClientSecret, dtEnvironment, slackConnectionId };
23
+ }
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const getDynatraceEnv_1 = require("./getDynatraceEnv");
4
+ describe("getDynatraceEnv", () => {
5
+ const baseEnv = {
6
+ OAUTH_CLIENT_ID: "dt0s02.SAMPLE",
7
+ OAUTH_CLIENT_SECRET: "dt0s02.SAMPLE.abcd1234",
8
+ DT_ENVIRONMENT: "https://abc123.apps.dynatrace.com",
9
+ SLACK_CONNECTION_ID: "slack-conn-id"
10
+ };
11
+ it("returns all required values when environment is valid", () => {
12
+ const env = { ...baseEnv };
13
+ const result = (0, getDynatraceEnv_1.getDynatraceEnv)(env);
14
+ expect(result).toEqual({
15
+ oauthClient: env.OAUTH_CLIENT_ID,
16
+ oauthClientSecret: env.OAUTH_CLIENT_SECRET,
17
+ dtEnvironment: env.DT_ENVIRONMENT,
18
+ slackConnectionId: env.SLACK_CONNECTION_ID
19
+ });
20
+ });
21
+ it("uses default slackConnectionId if not set", () => {
22
+ const env = { ...baseEnv, SLACK_CONNECTION_ID: undefined };
23
+ const result = (0, getDynatraceEnv_1.getDynatraceEnv)(env);
24
+ expect(result.slackConnectionId).toBe("fake-slack-connection-id");
25
+ });
26
+ it("throws if OAUTH_CLIENT_ID is missing", () => {
27
+ const env = { ...baseEnv, OAUTH_CLIENT_ID: undefined };
28
+ expect(() => (0, getDynatraceEnv_1.getDynatraceEnv)(env)).toThrow(/OAUTH_CLIENT_ID/);
29
+ });
30
+ it("throws if OAUTH_CLIENT_SECRET is missing", () => {
31
+ const env = { ...baseEnv, OAUTH_CLIENT_SECRET: undefined };
32
+ expect(() => (0, getDynatraceEnv_1.getDynatraceEnv)(env)).toThrow(/OAUTH_CLIENT_SECRET/);
33
+ });
34
+ it("throws if DT_ENVIRONMENT is missing", () => {
35
+ const env = { ...baseEnv, DT_ENVIRONMENT: undefined };
36
+ expect(() => (0, getDynatraceEnv_1.getDynatraceEnv)(env)).toThrow(/DT_ENVIRONMENT/);
37
+ });
38
+ it("throws if DT_ENVIRONMENT does not start with https://", () => {
39
+ const env = { ...baseEnv, DT_ENVIRONMENT: "http://abc123.apps.dynatrace.com" };
40
+ expect(() => (0, getDynatraceEnv_1.getDynatraceEnv)(env)).toThrow(/https:\/\//);
41
+ });
42
+ it("throws if DT_ENVIRONMENT is not a Dynatrace Platform URL (any URL)", () => {
43
+ const env = { ...baseEnv, DT_ENVIRONMENT: "https://abc123.example.com" };
44
+ expect(() => (0, getDynatraceEnv_1.getDynatraceEnv)(env)).toThrow(/Dynatrace Platform Environment URL/);
45
+ });
46
+ it("throws if DT_ENVIRONMENT is not a Dynatrace Platform URL (contains live)", () => {
47
+ const env = { ...baseEnv, DT_ENVIRONMENT: "https://abc123.live.dynatrace.com" };
48
+ expect(() => (0, getDynatraceEnv_1.getDynatraceEnv)(env)).toThrow(/Dynatrace Platform Environment URL/);
49
+ });
50
+ it("accepts DT_ENVIRONMENT with apps.dynatracelabs.com", () => {
51
+ const env = { ...baseEnv, DT_ENVIRONMENT: "https://xyz789.apps.dynatracelabs.com" };
52
+ expect(() => (0, getDynatraceEnv_1.getDynatraceEnv)(env)).not.toThrow();
53
+ });
54
+ it("accepts DT_ENVIRONMENT with apps.dynatrace.com", () => {
55
+ const env = { ...baseEnv, DT_ENVIRONMENT: "https://env123.apps.dynatrace.com" };
56
+ expect(() => (0, getDynatraceEnv_1.getDynatraceEnv)(env)).not.toThrow();
57
+ });
58
+ });
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const client_platform_management_service_1 = require("@dynatrace-sdk/client-platform-management-service");
5
+ const shared_errors_1 = require("@dynatrace-sdk/shared-errors");
5
6
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
7
  const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
7
8
  const dotenv_1 = require("dotenv");
@@ -19,6 +20,8 @@ const update_workflow_1 = require("./capabilities/update-workflow");
19
20
  const get_vulnerability_details_1 = require("./capabilities/get-vulnerability-details");
20
21
  const execute_dql_1 = require("./capabilities/execute-dql");
21
22
  const send_slack_message_1 = require("./capabilities/send-slack-message");
23
+ const find_monitored_entity_by_name_1 = require("./capabilities/find-monitored-entity-by-name");
24
+ const getDynatraceEnv_1 = require("./getDynatraceEnv");
22
25
  (0, dotenv_1.config)();
23
26
  let scopes = [
24
27
  'app-engine:apps:run', // needed for environmentInformationClient
@@ -54,15 +57,15 @@ if (process.env.USE_WORKFLOWS) {
54
57
  }
55
58
  const main = async () => {
56
59
  // read Environment variables
57
- const oauthClient = process.env.OAUTH_CLIENT_ID;
58
- const oauthClientSecret = process.env.OAUTH_CLIENT_SECRET;
59
- const dtEnvironment = process.env.DT_ENVIRONMENT;
60
- const slackConnectionId = process.env.SLACK_CONNECTION_ID || "fake-slack-connection-id";
61
- // ensure oauthClient and dtEnvironment are set
62
- if (!oauthClient || !oauthClientSecret || !dtEnvironment) {
63
- console.error("Please set OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET and DT_ENVIRONMENT environment variables");
60
+ let dynatraceEnv;
61
+ try {
62
+ dynatraceEnv = (0, getDynatraceEnv_1.getDynatraceEnv)();
63
+ }
64
+ catch (err) {
65
+ console.error(err.message);
64
66
  process.exit(1);
65
67
  }
68
+ const { oauthClient, oauthClientSecret, dtEnvironment, slackConnectionId } = dynatraceEnv;
66
69
  // create an oauth-client
67
70
  const dtClient = await (0, dynatrace_clients_1.createOAuthClient)(oauthClient, oauthClientSecret, dtEnvironment, scopes);
68
71
  console.error("Starting Dynatrace MCP Server...");
@@ -74,7 +77,7 @@ const main = async () => {
74
77
  tools: {},
75
78
  },
76
79
  });
77
- // quick abstraction/wrapper to make it easier to reply with text
80
+ // quick abstraction/wrapper to make it easier for tools to reply text instead of JSON
78
81
  const tool = (name, description, paramsSchema, cb) => {
79
82
  const wrappedCb = async (args) => {
80
83
  try {
@@ -84,6 +87,24 @@ const main = async () => {
84
87
  };
85
88
  }
86
89
  catch (error) {
90
+ // check if it's an error originating from the Dynatrace SDK / API Gateway and provide an appropriate message to the user
91
+ if ((0, shared_errors_1.isClientRequestError)(error)) {
92
+ const e = error;
93
+ let additionalErrorInformation = '';
94
+ if (e.response.status == 403) {
95
+ additionalErrorInformation = 'Note: Your user or service-user is most likely lacking the necessary permissions/scopes for this API Call.';
96
+ }
97
+ return {
98
+ content: [{
99
+ type: "text",
100
+ text: `Client Request Error: ${e.message} with HTTP status: ${e.response.status}. ${additionalErrorInformation} (body: ${JSON.stringify(e.body)})`
101
+ }
102
+ ],
103
+ isError: true,
104
+ };
105
+ }
106
+ // else: We don't know what kind of error happened - best-case we can provide error.message
107
+ console.log(error);
87
108
  return {
88
109
  content: [{ type: "text", text: `Error: ${error.message}` }],
89
110
  isError: true,
@@ -189,6 +210,12 @@ const main = async () => {
189
210
  resp += `Tell the user to access the link ${dtEnvironment}/ui/apps/dynatrace.davis.problems/problem/${result.problemId} to get more insights into the problem.\n`;
190
211
  return resp;
191
212
  });
213
+ tool("find_entity_by_name", "Get the entityId of a monitored entity based on the name of the entity on Dynatrace", {
214
+ entityName: zod_1.z.string()
215
+ }, async ({ entityName }) => {
216
+ const entityResponse = await (0, find_monitored_entity_by_name_1.findMonitoredEntityByName)(dtClient, entityName);
217
+ return entityResponse;
218
+ });
192
219
  tool("get_entity_details", "Get details of a monitored entity based on the entityId on Dynatrace", {
193
220
  entityId: zod_1.z.string().optional()
194
221
  }, async ({ entityId }) => {
@@ -222,13 +249,26 @@ const main = async () => {
222
249
  const logs = await (0, get_logs_for_entity_1.getLogsForEntity)(dtClient, entityName);
223
250
  return `Logs:\n${JSON.stringify(logs?.map(logLine => logLine ? logLine.content : 'Empty log'))}`;
224
251
  });
225
- tool("verify_dql", "Verify a DQL statement on Dynatrace", {
252
+ tool("verify_dql", "Verify a Dynatrace Query Language (DQL) statement on Dynatrace GRAIL before executing it. This is useful to ensure that the DQL statement is valid and can be executed without errors.", {
226
253
  dqlStatement: zod_1.z.string()
227
254
  }, async ({ dqlStatement }) => {
228
255
  const response = await (0, execute_dql_1.verifyDqlStatement)(dtClient, dqlStatement);
229
- return `Parsing DQL Statement resulted in: ${JSON.stringify(response)}`;
256
+ let resp = 'DQL Statement Verification:\n';
257
+ if (response.notifications && response.notifications.length > 0) {
258
+ resp += `Please consider the following notifications for adapting the your DQL statement:\n`;
259
+ response.notifications.forEach((notification) => {
260
+ resp += `* ${notification.severity}: ${notification.message}\n`;
261
+ });
262
+ }
263
+ if (response.valid) {
264
+ resp += `The DQL statement is valid - you can use the "execute_dql" tool.\n`;
265
+ }
266
+ else {
267
+ resp += `The DQL statement is invalid. Please adapt your statement.\n`;
268
+ }
269
+ return resp;
230
270
  });
231
- tool("execute_dql", "Get Logs, Metrics, Spans, Events from Dynatrace by executing a DQL statement. Please use verify_dql tool before you execute a DQL statement.", {
271
+ tool("execute_dql", 'Get Logs, Metrics, Spans or Events from Dynatrace GRAIL by executing a Dynatrace Query Language (DQL) statement. Always use "verify_dql" tool before you execute a DQL statement. A valid statement looks like this: "fetch [logs, metrics, spans, events] | filter <some-filter> | summarize count(), by:{some-fields}. Adapt filters for certain attributes: `traceId` could be `trace_id` or `trace.id`.', {
232
272
  dqlStatement: zod_1.z.string()
233
273
  }, async ({ dqlStatement }) => {
234
274
  const response = await (0, execute_dql_1.executeDql)(dtClient, dqlStatement);
@@ -1 +1 @@
1
- {"root":["../src/dynatrace-clients.ts","../src/index.ts","../src/capabilities/create-workflow-for-problem-notification.ts","../src/capabilities/execute-dql.ts","../src/capabilities/get-events-for-cluster.ts","../src/capabilities/get-logs-for-entity.ts","../src/capabilities/get-monitored-entity-details.ts","../src/capabilities/get-ownership-information.ts","../src/capabilities/get-problem-details.ts","../src/capabilities/get-vulnerability-details.ts","../src/capabilities/list-problems.ts","../src/capabilities/list-vulnerabilities.ts","../src/capabilities/send-slack-message.ts","../src/capabilities/update-workflow.ts"],"version":"5.8.2"}
1
+ {"root":["../src/dynatrace-clients.ts","../src/getDynatraceEnv.test.ts","../src/getDynatraceEnv.ts","../src/index.ts","../src/capabilities/create-workflow-for-problem-notification.ts","../src/capabilities/execute-dql.ts","../src/capabilities/find-monitored-entity-by-name.ts","../src/capabilities/get-events-for-cluster.ts","../src/capabilities/get-logs-for-entity.ts","../src/capabilities/get-monitored-entity-details.ts","../src/capabilities/get-ownership-information.ts","../src/capabilities/get-problem-details.ts","../src/capabilities/get-vulnerability-details.ts","../src/capabilities/list-problems.ts","../src/capabilities/list-vulnerabilities.ts","../src/capabilities/send-slack-message.ts","../src/capabilities/update-workflow.ts"],"version":"5.8.2"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynatrace-oss/dynatrace-mcp-server",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Model Context Protocol (MCP) server for Dynatrace",
5
5
  "keywords": [
6
6
  "Dynatrace",
@@ -36,7 +36,8 @@
36
36
  "scripts": {
37
37
  "build": "tsc --build",
38
38
  "prepare": "npm run build",
39
- "watch": "tsc --watch"
39
+ "watch": "tsc --watch",
40
+ "test": "jest"
40
41
  },
41
42
  "author": "Dynatrace",
42
43
  "license": "MIT",
@@ -45,13 +46,17 @@
45
46
  "@dynatrace-sdk/client-classic-environment-v2": "^3.6.8",
46
47
  "@dynatrace-sdk/client-platform-management-service": "^1.6.3",
47
48
  "@dynatrace-sdk/client-query": "^1.18.1",
49
+ "@dynatrace-sdk/shared-errors": "^1.0.0",
48
50
  "@modelcontextprotocol/sdk": "^1.8.0",
49
51
  "dotenv": "^16.4.7",
50
52
  "dt-app": "^0.140.1",
51
53
  "zod-to-json-schema": "^3.24.5"
52
54
  },
53
55
  "devDependencies": {
56
+ "@types/jest": "^30.0.0",
54
57
  "@types/node": "^22",
58
+ "jest": "^30.0.0",
59
+ "ts-jest": "^29.4.0",
55
60
  "ts-node": "^10.9.2",
56
61
  "typescript": "^5.6.2"
57
62
  }