-
Notifications
You must be signed in to change notification settings - Fork 4
Description
Description
The MCP server fails to register environments as valid when the API token only has the scopes listed in the README documentation. The server internally requires the V1 DataExport scope for the /api/v1/config/clusterversion endpoint, but this scope is not listed in the README's Authentication section.
Steps to Reproduce
- Create a Dynatrace Managed API token with only the scopes documented in the README:
auditLogs.read,entities.read,events.read,logs.read,metrics.read,networkZones.read,problems.read,securityProblems.read,slo.read
- Configure the MCP server with this token
- Start the MCP server
- Call
get_environments_info
Expected Behavior
The environment is registered as valid and all MCP tools work correctly.
Actual Behavior
The environment shows Valid Environment: No with a 403 error. All tool calls fail with:
Environment alias(es) not valid. Options are: ALL_ENVIRONMENTS
Root Cause Analysis
The issue is in src/authentication/managed-auth-client.ts:
1. validateConnection() (line ~122) has a fallback — works fine:
async validateConnection(): Promise<boolean> {
try {
const response = await this.httpClient.get('/api/v1/config/clusterversion');
return response.status === 200;
} catch (error) {
// Fallback: try a basic API endpoint
try {
const response = await this.httpClient.get('/api/v2/metrics', { params: { pageSize: 1 } });
return response.status === 200;
} catch (fallbackError) {
return false;
}
}
}When the token lacks DataExport, the V1 call gets 403, but the V2 fallback succeeds → validateConnection() returns true.
2. getClusterVersion() (line ~143) has NO fallback — fails:
async getClusterVersion(): Promise<ClusterVersion> {
const response = await this.httpClient.get('/api/v1/config/clusterversion');
return response.data;
}3. isConfigured() (line ~192) calls both sequentially:
async isConfigured() {
try {
const isConnected = await this.validateConnection(); // ✅ passes (V2 fallback)
if (!isConnected) { return false; }
const clusterVersion = await this.getClusterVersion(); // ❌ 403 - no fallback!
// ...never reaches here
} catch (error) {
this.validationError = `Failed to connect...`;
return false;
}
}So validateConnection() passes via the V2 fallback, but then getClusterVersion() hits the same V1 endpoint again without a fallback, throwing a 403 that marks the environment as invalid.
Evidence
The Dynatrace API returns this error for the V1 endpoint:
{"error":{"code":403,"message":"Token is missing required scope. Use one of: DataExport (Access problem and event feed, metrics, and topology)"}}Meanwhile, V2 endpoints work perfectly with the documented scopes:
# V1 endpoint - 403
curl -H "Authorization: Api-Token <token>" "https://<host>/e/<env>/api/v1/config/clusterversion"
# V2 endpoint - 200
curl -H "Authorization: Api-Token <token>" "https://<host>/e/<env>/api/v2/metrics?pageSize=1"Documentation Discrepancy
The source code at managed-auth-client.ts line 4-13 defines a MANAGED_API_SCOPES constant that includes DataExport and ReadConfig:
const MANAGED_API_SCOPES = [
'DataExport',
'ReadConfig',
'ReadSyntheticData',
// ...
];But the README's Authentication section only lists V2 scopes:
auditLogs.read,entities.read,events.read,logs.read,metrics.read,networkZones.read,problems.read,securityProblems.read,slo.read
Suggested Fix
Option A (code fix): Add a fallback in getClusterVersion() similar to validateConnection() — if the V1 endpoint fails with 403, either:
- Skip the version check and return a default/unknown version
- Use a V2 endpoint to infer version info
Option B (documentation fix): Add DataExport to the README's required scopes list.
Option C (recommended — both): Fix the code to gracefully handle missing V1 scopes AND update the README to accurately document all required scopes (both V1 and V2).