@dynatrace-oss/dynatrace-mcp-server 1.5.0-beta.1 → 1.5.0-beta.2

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
@@ -43,8 +43,26 @@ Furthermore, you need to configure the URL to a Dynatrace environment:
43
43
 
44
44
  - `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`)
45
45
 
46
+ Authentication will be handled via Authorization Code Flow in your browser, you don't need to define a Platform Token nor an OAuth Client to get started.
47
+
46
48
  Once you are done, we recommend looking into [example prompts](#-example-prompts-), like `Get all details of the entity 'my-service'` or `Show me error logs`. Please mind that these prompts lead to executing DQL statements which may incur [costs](#costs) in accordance to your licence.
47
49
 
50
+ **VSCode**
51
+
52
+ ```json
53
+ {
54
+ "servers": {
55
+ "npx-dynatrace-mcp-server": {
56
+ "command": "npx",
57
+ "args": ["-y", "@dynatrace-oss/dynatrace-mcp-server@latest"],
58
+ "env": {
59
+ "DT_ENVIRONMENT": "https://abc12345.apps.dynatrace.com"
60
+ }
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
48
66
  ## Architecture
49
67
 
50
68
  ![Architecture](https://github.com/dynatrace-oss/dynatrace-mcp/blob/main/assets/dynatrace-mcp-arch.png?raw=true)
@@ -124,22 +142,6 @@ We recommend to always set it up for your current workspace instead of using it
124
142
 
125
143
  **VS Code**
126
144
 
127
- ```json
128
- {
129
- "servers": {
130
- "npx-dynatrace-mcp-server": {
131
- "command": "npx",
132
- "cwd": "${workspaceFolder}",
133
- "args": ["-y", "@dynatrace-oss/dynatrace-mcp-server@latest"],
134
- "envFile": "${workspaceFolder}/.env"
135
- }
136
- }
137
- }
138
- ```
139
-
140
- Please note: In this config, [the `${workspaceFolder}` variable](https://code.visualstudio.com/docs/reference/variables-reference#_predefined-variables) is used.
141
- This only works if the config is stored in the current workspaces, e.g., `<your-repo>/.vscode/mcp.json`. Alternatively, this can also be stored in user-settings, and you can define `env` as follows:
142
-
143
145
  ```json
144
146
  {
145
147
  "servers": {
@@ -147,7 +149,7 @@ This only works if the config is stored in the current workspaces, e.g., `<your-
147
149
  "command": "npx",
148
150
  "args": ["-y", "@dynatrace-oss/dynatrace-mcp-server@latest"],
149
151
  "env": {
150
- "DT_ENVIRONMENT": ""
152
+ "DT_ENVIRONMENT": "https://abc12345.apps.dynatrace.com"
151
153
  }
152
154
  }
153
155
  }
@@ -163,7 +165,7 @@ This only works if the config is stored in the current workspaces, e.g., `<your-
163
165
  "command": "npx",
164
166
  "args": ["-y", "@dynatrace-oss/dynatrace-mcp-server@latest"],
165
167
  "env": {
166
- "DT_ENVIRONMENT": ""
168
+ "DT_ENVIRONMENT": "https://abc12345.apps.dynatrace.com"
167
169
  }
168
170
  }
169
171
  }
@@ -181,7 +183,7 @@ The [Amazon Q Developer CLI](https://docs.aws.amazon.com/amazonq/latest/qdevelop
181
183
  "command": "npx",
182
184
  "args": ["-y", "@dynatrace-oss/dynatrace-mcp-server@latest"],
183
185
  "env": {
184
- "DT_ENVIRONMENT": ""
186
+ "DT_ENVIRONMENT": "https://abc12345.apps.dynatrace.com"
185
187
  }
186
188
  }
187
189
  }
@@ -201,7 +203,7 @@ The [Amazon Kiro](https://kiro.dev/) is an agentic IDE that helps you do your be
201
203
  "command": "npx",
202
204
  "args": ["-y", "@dynatrace-oss/dynatrace-mcp-server@latest"],
203
205
  "env": {
204
- "DT_ENVIRONMENT": ""
206
+ "DT_ENVIRONMENT": "https://abc12345.apps.dynatrace.com"
205
207
  }
206
208
  }
207
209
  }
@@ -219,10 +221,11 @@ Using `gemini` CLI directly (recommended):
219
221
  ```bash
220
222
  gemini extensions install https://github.com/dynatrace-oss/dynatrace-mcp
221
223
  export DT_PLATFORM_TOKEN=... # optional
222
- export DT_ENVIRONMENT=https://...
223
224
  ```
224
225
 
225
- and verify that the server is running via
226
+ The command will ask for the value Dynatrace Environment.
227
+
228
+ Verify that the server is running via
226
229
 
