diff --git a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs
index 3e7ade6075..95c53d1d28 100644
--- a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs
+++ b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs
@@ -5,79 +5,383 @@
using Azure.DataApiBuilder.Config.ObjectModel;
using Azure.DataApiBuilder.Core.Configurations;
using Azure.DataApiBuilder.Mcp.Model;
+using Azure.DataApiBuilder.Mcp.Utils;
+using Azure.DataApiBuilder.Service.Exceptions;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
using ModelContextProtocol.Protocol;
using static Azure.DataApiBuilder.Mcp.Model.McpEnums;
namespace Azure.DataApiBuilder.Mcp.BuiltInTools
{
+ ///
+ /// Tool to describe all entities configured in DAB, including their types and metadata.
+ ///
public class DescribeEntitiesTool : IMcpTool
{
+ ///
+ /// Gets the type of the tool, which is BuiltIn for this implementation.
+ ///
public ToolType ToolType { get; } = ToolType.BuiltIn;
+ ///
+ /// Gets the metadata for the delete-record tool, including its name, description, and input schema.
+ ///
+ ///
public Tool GetToolMetadata()
{
return new Tool
{
- Name = "describe-entities",
- Description = "Lists and describes all entities in the database."
+ Name = "describe_entities",
+ Description = "Lists and describes all entities in the database, including their types and available operations.",
+ InputSchema = JsonSerializer.Deserialize(
+ @"{
+ ""type"": ""object"",
+ ""properties"": {
+ ""nameOnly"": {
+ ""type"": ""boolean"",
+ ""description"": ""If true, only entity names and descriptions will be returned. If false, full metadata including fields, parameters etc. will be included. Default is false.""
+ },
+ ""entities"": {
+ ""type"": ""array"",
+ ""items"": {
+ ""type"": ""string""
+ },
+ ""description"": ""Optional list of specific entity names to filter by. If empty, all entities will be described.""
+ }
+ }
+ }"
+ )
};
}
+ ///
+ /// Executes the DescribeEntities tool, returning metadata about configured entities.
+ ///
public Task ExecuteAsync(
JsonDocument? arguments,
IServiceProvider serviceProvider,
CancellationToken cancellationToken = default)
{
+ ILogger? logger = serviceProvider.GetService>();
+
try
{
- // Get the runtime config provider
- RuntimeConfigProvider? runtimeConfigProvider = serviceProvider.GetService();
- if (runtimeConfigProvider == null || !runtimeConfigProvider.TryGetConfig(out RuntimeConfig? runtimeConfig))
+ cancellationToken.ThrowIfCancellationRequested();
+
+ RuntimeConfigProvider runtimeConfigProvider = serviceProvider.GetRequiredService();
+ RuntimeConfig runtimeConfig = runtimeConfigProvider.GetConfig();
+
+ if (!IsToolEnabled(runtimeConfig))
{
- return Task.FromResult(new CallToolResult
- {
- Content = [new TextContentBlock { Type = "text", Text = "Error: Runtime configuration not available." }]
- });
+ return Task.FromResult(McpResponseBuilder.BuildErrorResult(
+ "ToolDisabled",
+ $"The {GetToolMetadata().Name} tool is disabled in the configuration.",
+ logger));
}
- // Extract entity information from the runtime config
- Dictionary entities = new();
+ (bool nameOnly, HashSet? entityFilter) = ParseArguments(arguments, logger);
+
+ List> entityList = new();
if (runtimeConfig.Entities != null)
{
- foreach (KeyValuePair entity in runtimeConfig.Entities)
+ foreach (KeyValuePair entityEntry in runtimeConfig.Entities)
{
- entities[entity.Key] = new
+ cancellationToken.ThrowIfCancellationRequested();
+
+ string entityName = entityEntry.Key;
+ Entity entity = entityEntry.Value;
+
+ if (!ShouldIncludeEntity(entityName, entityFilter))
{
- source = entity.Value.Source,
- permissions = entity.Value.Permissions?.Select(p => new
- {
- role = p.Role,
- actions = p.Actions
- })
- };
+ continue;
+ }
+
+ try
+ {
+ Dictionary entityInfo = nameOnly
+ ? BuildBasicEntityInfo(entityName, entity)
+ : BuildFullEntityInfo(entityName, entity);
+
+ entityList.Add(entityInfo);
+ }
+ catch (Exception ex)
+ {
+ logger?.LogWarning(ex, "Failed to build info for entity {EntityName}", entityName);
+ }
+ }
+ }
+
+ if (entityList.Count == 0)
+ {
+ if (entityFilter != null && entityFilter.Count > 0)
+ {
+ return Task.FromResult(McpResponseBuilder.BuildErrorResult(
+ "EntitiesNotFound",
+ $"No entities found matching the filter: {string.Join(", ", entityFilter)}",
+ logger));
+ }
+ else
+ {
+ return Task.FromResult(McpResponseBuilder.BuildErrorResult(
+ "NoEntitiesConfigured",
+ "No entities are configured in the runtime configuration.",
+ logger));
}
}
- string entitiesJson = JsonSerializer.Serialize(entities, new JsonSerializerOptions
+ cancellationToken.ThrowIfCancellationRequested();
+
+ entityList = entityList.OrderBy(e => e["name"]?.ToString() ?? string.Empty).ToList();
+
+ List