Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
28 changes: 22 additions & 6 deletions .env.template
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
## Dynatrace Managed Configuration
# DT_MANAGED_ENVIRONMENT=01234567-89ab-cdef-abcd-ef0123456789
# DT_API_ENDPOINT_URL=https://abc123.dynatrace-managed.example.com:9999
# DT_DYNATRACE_URL=https://dmz123.dynatrace-managed.example.com
# DT_MANAGED_API_TOKEN=dt0s16.SAMPLE.abcd1234
# Proxy configuration optional (for corporate environments)
# Mandatory keys are: "apiEndpointUrl", "environmentId", "alias" and "apiToken"

# Proxy configuration (optional - for corporate environments)
# HTTPS_PROXY=http://proxy.example.com:8080
DT_ENVIRONMENT_CONFIGS='[
{
"dynatraceUrl": "https://my-dashboard-endpoint.com/",
"apiEndpointUrl": "https://my-api-endpoint.com/",
"environmentId": "my-env-id-1",
"alias": "alias-env",
"apiToken": "my-api-token",
"httpProxyUrl": "",
"httpsProxyUrl": ""
},
{
"dynatraceUrl": "https://my-dashboard2-endpoint.com/",
"apiEndpointUrl": "https://my-api2-endpoint.com/",
"environmentId": "my-env-id-2",
"alias": "alias-env-2",
"apiToken": "my-api-token-2",
"httpProxyUrl": "",
"httpsProxyUrl": ""
}
]'
194 changes: 146 additions & 48 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ If you would like to use encryption for your message, please first reach out to

### When Should I NOT Report a Vulnerability?

- You need help tuning one of our our Open Source projects for security - please discuss this with the maintainers of said project
- You need help tuning one of our Open Source projects for security - please discuss this with the maintainers of said project
- You need help applying security-related updates
- Your issue is not security-related

Expand Down
24 changes: 6 additions & 18 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ API responses, and the response text returned by the MCP tool. Also check the lo

### Integration Tests

Integration tests run against a real Dynatrace Managed environment, making real API calls.
Integration tests run against a real Dynatrace Managed environment with alias set to `testAlias`, making real API calls.
It is assumed that this environment has sufficient data to be able to sensibly test the API
calls and processing of responses.
calls and processing of responses. A second environment with alias `invalidApiToken` needs to be set up, with working credentials but a wrong apiToken, used to check error responses.