227
230
  ```bash
228
231
  gemini mcp list
@@ -237,7 +240,7 @@ Or manually in your `~/.gemini/settings.json` or `.gemini/settings.json`:
237
240
  "command": "npx",
238
241
  "args": ["@dynatrace-oss/dynatrace-mcp-server@latest"],
239
242
  "env": {
240
- "DT_ENVIRONMENT": ""
243
+ "DT_ENVIRONMENT": "https://abc12345.apps.dynatrace.com"
241
244
  },
242
245
  "timeout": 30000,
243
246
  "trust": false
@@ -325,7 +328,7 @@ When just providing `DT_ENVIRONMENT`, the local MCP server will try to open a br
325
328
 
326
329
  For more information about the other authentication methods, please have a look at the documentation about
327
330
  [creating a Platform Token in Dynatrace](https://docs.dynatrace.com/docs/manage/identity-access-management/access-tokens-and-oauth-clients/platform-tokens), as well as
328
- [creating an OAuth Client in Dynatrace](https://docs.dynatrace.com/docs/manage/identity-access-management/access-tokens-and-oauth-clients/oauth-clients) for advanced scenarios.
331
+ [creating an OAuth Client in Dynatrace](https://docs.dynatrace.com/docs/manage/identity-access-management/access-tokens-and-oauth-clients/oauth-clients) for advanced scenarios (service-users, backend-to-backend communication).
329
332
 
330
333
  In addition, depending on the features you use, the following variables can be configured:
331
334
 
@@ -338,6 +341,7 @@ The MCP server honors system proxy settings for corporate environments:
338
341
  - `https_proxy` or `HTTPS_PROXY` (optional, string, e.g., `http://proxy.example.com:8080`) - Proxy server URL for HTTPS requests
339
342
  - `http_proxy` or `HTTP_PROXY` (optional, string, e.g., `http://proxy.example.com:8080`) - Proxy server URL for HTTP requests
340
343
  - `no_proxy` or `NO_PROXY` (optional, string, e.g., `localhost,127.0.0.1,.local`) - Comma-separated list of hostnames or domains that should bypass the proxy
344
+ - `NODE_EXTRA_CA_CERTS` (optional, string, e.g., `C:\some-path\certificate.pem`) - When set, the well known "root" CAs (like VeriSign) will be extended with the extra certificates
341
345
 
342
346
  **Note:** The `no_proxy` environment variable is currently logged for informational purposes but not fully enforced by the underlying HTTP client. If you need to bypass the proxy for specific hosts, consider configuring your proxy server to handle these exclusions.
343
347
 
package/dist/index.js CHANGED
@@ -521,7 +521,7 @@ const main = async () => {
521
521
  // Register the execute_dql tool with MCP App UI support.
522
522
  registerAppTool(server, 'execute_dql', {
523
523
  title: 'Execute DQL',
524
- description: 'Get data like Logs, Metrics, Spans, Events, or Entity Data from Dynatrace GRAIL by executing a Dynatrace Query Language (DQL) statement. ' +
524
+ description: 'Get data like Logs, Metrics, Spans, Events, or Entity Data from Dynatrace Grail by executing a Dynatrace Query Language (DQL) statement. ' +
525
525
  'Use the "generate_dql_from_natural_language" tool upfront to generate or refine a DQL statement based on your request. ' +
526
526
  'To learn about possible fields available for filtering, use the query "fetch dt.semantic_dictionary.models | filter data_object == \\"logs\\""',
527
527
  inputSchema: {
@@ -565,17 +565,20 @@ const main = async () => {
565
565
  if (!response) {
566
566
  return 'DQL execution failed or returned no result.';
567
567
  }
568
- let result = `šŸ“Š **DQL Query Results**\n\n`;
569
- // Budget warning comes first if present
568
+ // Build warnings array for structured metadata
569
+ const warnings = [];
570
570
  if (response.budgetWarning) {
571
- result += `${response.budgetWarning}\n\n`;
571
+ warnings.push(response.budgetWarning);
572
572
  }
573
+ // Build human-readable text result
574
+ let result = `šŸ“Š **DQL Query Results**\n\n`;
573
575
  // Cost and Performance Information
574
576
  if (response.scannedRecords !== undefined) {
575
577
  result += `- **Scanned Records:** ${response.scannedRecords.toLocaleString()}\n`;
576
578
  }
577
579
  if (response.scannedBytes !== undefined) {
578
- const scannedGB = response.scannedBytes / (1000 * 1000 * 1000);
580
+ // calculate scanned gigabytes for better readability in warnings and result text
581
+ const scannedGB = response.scannedBytes !== undefined ? response.scannedBytes / (1000 * 1000 * 1000) : 0;
579
582
  result += `- **Scanned Bytes:** ${scannedGB.toFixed(2)} GB`;
580
583
  // Show budget status if available
581
584
  if (response.budgetState) {
@@ -591,38 +594,51 @@ const main = async () => {
591
594
  }
592
595
  result += '\n';
593
596
  if (scannedGB > 500) {
594
- result += ` āš ļø **Very High Data Usage Warning:** This query scanned ${scannedGB.toFixed(1)} GB of data, which may impact your Dynatrace consumption. Please take measures to optimize your query, like limiting the timeframe or selecting a bucket.\n`;
597
+ warnings.push(`Very High Data Usage: This query scanned ${scannedGB.toFixed(1)} GB of data, which may impact your Dynatrace consumption. Please take measures to optimize your query, like limiting the timeframe or selecting a bucket.`);
595
598
  }
596
599
  else if (scannedGB > 50) {
597
- result += ` āš ļø **High Data Usage Warning:** This query scanned ${scannedGB.toFixed(2)} GB of data, which may impact your Dynatrace consumption.\n`;
600
+ warnings.push(`High Data Usage: This query scanned ${scannedGB.toFixed(2)} GB of data, which may impact your Dynatrace consumption.`);
598
601
  }
599
- else if (scannedGB > 5) {
602
+ // Add informational messages (not warnings) about data usage
603
+ else if (scannedGB > 5 && scannedGB <= 50) {
600
604
  result += ` šŸ’” **Moderate Data Usage:** This query scanned ${scannedGB.toFixed(2)} GB of data.\n`;
601
605
  }
602
606
  else if (response.scannedBytes === 0) {
603
607
  result += ` šŸ’” **No Data consumed:** This query did not consume any data.\n`;
604
608
  }
609
+ if (response.sampled) {
610
+ warnings.push('Sampling Used: Results may be approximate');
611
+ }
612
+ if (response.records.length === recordLimit) {
613
+ warnings.push(`Record Limit Reached: The result set was limited to ${recordLimit} records. Consider changing your query with a smaller timeframe, an aggregation or a more concise filter. Alternatively, increase the recordLimit if you expect more results.`);
614
+ }
605
615
  }
606
- if (response.sampled !== undefined && response.sampled) {
607
- result += `- **āš ļø Sampling Used:** Yes (results may be approximate)\n`;
608
- }
609
- if (response.records.length === recordLimit) {
610
- result += `- **āš ļø Record Limit Reached:** The result set was limited to ${recordLimit} records. Consider changing your query with a smaller timeframe, an aggregation or a more concise filter. Alternatively, increase the recordLimit if you expect more results.\n`;
616
+ // Add all warnings to result
617
+ if (warnings.length > 0) {
618
+ result += '\n';
619
+ warnings.forEach((warning) => {
620
+ result += `- **āš ļø ${warning}**\n`;
621
+ });
611
622
  }
612
623
  result += `\nšŸ“‹ **Query Results**: (${response.records?.length || 0} records):\n\n`;
613
624
  result += `\`\`\`json\n${JSON.stringify(response.records, null, 2)}\n\`\`\``;
614
- // Include field type definitions for chart rendering in the UI
615
- if (response.types && response.types.length > 0) {
616
- result += `\n\nšŸ“Š **Field Types**:\n\n`;
617
- result += `\`\`\`json:types\n${JSON.stringify(response.types)}\n\`\`\``;
618
- }
619
- // Include analysisTimeframe metadata for chart rendering in the UI.
620
- // This is needed when timeseries results lack explicit timeframe/interval
621
- // columns (e.g. timeseries queries with fieldsRemove or custom projections).
622
- if (response.metadata?.grail?.analysisTimeframe) {
623
- result += `\n\n\`\`\`json:analysisTimeframe\n${JSON.stringify(response.metadata.grail.analysisTimeframe)}\n\`\`\``;
624
- }
625
- return result;
625
+ // Return structured data in _meta for MCP App UI instead of embedding in text
626
+ return {
627
+ text: result,
628
+ _meta: {
629
+ records: response.records,
630
+ types: response.types,
631
+ analysisTimeframe: response.metadata?.grail?.analysisTimeframe,
632
+ scannedRecords: response.scannedRecords,
633
+ scannedBytes: response.scannedBytes,
634
+ sampled: response.sampled,
635
+ environmentUrl: dtEnvironment,
636
+ budgetState: response.budgetState,
637
+ warnings,
638
+ recordLimit,
639
+ recordLimitReached: response.records.length === recordLimit,
640
+ },
641
+ };
626
642
  }));
627
643
  // MCP App: Register the HTML resource for the execute_dql interactive UI (MCP App)
628
644
  registerAppResource(server, 'DQL Results Viewer', executeDqlResourceUri, {}, async () => {