Skip to content

Commit 406cb08

Browse files
patch: Added query limit to execute_dql (#210)
1 parent bed341f commit 406cb08

File tree

2 files changed

+17
-3
lines changed

2 files changed

+17
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Tools
66

77
- `find_entities_by_name` now uses `smartscapeNode` DQL command under the hood, and will fall back to `fetch dt.entity.${entityType}`.
8+
- Added default response limiting to `execute_dql` tool with new parameters `recordLimit` (default 100) and `recordSizeLimitMB` (default 1 MB) to prevent overwhelming LLM context. These limits apply only to the returned payload, not the underlying DQL execution.
89

910
### Scopes
1011

src/index.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ const main = async () => {
124124
dynatraceEnv;
125125

126126
// Infer OAuth auth code flow if no OAuth Client credentials are provided
127-
// -> configure default OAuth client ID for auth code flow
128127
if (!oauthClientId && !oauthClientSecret && !dtPlatformToken) {
129128
console.error('No OAuth credentials or platform token provided - switching to OAuth authorization code flow.');
130129
oauthClientId = DT_MCP_AUTH_CODE_FLOW_OAUTH_CLIENT_ID; // Default OAuth client ID for auth code flow
@@ -606,6 +605,12 @@ const main = async () => {
606605
'DQL Statement (Ex: "fetch [logs, spans, events, metric.series, ...], from: now()-4h, to: now() [| filter <some-filter>] [| summarize count(), by:{some-fields}]", or for metrics: "timeseries { avg(<metric-name>), value.A = avg(<metric-name>, scalar: true) }", or for entities via smartscape: "smartscapeNodes \"[*, HOST, PROCESS, ...]\" [| filter id == "<ENTITY-ID>"]"). ' +
607606
'When querying data for a specific entity, call the `find_entity_by_name` tool first to get an appropriate filter like `dt.entity.service == "SERVICE-1234"` or `dt.entity.host == "HOST-1234"` to be used in the DQL statement. ',
608607
),
608+
recordLimit: z.number().optional().default(100).describe('Maximum number of records to return (default: 100)'),
609+
recordSizeLimitMB: z
610+
.number()
611+
.optional()
612+
.default(1)
613+
.describe('Maximum size of the returned records in MB (default: 1MB)'),
609614
},
610615
{
611616
// not readonly (DQL statements may modify things), not idempotent (may change over time)
@@ -614,7 +619,7 @@ const main = async () => {
614619
// while we are not strictly talking to the open world here, the response from execute DQL could interpreted as a web-search, which often is referred to open-world
615620
openWorldHint: true,
616621
},
617-
async ({ dqlStatement }) => {
622+
async ({ dqlStatement, recordLimit = 100, recordSizeLimitMB = 1 }) => {
618623
// Create a HTTP Client that has all storage:*:read scopes
619624
const dtClient = await createAuthenticatedHttpClient(
620625
scopesBase.concat(
@@ -632,7 +637,11 @@ const main = async () => {
632637
'storage:smartscape:read', // Read Smartscape Entities from Grail
633638
),
634639
);
635-
const response = await executeDql(dtClient, { query: dqlStatement }, grailBudgetGB);
640+
const response = await executeDql(
641+
dtClient,
642+
{ query: dqlStatement, maxResultRecords: recordLimit, maxResultBytes: recordSizeLimitMB * 1024 * 1024 },
643+
grailBudgetGB,
644+
);
636645

637646
if (!response) {
638647
return 'DQL execution failed or returned no result.';
@@ -677,6 +686,10 @@ const main = async () => {
677686
result += `- **⚠️ Sampling Used:** Yes (results may be approximate)\n`;
678687
}
679688

689+
if (response.records.length === recordLimit) {
690+
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`;
691+
}
692+
680693
result += `\n📋 **Query Results**: (${response.records?.length || 0} records):\n\n`;
681694
result += `\`\`\`json\n${JSON.stringify(response.records, null, 2)}\n\`\`\``;
682695

0 commit comments

Comments
 (0)