Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
594 changes: 594 additions & 0 deletions src/Azure.DataApiBuilder.Mcp/BuiltInTools/AggregateRecordsTool.cs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions src/Cli/Commands/ConfigureOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ public ConfigureOptions(
[Option("runtime.mcp.dml-tools.execute-entity.enabled", Required = false, HelpText = "Enable DAB's MCP execute entity tool. Default: true (boolean).")]
public bool? RuntimeMcpDmlToolsExecuteEntityEnabled { get; }

[Option("runtime.mcp.dml-tools.aggregate-records.enabled", Required = false, HelpText = "Enable DAB's MCP aggregate records tool. Default: true (boolean).")]
public bool? RuntimeMcpDmlToolsAggregateRecordsEnabled { get; }

[Option("runtime.cache.enabled", Required = false, HelpText = "Enable DAB's cache globally. (You must also enable each entity's cache separately.). Default: false (boolean).")]
public bool? RuntimeCacheEnabled { get; }

Expand Down
12 changes: 11 additions & 1 deletion src/Cli/ConfigGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,7 @@ private static bool TryUpdateConfiguredMcpValues(
bool? updateRecord = currentDmlTools?.UpdateRecord;
bool? deleteRecord = currentDmlTools?.DeleteRecord;
bool? executeEntity = currentDmlTools?.ExecuteEntity;
bool? aggregateRecords = currentDmlTools?.AggregateRecords;

updatedValue = options?.RuntimeMcpDmlToolsDescribeEntitiesEnabled;
if (updatedValue != null)
Expand Down Expand Up @@ -1230,6 +1231,14 @@ private static bool TryUpdateConfiguredMcpValues(
_logger.LogInformation("Updated RuntimeConfig with runtime.mcp.dml-tools.execute-entity as '{updatedValue}'", updatedValue);
}

updatedValue = options?.RuntimeMcpDmlToolsAggregateRecordsEnabled;
if (updatedValue != null)
{
aggregateRecords = (bool)updatedValue;
hasToolUpdates = true;
_logger.LogInformation("Updated RuntimeConfig with runtime.mcp.dml-tools.aggregate-records as '{updatedValue}'", updatedValue);
}

if (hasToolUpdates)
{
updatedMcpOptions = updatedMcpOptions! with
Expand All @@ -1242,7 +1251,8 @@ private static bool TryUpdateConfiguredMcpValues(
ReadRecords = readRecord,
UpdateRecord = updateRecord,
DeleteRecord = deleteRecord,
ExecuteEntity = executeEntity
ExecuteEntity = executeEntity,
AggregateRecords = aggregateRecords
}
};
}
Expand Down
18 changes: 15 additions & 3 deletions src/Config/Converters/DmlToolsConfigConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ internal class DmlToolsConfigConverter : JsonConverter<DmlToolsConfig>
bool? updateRecord = null;
bool? deleteRecord = null;
bool? executeEntity = null;
bool? aggregateRecords = null;

while (reader.Read())
{
Expand Down Expand Up @@ -82,6 +83,9 @@ internal class DmlToolsConfigConverter : JsonConverter<DmlToolsConfig>
case "execute-entity":
executeEntity = value;
break;
case "aggregate-records":
aggregateRecords = value;
break;
default:
// Skip unknown properties
break;
Expand All @@ -91,7 +95,8 @@ internal class DmlToolsConfigConverter : JsonConverter<DmlToolsConfig>
{
// Error on non-boolean values for known properties
if (property?.ToLowerInvariant() is "describe-entities" or "create-record"
or "read-records" or "update-record" or "delete-record" or "execute-entity")
or "read-records" or "update-record" or "delete-record" or "execute-entity"
or "aggregate-records")
{
throw new JsonException($"Property '{property}' must be a boolean value.");
}
Expand All @@ -110,7 +115,8 @@ internal class DmlToolsConfigConverter : JsonConverter<DmlToolsConfig>
readRecords: readRecords,
updateRecord: updateRecord,
deleteRecord: deleteRecord,
executeEntity: executeEntity);
executeEntity: executeEntity,
aggregateRecords: aggregateRecords);
}

