Skip to content

Commit d5fe23b

Browse files
patch: Added dtClientContext to execute_dql to allow cost and usage monitoring (#119)
1 parent ae14653 commit d5fe23b

File tree

5 files changed

+34
-3
lines changed

5 files changed

+34
-3
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased Changes
44

5+
- Added cost considerations disclaimer in README about Dynatrace Grail data access.
6+
- Added `dtClientContext` to `execute_dql` tool, to allow usage-monitoring for Grail access.
7+
58
## 0.5.0 (Release Candidate 4)
69

710
- Added Streamable HTTP transport support with `--http`/`--server`, `--port`, and `--host` arguments (default remains stdio for backward compatibility)

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,20 @@ Bring real-time observability data directly into your development workflow.
2727
- Get more information about a monitored entity
2828
- Get Ownership of an entity
2929

30+
## Costs
31+
32+
**Important:** While this local MCP server is provided for free, using it to access data in Dynatrace Grail may incur additional costs based
33+
on your Dynatrace consumption model. This affects `execute_dql` tool and other capabilities that **query** Dynatrace Grail storage, and costs
34+
depend on the volume (GB scanned/billed).
35+
36+
**Before using this MCP server extensively, please:**
37+
38+
1. Review your current Dynatrace consumption model and pricing
39+
2. Understand the cost implications of the specific data you plan to query (logs, events, metrics) - see [Dynatrace Pricing and Rate Card](https://www.dynatrace.com/pricing/)
40+
3. Start with smaller timeframes (e.g., 12h-24h) and make use of [buckets](https://docs.dynatrace.com/docs/discover-dynatrace/platform/grail/data-model#built-in-grail-buckets) to reduce the cost impact
41+
42+
**Note**: We will be providing a way to monitor Query Usage of the dynatrace-mcp-server in the future.
43+
3044
### AI-Powered Assistance (Preview)
3145

3246
- **Natural Language to DQL** - Convert plain English queries to Dynatrace Query Language

src/authentication/dynatrace-clients.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { HttpClient, PlatformHttpClient } from '@dynatrace-sdk/http-client';
22
import { getSSOUrl } from 'dt-app';
3-
import { version as VERSION } from '../../package.json';
3+
import { getUserAgent } from '../utils/user-agent';
44
import { OAuthTokenResponse } from './types';
55

66
/**
@@ -73,7 +73,7 @@ const createBearerTokenHttpClient = async (environmentUrl: string, dtPlatformTok
7373
baseUrl: environmentUrl,
7474
defaultHeaders: {
7575
'Authorization': `Bearer ${dtPlatformToken}`,
76-
'User-Agent': `dynatrace-mcp-server/v${VERSION} (${process.platform}-${process.arch})`,
76+
'User-Agent': getUserAgent(),
7777
},
7878
});
7979
};

src/capabilities/execute-dql.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { HttpClient } from '@dynatrace-sdk/http-client';
22
import { QueryExecutionClient, QueryAssistanceClient, QueryResult, ExecuteRequest } from '@dynatrace-sdk/client-query';
3+
import { getUserAgent } from '../utils/user-agent';
34

45
export const verifyDqlStatement = async (dtClient: HttpClient, dqlStatement: string) => {
56
const queryAssistanceClient = new QueryAssistanceClient(dtClient);
@@ -27,7 +28,10 @@ export const executeDql = async (
2728
): Promise<QueryResult['records'] | undefined> => {
2829
const queryExecutionClient = new QueryExecutionClient(dtClient);
2930

30-
const response = await queryExecutionClient.queryExecute({ body });
31+
const response = await queryExecutionClient.queryExecute({
32+
body,
33+
dtClientContext: getUserAgent(),
34+
});
3135

3236
if (response.result) {
3337
// return response result immediately
@@ -42,6 +46,7 @@ export const executeDql = async (
4246
await new Promise((resolve) => setTimeout(resolve, 2000));
4347
pollResponse = await queryExecutionClient.queryPoll({
4448
requestToken: response.requestToken,
49+
dtClientContext: getUserAgent(),
4550
});
4651
// done - let's return it
4752
if (pollResponse.result) {

src/utils/user-agent.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { version as VERSION } from '../../package.json';
2+
3+
/**
4+
* Generate a user agent string for Dynatrace MCP Server
5+
* @returns User agent string in format: dynatrace-mcp-server/vX.X.X (platform-arch)
6+
*/
7+
export const getUserAgent = (): string => {
8+
return `dynatrace-mcp-server/v${VERSION} (${process.platform}-${process.arch})`;
9+
};

0 commit comments

Comments
 (0)