Skip to content

Add aggregate_records MCP tool with query-timeout support#3186

Closed
Copilot wants to merge 4 commits intomainfrom
copilot/update-aggregate-records-tool-fixes
Closed

Add aggregate_records MCP tool with query-timeout support#3186
Copilot wants to merge 4 commits intomainfrom
copilot/update-aggregate-records-tool-fixes

Conversation

Copy link
Contributor

Copilot AI commented Mar 2, 2026

Adds a new aggregate_records built-in MCP tool that enables models to answer aggregation questions (count, avg, sum, min, max) over entity data, with optional groupby/having/pagination. Adds configurable query-timeout for all MCP tool executions.

Why make this change?

  • Models frequently need to answer questions like "How many products?" or "What's the average price by category?" — previously unsupported without custom tooling.
  • MCP tool calls had no timeout, leaving models hung indefinitely on large datasets.

What is this change?

aggregate_records tool (AggregateRecordsTool.cs)

  • Supports count, avg, sum, min, max with optional filter (OData WHERE), distinct, groupby, having (post-aggregation), orderby, and cursor-based first/after pagination
  • Response alias: {function}_{field} (e.g. avg_unitPrice); count for count(*)
  • Enabled/disabled via DmlToolsConfig.AggregateRecords; CLI: --runtime.mcp.dml-tools.aggregate-records.enabled

Validation (deterministic, model-facing errors)

  • field='*' with non-count function → InvalidArguments
  • count(*) + distinct=trueInvalidArguments (was silently returning 0)

query-timeout (default 30s)

  • McpRuntimeOptions.QueryTimeout serialized as query-timeout in JSON config
  • McpTelemetryHelper.ExecuteWithTelemetryAsync wraps every tool call with a linked CancellationTokenSource.CancelAfter; timeout fires TimeoutException with model-facing guidance, distinct from client cancellation (OperationCanceledException)
  • Hot-reload safe: reads timeout from RuntimeConfigProvider per call, no restart needed
  • CLI: --runtime.mcp.query-timeout

Schema/config

  • dab.draft.schema.json updated with query-timeout (integer, min 1, default 30) and aggregate-records
  • RuntimeConfigValidator rejects query-timeout < 1
  • McpRuntimeOptionsConverterFactory reads/writes query-timeout in both Read and Write paths

How was this tested?

  • Integration Tests
  • Unit Tests
    • Mcp/AggregateRecordsToolTests.cs — 63 tests covering all 13 documented spec examples, groupby/having/orderby, cursor pagination, edge cases
    • Mcp/McpQueryTimeoutTests.cs — 21 tests: timeout firing, client cancellation, error message content, hot-reload behavior
    • UnitTests/AggregateRecordsToolTests.cs — 31 tests: validation paths (invalid field/function combos, count(*)+distinct, pagination cursor semantics)
    • UnitTests/McpTelemetryTests.cs — expanded with timeout and aggregate_records"aggregate" operation-mapping tests

Sample Request(s)

Config: enable aggregate-records with custom timeout

{
  "runtime": {
    "mcp": {
      "enabled": true,
      "query-timeout": 60,
      "dml-tools": { "aggregate-records": true }
    }
  }
}

CLI

dab configure --runtime.mcp.query-timeout 60
dab configure --runtime.mcp.dml-tools.aggregate-records.enabled true

Tool call: count all products

{ "entity": "Product", "function": "count", "field": "*" }

Response: { "count": 77 }

Tool call: top categories by avg price (grouped, paginated)

{
  "entity": "Product", "function": "avg", "field": "unitPrice",
  "groupby": ["categoryName"], "having": { "gt": 25 },
  "orderby": "desc", "first": 5
}

Response: { "items": [...], "endCursor": "<opaque>", "hasNextPage": true }

Original prompt

Update PR #3179 in Azure/data-api-builder by implementing the previously identified review fixes directly in code.

Context:

Required changes:

  1. Fix AggregateRecordsTool distinct-count star behavior:

    • In AggregateRecordsTool.ComputeAggregateValue, current behavior returns 0 when function=count, field=*, distinct=true.
    • Replace with correct deterministic behavior: either reject this argument combination with InvalidArguments or treat it as count(*) ignoring distinct.
    • Prefer explicit validation in ExecuteAsync returning InvalidArguments with clear message.
  2. Add explicit validation for function/field compatibility:

    • Enforce that field="*" is only valid when function is "count".
    • Enforce numeric field requirements for avg/sum/min/max with clear InvalidArguments errors.
    • Ensure validation is deterministic and model-facing errors are explicit.
  3. Pagination contract clarity:

    • Keep behavior consistent with current intended contract for after usage (do NOT force after to require first or groupby).
    • Ensure pagination behavior and terminal endCursor semantics are explicitly documented and tested.
    • Add/adjust tests to codify intended behavior and avoid ambiguity.
  4. Tests:

    • Update/add unit tests in AggregateRecordsToolTests (and others if needed) to cover:
      • count(*) + distinct handling path (per chosen behavior)
      • invalid * usage with non-count functions
      • numeric field validation for avg/sum/min/max
      • pagination terminal cursor semantics according to intended contract
    • Ensure all tests pass.
  5. Keep existing successful timeout/query-timeout behavior unchanged unless required by refactors.

Acceptance criteria:

This pull request was created from Copilot chat.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 2 commits March 2, 2026 19:15
…pport

- Add AggregateRecordsTool with validation for field/function compatibility
- Reject count+star+distinct=true with InvalidArguments
- Reject field='*' with non-count functions
- Add QueryTimeout to McpRuntimeOptions and converter
- Add AggregateRecords to DmlToolsConfig and converter
- Add TIMEOUT error code to McpTelemetryErrorCodes
- Add timeout wrapping and aggregate_records mapping to McpTelemetryHelper
- Update JSON schema with query-timeout and aggregate-records
- Update CLI ConfigGenerator and ConfigureOptions for aggregate-records
- Add AggregateRecordsToolTests with validation, aggregation, and pagination tests
- Add timeout and aggregate_records tests to McpTelemetryTests

Co-authored-by: JerryNixon <1749983+JerryNixon@users.noreply.github.com>
Co-authored-by: JerryNixon <1749983+JerryNixon@users.noreply.github.com>
Copilot AI changed the title [WIP] Update PR #3179 by implementing review fixes Add aggregate_records MCP tool with query-timeout support and validation fixes Mar 2, 2026
…-tool

- Add comprehensive AggregateRecordsTool.cs (with validation fixes from update branch)
- Add McpTelemetryErrorCodes.cs updates
- Add ConfigureOptions.cs with query-timeout CLI option
- Add ConfigGenerator.cs with query-timeout and aggregate-records support
- Add RuntimeConfigValidator.cs query-timeout validation
- Add comprehensive AggregateRecordsToolTests.cs (Mcp/ folder, 63 tests)
- Add McpQueryTimeoutTests.cs (21 tests, fixed assertion for '1 second')
- Update EntityLevelDmlToolConfigurationTests.cs
- Remove unused _numericFunctions field (dotnet format clean)

This branch now contains all work from both:
- copilot/add-aggregate-records-tool (comprehensive implementation + tests)
- copilot/update-aggregate-records-tool-fixes (validation fixes + grammar fix)

Co-authored-by: JerryNixon <1749983+JerryNixon@users.noreply.github.com>
Copilot AI changed the title Add aggregate_records MCP tool with query-timeout support and validation fixes Add aggregate_records MCP tool with validation fixes and query-timeout support Mar 2, 2026
Copilot AI changed the title Add aggregate_records MCP tool with validation fixes and query-timeout support Add aggregate_records MCP tool with query-timeout support Mar 2, 2026
@JerryNixon JerryNixon closed this Mar 2, 2026
@JerryNixon JerryNixon deleted the copilot/update-aggregate-records-tool-fixes branch March 2, 2026 22:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants