@dynatrace-oss/dynatrace-mcp-server 0.2.0 → 0.3.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
@@ -16,9 +16,10 @@ Bring real-time observability data directly into your development workflow.
16
16
 
17
17
  - List and get [problem](https://www.dynatrace.com/hub/detail/problems/) details from your services (for example Kubernetes)
18
18
  - List and get security problems / [vulnerability](https://www.dynatrace.com/hub/detail/vulnerabilities/) details
19
- - Execute DQL(Dynatrace Query Language) like getting events or logs
19
+ - Execute DQL (Dynatrace Query Language) and retrieve logs, events, spans and metrics
20
20
  - Send Slack messages (via Slack Connector)
21
21
  - Set up notification Workflow (via Dynatrace [AutomationEngine](https://docs.dynatrace.com/docs/discover-dynatrace/platform/automationengine))
22
+ - Get more information about a monitored entity
22
23
  - Get Ownership of an entity
23
24
 
24
25
  ## Quickstart
@@ -27,6 +28,8 @@ Bring real-time observability data directly into your development workflow.
27
28
 
28
29
  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
30
 
31
+ We recommend to always set it up for your current workspace instead of using it globally.
32
+
30
33
  **VS Code**
31
34
 
32
35
  ```json
@@ -34,6 +37,7 @@ You can add this MCP server (using STDIO) to your MCP Client like VS Code, Claud
34
37
  "servers": {
35
38
  "npx-dynatrace-mcp-server": {
36
39
  "command": "npx",
40
+ "cwd": "${workspaceFolder}",
37
41
  "args": ["-y", "@dynatrace-oss/dynatrace-mcp-server@latest"],
38
42
  "envFile": "${workspaceFolder}/.env"
39
43
  }
@@ -61,6 +65,7 @@ This only works if the config is stored in the current workspaces, e.g., `<your-
61
65
  ```
62
66
 
63
67
  **Claude Desktop**
68
+
64
69
  ```json
65
70
  {
66
71
  "mcpServers": {
@@ -80,6 +85,7 @@ This only works if the config is stored in the current workspaces, e.g., `<your-
80
85
  **Amazon Q Developer CLI**
81
86
 
82
87
  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.
88
+
83
89
  ```json
84
90
  {
85
91
  "mcpServers": {
@@ -96,6 +102,8 @@ The [Amazon Q Developer CLI](https://docs.aws.amazon.com/amazonq/latest/qdevelop
96
102
  }
97
103
  ```
98
104
 
105
+ This configuration should be stored in `<your-repo>/.amazonq/mcp.json`.
106
+
99
107
  ## Environment Variables
100
108
 
101
109
  A **Dynatrace OAuth Client** is needed to communicate with your Dynatrace Environment. Please follow the documentation about
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.callAppFunction = exports.createOAuthClient = void 0;
3
+ exports.callAppFunction = exports.createOAuthClient = exports.ExtendedOauthClient = void 0;
4
4
  const http_client_1 = require("@dynatrace-sdk/http-client");
5
5
  const dt_app_1 = require("dt-app");
6
+ const package_json_1 = require("../package.json");
6
7
  /**
7
8
  * Uses the provided oauth Client ID and Secret and requests a token
8
9
  * @param clientId - OAuth Client ID for Dynatrace
@@ -32,6 +33,26 @@ const requestToken = async (clientId, clientSecret, authUrl, scopes) => {
32
33
  // and return the JSON result, as it contains additional information
33
34
  return await res.json();
34
35
  };
36
+ /**
37
+ * ExtendedOAuthClient that takes parameters for clientId, secret, scopes, environmentUrl, authUrl, and the version of the dynatrace-mcp-server
38
+ */
39
+ class ExtendedOauthClient extends http_client_1._OAuthHttpClient {
40
+ userAgent;
41
+ constructor(config, userAgent) {
42
+ super(config);
43
+ this.userAgent = userAgent;
44
+ }
45
+ send(options) {
46
+ // add the user-agent header to the request
47
+ options.headers = {
48
+ ...options.headers,
49
+ 'User-Agent': this.userAgent,
50
+ };
51
+ // call the parent send method
52
+ return super.send(options);
53
+ }
54
+ }
55
+ exports.ExtendedOauthClient = ExtendedOauthClient;
35
56
  /** Create an Oauth Client based on clientId, clientSecret, environmentUrl and scopes */
36
57
  const createOAuthClient = async (clientId, clientSecret, environmentUrl, scopes) => {
37
58
  if (!clientId) {
@@ -54,13 +75,14 @@ const createOAuthClient = async (clientId, clientSecret, environmentUrl, scopes)
54
75
  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.`);
55
76
  }
56
77
  console.error(`Successfully retrieved token from SSO!`);
57
- return new http_client_1._OAuthHttpClient({
78
+ const userAgent = `dynatrace-mcp-server/v${package_json_1.version} (${process.platform}-${process.arch})`;
79
+ return new ExtendedOauthClient({
58
80
  scopes,
59
81
  clientId,
60
82
  secret: clientSecret,
61
83
  environmentUrl,
62
84
  authUrl: ssoAuthUrl,
63
- });
85
+ }, userAgent);
64
86
  };
65
87
  exports.createOAuthClient = createOAuthClient;
66
88
  /** Helper function to call an app-function via platform-api */
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
7
7
  const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
8
8
  const dotenv_1 = require("dotenv");
9
9
  const zod_1 = require("zod");
10
+ const package_json_1 = require("../package.json");
10
11
  const dynatrace_clients_1 = require("./dynatrace-clients");
11
12
  const list_vulnerabilities_1 = require("./capabilities/list-vulnerabilities");
12
13
  const list_problems_1 = require("./capabilities/list-problems");
@@ -68,10 +69,10 @@ const main = async () => {
68
69
  const { oauthClient, oauthClientSecret, dtEnvironment, slackConnectionId } = dynatraceEnv;
69
70
  // create an oauth-client
70
71
  const dtClient = await (0, dynatrace_clients_1.createOAuthClient)(oauthClient, oauthClientSecret, dtEnvironment, scopes);
71
- console.error("Starting Dynatrace MCP Server...");
72
+ console.error(`Starting Dynatrace MCP Server v${package_json_1.version}...`);
72
73
  const server = new mcp_js_1.McpServer({
73
74
  name: "Dynatrace MCP Server",
74
- version: "0.0.1", // ToDo: Read from package.json / hard-code?
75
+ version: package_json_1.version,
75
76
  }, {
76
77
  capabilities: {
77
78
  tools: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynatrace-oss/dynatrace-mcp-server",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Model Context Protocol (MCP) server for Dynatrace",
5
5
  "keywords": [
6
6
  "Dynatrace",
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getMonitoredEntityOwner = void 0;
4
- const get_monitored_entity_details_1 = require("./get-monitored-entity-details");
5
- const getMonitoredEntityOwner = async (dtClient, entityId) => {
6
- const monitoredEntity = await (0, get_monitored_entity_details_1.getMonitoredEntityDetails)(dtClient, entityId);
7
- const owner = monitoredEntity.tags?.find((tag) => {
8
- return tag?.key === "owner";
9
- });
10
- return {
11
- entity: monitoredEntity,
12
- owner: owner?.value
13
- };
14
- };
15
- exports.getMonitoredEntityOwner = getMonitoredEntityOwner;
@@ -1,27 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.executeWorkflow = exports.deleteWorkflow = exports.getWorkflowDetails = exports.listWorkflows = void 0;
4
- const client_automation_1 = require("@dynatrace-sdk/client-automation");
5
- const listWorkflows = async (dtClient) => {
6
- const workflowsClient = new client_automation_1.WorkflowsClient(dtClient);
7
- return await workflowsClient.getWorkflows({});
8
- };
9
- exports.listWorkflows = listWorkflows;
10
- const getWorkflowDetails = async (dtClient, workflowId) => {
11
- const workflowsClient = new client_automation_1.WorkflowsClient(dtClient);
12
- return await workflowsClient.getWorkflow({ id: workflowId });
13
- };
14
- exports.getWorkflowDetails = getWorkflowDetails;
15
- const deleteWorkflow = async (dtClient, workflowId) => {
16
- const workflowsClient = new client_automation_1.WorkflowsClient(dtClient);
17
- return await workflowsClient.deleteWorkflow({ id: workflowId });
18
- };
19
- exports.deleteWorkflow = deleteWorkflow;
20
- const executeWorkflow = async (dtClient, workflowId, input) => {
21
- const workflowsClient = new client_automation_1.WorkflowsClient(dtClient);
22
- return await workflowsClient.runWorkflow({
23
- id: workflowId,
24
- body: input || {}
25
- });
26
- };
27
- exports.executeWorkflow = executeWorkflow;
@@ -1,55 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OAuthHttpClient = void 0;
4
- class OAuthHttpClient {
5
- config;
6
- oauthToken;
7
- constructor(config) {
8
- this.config = config;
9
- }
10
- async send(options) {
11
- const { statusValidator = defaultStatusValidator } = options;
12
- if (!this.oauthToken || this.oauthToken.isExpired()) {
13
- this.oauthToken = await this.requestToken();
14
- }
15
- const requestBodyType = options.requestBodyType ?? 'json';
16
- const url = new URL(options.url, this.config.environmentUrl);
17
- const body = options.body !== undefined
18
- ? await encodeRequestBody(options.body, requestBodyType)
19
- : undefined;
20
- const headers = {
21
- ...applyContentTypeHeader(options.headers, requestBodyType),
22
- Authorization: `${this.oauthToken.tokenType} ${this.oauthToken.accessToken}`,
23
- };
24
- const response = await send(url.toString(), {
25
- method: options.method,
26
- signal: options.abortSignal,
27
- body,
28
- headers,
29
- });
30
- const ok = statusValidator(response.status);
31
- if (ok) {
32
- return new HttpClientResponse(response);
33
- }
34
- else {
35
- throw new HttpClientResponseError(response, { requestMethod: options.method });
36
- }
37
- }
38
- async requestToken() {
39
- const res = await send(this.config.authUrl, {
40
- method: 'POST',
41
- headers: {
42
- 'Content-Type': 'application/x-www-form-urlencoded',
43
- },
44
- body: new URLSearchParams({
45
- grant_type: 'client_credentials',
46
- client_id: this.config.clientId,
47
- client_secret: this.config.secret,
48
- scope: this.config.scopes.join(' '),
49
- }),
50
- });
51
- const data = await res.json();
52
- return new OAuthToken(data);
53
- }
54
- }
55
- exports.OAuthHttpClient = OAuthHttpClient;
@@ -1 +0,0 @@
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"}