Configure the `.env` file with the URL and [an API token with the required scopes](../README.md#api-scopes-for-managed-deployment). See `.env.template` as a starting point.
Configure both environments in the `.env` file with the URL and [an API token with the required scopes](../README.md#api-scopes-for-managed-deployment). See `.env.template` as a starting point.
See [main README](../README.md#environment-variables) for description of Environment Variables.

Some useful example testing commands:
Expand Down Expand Up @@ -90,10 +90,7 @@ Configure your preferred AI Assistant with an mcp.json file like that below:
"command": "npx",
"args": ["--watch", "/path/to/repos/dynatrace-oss/dynatrace-manage-mcp/dist/index.js"],
"env": {
"DT_MANAGED_ENVIRONMENT": "01234567-89ab-cdef-abcd-ef0123456789",
"DT_API_ENDPOINT_URL": "https://abc123.dynatrace-managed.example.com:9999",
"DT_DYNATRACE_URL": "https://dmz123.dynatrace-managed.example.com",
"DT_MANAGED_API_TOKEN": "dt0s16.SAMPLE.abcd1234",
"DT_ENVIRONMENT_CONFIGS": "[{\"dynatraceUrl\":\"https://my-dashboard-endpoint.com/\",\"apiEndpointUrl\":\"https://my-api-endpoint.com/\",\"environmentId\":\"my-env-id-1\",\"alias\":\"alias-env\",\"apiToken\":\"my-api-token\"},{\"dynatraceUrl\":\"https://my-dashboard2-endpoint.com/\",\"apiEndpointUrl\":\"https://my-api2-endpoint.com/\",\"environmentId\":\"my-env-id-2\",\"alias\":\"alias-env-2\",\"apiToken\":\"my-api-token-2\"}]",
"DT_MCP_DISABLE_TELEMETRY": "true",
"LOG_LEVEL": "debug"
}
Expand Down Expand Up @@ -143,24 +140,15 @@ You can then use that locally, for example with the following in your `mcp.json`
"--rm",
"-i",
"-e",
"DT_MANAGED_ENVIRONMENT",
"-e",
"DT_API_ENDPOINT_URL",
"-e",
"DT_DYNATRACE_URL",
"-e",
"DT_MANAGED_API_TOKEN",
"DT_ENVIRONMENT_CONFIGS",
"-e",
"DT_MCP_DISABLE_TELEMETRY",
"-e",
"LOG_LEVEL",
"mcp/dynatrace-managed-mcp-server:snapshot"
],
"env": {
"DT_MANAGED_ENVIRONMENT": "01234567-89ab-cdef-abcd-ef0123456789",
"DT_API_ENDPOINT_URL": "https://abc123.dynatrace-managed.example.com:9999",
"DT_DYNATRACE_URL": "https://dmz123.dynatrace-managed.example.com",
"DT_MANAGED_API_TOKEN": "dt0s16.SAMPLE.abcd1234"
"DT_ENVIRONMENT_CONFIGS": "[{\"dynatraceUrl\":\"https://my-dashboard-endpoint.com/\",\"apiEndpointUrl\":\"https://my-api-endpoint.com/\",\"environmentId\":\"my-env-id-1\",\"alias\":\"alias-env\",\"apiToken\":\"my-api-token\"},{\"dynatraceUrl\":\"https://my-dashboard2-endpoint.com/\",\"apiEndpointUrl\":\"https://my-api2-endpoint.com/\",\"environmentId\":\"my-env-id-2\",\"alias\":\"alias-env-2\",\"apiToken\":\"my-api-token-2\"}]",
"DT_MCP_DISABLE_TELEMETRY": "true",
"LOG_LEVEL": "debug"
},
Expand Down
10 changes: 10 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ What performance metrics are available for the books service
Ask Dynatrace for the daily trend of the "builtin:service.response.time" metric for the dt_books_storage service over the last week
```

### Example - Multienvironment

```text
Ask Dynatrace to list the open problems from all of my environments
```

```text
Ask Dynatrace to list the open problems from my production environment
```

### Example - Misc.

```text
Expand Down
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = {
testEnvironment: 'node',
testMatch: ['<rootDir>/integration-tests/**/*.integration.test.ts', '<rootDir>/tests/**/*.integration.test.ts'],
testTimeout: 30000,
setupFiles: ['dotenv/config'],
},
],
};
28 changes: 2 additions & 26 deletions server.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,8 @@
},
"environmentVariables": [
{
"name": "DT_MANAGED_ENVIRONMENT",
"description": "id of the managed environment, used for constructing URL for API and dashboards (e.g. of the form `01234567-89ab-cdef-abcd-ef0123456789`)",
"isRequired": true,
"format": "string"
},
{
"name": "DT_API_ENDPOINT_URL",
"description": "base url for Dynatrace Managed API, to which the environment id will be appended (e.g. `https://abc123.dynatrace-managed.com:9999`)",
"isRequired": true,
"format": "string"
},
{
"name": "DT_DYNATRACE_URL",
"description": "base url for Dynatrace Managed dashboard, to which the environment id will be appended (e.g. `https://dmz123.dynatrace-managed.com`)",
"isRequired": false,
"format": "string"
},
{
"name": "DT_MANAGED_API_TOKEN",
"description": "API Token with required scopes (e.g. 'dt0s16.SAMPLE.abcd1234')",
"name": "DT_ENVIRONMENT_CONFIGS",
"description": "An escaped JSON array that defines the Dynatrace Managed environment(s) to connect to. See README file for contents of this.",
"isRequired": true,
"format": "string"
},
Expand All @@ -48,12 +30,6 @@
"isRequired": false,
"format": "string"
},
{
"name": "HTTP_PROXY",
"description": "HTTP Proxy to use",
"isRequired": false,
"format": "string"
},
{
"name": "DT_MCP_DISABLE_TELEMETRY",
"description": "Disable telemetry",
Expand Down
4 changes: 4 additions & 0 deletions src/authentication/__tests__/managed-auth-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ describe('ManagedAuthClient', () => {
apiBaseUrl: 'https://managed.test.com',
dashboardBaseUrl: 'https://managed-dashboard.test.com',
apiToken: 'test-token',
alias: 'testAlias',
minimum_version: '1.328.0',
});
});