// For any other unexpected token type, return default (all enabled)
Expand All @@ -135,7 +141,8 @@ public override void Write(Utf8JsonWriter writer, DmlToolsConfig? value, JsonSer
value.UserProvidedReadRecords ||
value.UserProvidedUpdateRecord ||
value.UserProvidedDeleteRecord ||
value.UserProvidedExecuteEntity;
value.UserProvidedExecuteEntity ||
value.UserProvidedAggregateRecords;

// Only write the boolean value if it's provided by user
// This prevents writing "dml-tools": true when it's the default
Expand Down Expand Up @@ -181,6 +188,11 @@ public override void Write(Utf8JsonWriter writer, DmlToolsConfig? value, JsonSer
writer.WriteBoolean("execute-entity", value.ExecuteEntity.Value);
}

if (value.UserProvidedAggregateRecords && value.AggregateRecords.HasValue)
{
writer.WriteBoolean("aggregate-records", value.AggregateRecords.Value);
}

writer.WriteEndObject();
}
}
Expand Down
25 changes: 22 additions & 3 deletions src/Config/ObjectModel/DmlToolsConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ public record DmlToolsConfig
/// </summary>
public bool? ExecuteEntity { get; init; }

/// <summary>
/// Whether aggregate-records tool is enabled
/// </summary>
public bool? AggregateRecords { get; init; }

[JsonConstructor]
public DmlToolsConfig(
bool? allToolsEnabled = null,
Expand All @@ -59,7 +64,8 @@ public DmlToolsConfig(
bool? readRecords = null,
bool? updateRecord = null,
bool? deleteRecord = null,
bool? executeEntity = null)
bool? executeEntity = null,
bool? aggregateRecords = null)
{
if (allToolsEnabled is not null)
{
Expand All @@ -75,6 +81,7 @@ public DmlToolsConfig(
UpdateRecord = updateRecord ?? toolDefault;
DeleteRecord = deleteRecord ?? toolDefault;
ExecuteEntity = executeEntity ?? toolDefault;
AggregateRecords = aggregateRecords ?? toolDefault;
}
else
{
Expand All @@ -87,6 +94,7 @@ public DmlToolsConfig(
UpdateRecord = updateRecord ?? DEFAULT_ENABLED;
DeleteRecord = deleteRecord ?? DEFAULT_ENABLED;
ExecuteEntity = executeEntity ?? DEFAULT_ENABLED;
AggregateRecords = aggregateRecords ?? DEFAULT_ENABLED;
}

// Track user-provided status - only true if the parameter was not null
Expand All @@ -96,6 +104,7 @@ public DmlToolsConfig(
UserProvidedUpdateRecord = updateRecord is not null;
UserProvidedDeleteRecord = deleteRecord is not null;
UserProvidedExecuteEntity = executeEntity is not null;
UserProvidedAggregateRecords = aggregateRecords is not null;
}

/// <summary>
Expand All @@ -112,7 +121,8 @@ public static DmlToolsConfig FromBoolean(bool enabled)
readRecords: null,
updateRecord: null,
deleteRecord: null,
executeEntity: null
executeEntity: null,
aggregateRecords: null
);
}

Expand All @@ -127,7 +137,8 @@ public static DmlToolsConfig FromBoolean(bool enabled)
readRecords: null,
updateRecord: null,
deleteRecord: null,
executeEntity: null
executeEntity: null,
aggregateRecords: null
);

/// <summary>
Expand Down Expand Up @@ -185,4 +196,12 @@ public static DmlToolsConfig FromBoolean(bool enabled)
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
[MemberNotNullWhen(true, nameof(ExecuteEntity))]
public bool UserProvidedExecuteEntity { get; init; } = false;

/// <summary>
/// Flag which informs CLI and JSON serializer whether to write aggregate-records
/// property/value to the runtime config file.
/// </summary>
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
[MemberNotNullWhen(true, nameof(AggregateRecords))]
public bool UserProvidedAggregateRecords { get; init; } = false;
}
Loading