Expand Down Expand Up @@ -50,6 +52,8 @@ describe('ManagedAuthClient', () => {
apiBaseUrl: 'https://managed.test.com',
dashboardBaseUrl: 'https://managed-dashboard.test.com',
apiToken: 'test-token',
alias: 'testAlias',
minimum_version: '1.328.0',
});

const result = await client.validateConnection();
Expand Down
23 changes: 10 additions & 13 deletions src/authentication/__tests__/proxy.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getAxiosProxyFromEnv } from '../managed-auth-client';
import { setAxiosProxy } from '../managed-auth-client';

// Mock undici
describe('proxy-config', () => {
Expand All @@ -21,7 +21,7 @@ describe('proxy-config', () => {
describe('configureProxyFromEnvironment', () => {
it('should parse HTTP_PROXY', () => {
process.env.HTTP_PROXY = 'http://myhost.com:1234';
const response = getAxiosProxyFromEnv();
const response = setAxiosProxy(process.env.HTTP_PROXY);

expect(response).toEqual({
host: 'myhost.com',
Expand All @@ -33,7 +33,7 @@ describe('proxy-config', () => {

it('should parse HTTPS_PROXY', () => {
process.env.HTTPS_PROXY = 'https://myhost.com:1234';
const response = getAxiosProxyFromEnv();
const response = setAxiosProxy(process.env.HTTPS_PROXY);

expect(response).toEqual({
host: 'myhost.com',
Expand All @@ -45,7 +45,7 @@ describe('proxy-config', () => {

it('should parse auth', () => {
process.env.HTTP_PROXY = 'http://myuser:mypass@myhost.com:1234';
const response = getAxiosProxyFromEnv();
const response = setAxiosProxy(process.env.HTTP_PROXY);

expect(response).toEqual({
host: 'myhost.com',
Expand All @@ -56,25 +56,22 @@ describe('proxy-config', () => {
});

it('should return undefined if no proxy', () => {
const response = getAxiosProxyFromEnv();
const response = setAxiosProxy();
expect(response).toBeUndefined();
});

it('should fail if set HTTP_PROXY and HTTPS_PROXY', () => {
it('should return undefined if set HTTP_PROXY and HTTPS_PROXY', () => {
process.env.HTTP_PROXY = 'http://myuser:mypass@myhost.com:1234';
process.env.HTTPS_PROXY = 'https://myuser:mypass@myhost.com:4321';
try {
const response = getAxiosProxyFromEnv();
fail(`Should have failed, but returned response=${response}`);
} catch (err: any) {
expect(err.message).toContain('Cannot specify both HTTPS_PROXY and HTTP_PROXY, use only one');
}

const response = setAxiosProxy();
expect(response).toBeUndefined();
});

it('should fail if invalid URL', () => {
process.env.HTTP_PROXY = 'this is not a url';
try {
const response = getAxiosProxyFromEnv();
const response = setAxiosProxy(process.env.HTTP_PROXY);
fail(`Should have failed, but returned response=${response}`);
} catch (err: any) {
expect(err.message).toContain('Failed to parse and configure http(s) proxy');
Expand Down
Loading