From 4db648278fe9523cafeefa27ec4acd121bdcce6c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 20:10:44 +0000 Subject: [PATCH 1/4] Initial plan From 51333b9567c68c85d16d72ac6faab84c674e2c5e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 20:17:23 +0000 Subject: [PATCH 2/4] Update MCP tool descriptions for better ChatGPT compatibility Co-authored-by: JerryNixon <1749983+JerryNixon@users.noreply.github.com> --- .../BuiltInTools/CreateRecordTool.cs | 6 ++--- .../BuiltInTools/DeleteRecordTool.cs | 6 ++--- .../BuiltInTools/DescribeEntitiesTool.cs | 6 ++--- .../BuiltInTools/ExecuteEntityTool.cs | 6 ++--- .../BuiltInTools/ReadRecordsTool.cs | 23 ++++++++++--------- .../BuiltInTools/UpdateRecordTool.cs | 8 +++---- 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/CreateRecordTool.cs b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/CreateRecordTool.cs index 6fbe08879b..68447f16f4 100644 --- a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/CreateRecordTool.cs +++ b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/CreateRecordTool.cs @@ -31,18 +31,18 @@ public Tool GetToolMetadata() return new Tool { Name = "create_record", - Description = "Creates a new record in the specified entity.", + Description = "STEP 1: describe_entities -> find entities with CREATE permission and their fields. STEP 2: call this tool with matching field names and values.", InputSchema = JsonSerializer.Deserialize( @"{ ""type"": ""object"", ""properties"": { ""entity"": { ""type"": ""string"", - ""description"": ""The name of the entity"" + ""description"": ""Entity name with CREATE permission."" }, ""data"": { ""type"": ""object"", - ""description"": ""The data for the new record"" + ""description"": ""Required fields and values for the new record."" } }, ""required"": [""entity"", ""data""] diff --git a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DeleteRecordTool.cs b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DeleteRecordTool.cs index 86a5ce15ec..7abac888c5 100644 --- a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DeleteRecordTool.cs +++ b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DeleteRecordTool.cs @@ -44,18 +44,18 @@ public Tool GetToolMetadata() return new Tool { Name = "delete_record", - Description = "Deletes a record from a table based on primary key or composite key", + Description = "STEP 1: describe_entities -> find entities with DELETE permission and their key fields. STEP 2: call this tool with full key values.", InputSchema = JsonSerializer.Deserialize( @"{ ""type"": ""object"", ""properties"": { ""entity"": { ""type"": ""string"", - ""description"": ""The name of the entity (table) as configured in dab-config. Required."" + ""description"": ""Entity name with DELETE permission."" }, ""keys"": { ""type"": ""object"", - ""description"": ""Primary key values to identify the record to delete. For composite keys, provide all key columns as properties. Required."" + ""description"": ""All key fields identifying the record."" } }, ""required"": [""entity"", ""keys""] diff --git a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs index 95c53d1d28..952eff61fc 100644 --- a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs +++ b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs @@ -33,21 +33,21 @@ public Tool GetToolMetadata() return new Tool { Name = "describe_entities", - Description = "Lists and describes all entities in the database, including their types and available operations.", + Description = "Lists all entities and metadata. ALWAYS CALL FIRST. Each entity includes: name, type, fields, parameters, and permissions. The permissions array defines which tools are allowed. 'ALL' expands by type: data->CREATE, READ, UPDATE, DELETE.", 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."" + ""description"": ""True: names and summaries only. False (default): full metadata."" }, ""entities"": { ""type"": ""array"", ""items"": { ""type"": ""string"" }, - ""description"": ""Optional list of specific entity names to filter by. If empty, all entities will be described."" + ""description"": ""Optional: specific entity names. Omit for all."" } } }" diff --git a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ExecuteEntityTool.cs b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ExecuteEntityTool.cs index c7734eea22..be2fa7af36 100644 --- a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ExecuteEntityTool.cs +++ b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ExecuteEntityTool.cs @@ -44,18 +44,18 @@ public Tool GetToolMetadata() return new Tool { Name = "execute_entity", - Description = "Executes a stored procedure or function, returns the results (if any)", + Description = "STEP 1: describe_entities -> find entities with EXECUTE permission and their parameters. STEP 2: call this tool with matching parameter values. Used for entities that perform actions or return computed results.", InputSchema = JsonSerializer.Deserialize( @"{ ""type"": ""object"", ""properties"": { ""entity"": { ""type"": ""string"", - ""description"": ""The entity name of the procedure or function to execute. Must match a stored-procedure entity as configured in dab-config. Required."" + ""description"": ""Entity name with EXECUTE permission."" }, ""parameters"": { ""type"": ""object"", - ""description"": ""A dictionary of parameter names and values to pass to the procedure. Parameters must match those defined in dab-config. Optional if no parameters."" + ""description"": ""Optional parameter names and values."" } }, ""required"": [""entity""] diff --git a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs index db1c761d2f..42b1f41ea0 100644 --- a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs +++ b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs @@ -35,37 +35,38 @@ public Tool GetToolMetadata() return new Tool { Name = "read_records", - Description = "Retrieves records from a given entity.", + Description = "STEP 1: describe_entities -> find entities with READ permission and their fields. STEP 2: call this tool with select, filter, sort, or pagination options.", InputSchema = JsonSerializer.Deserialize( @"{ ""type"": ""object"", ""properties"": { ""entity"": { ""type"": ""string"", - ""description"": ""The name of the entity to read, as provided by the describe_entities tool. Required."" + ""description"": ""Entity name with READ permission."" }, ""select"": { ""type"": ""string"", - ""description"": ""A comma-separated list of field names to include in the response. If omitted, all fields are returned. Optional."" + ""description"": ""Comma-separated field names."" }, ""filter"": { ""type"": ""string"", - ""description"": ""A case-insensitive OData-like expression that defines a query predicate. Supports logical grouping with parentheses and the operators eq, ne, gt, ge, lt, le, and, or, not. Examples: year ge 1990, date lt 2025-01-01T00:00:00Z, (title eq 'Foundation') and (available ne false). Optional."" - }, - ""first"": { - ""type"": ""integer"", - ""description"": ""The maximum number of records to return in the current page. Optional."" + ""description"": ""OData expression: eq, ne, gt, ge, lt, le, and, or, not."" }, ""orderby"": { ""type"": ""array"", ""items"": { ""type"": ""string"" }, - ""description"": ""A list of field names and directions for sorting, for example 'name asc' or 'year desc'. Optional."" + ""description"": ""Sort fields and directions, e.g., ['name asc', 'year desc']."" + }, + ""first"": { + ""type"": ""integer"", + ""description"": ""Max number of records (page size)."" }, ""after"": { ""type"": ""string"", - ""description"": ""A cursor token for retrieving the next page of results. Returned as 'after' in the previous response. Optional."" + ""description"": ""Cursor token for next page."" } - } + }, + ""required"": [""entity""] }" ) }; diff --git a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/UpdateRecordTool.cs b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/UpdateRecordTool.cs index 195a758454..9e7d101fe6 100644 --- a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/UpdateRecordTool.cs +++ b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/UpdateRecordTool.cs @@ -46,22 +46,22 @@ public Tool GetToolMetadata() return new Tool { Name = "update_record", - Description = "Updates an existing record in the specified entity. Requires 'keys' to locate the record and 'fields' to specify new values.", + Description = "STEP 1: describe_entities -> find entities with UPDATE permission and their key fields. STEP 2: call this tool with keys and new field values.", InputSchema = JsonSerializer.Deserialize( @"{ ""type"": ""object"", ""properties"": { ""entity"": { ""type"": ""string"", - ""description"": ""The name of the entity"" + ""description"": ""Entity name with UPDATE permission."" }, ""keys"": { ""type"": ""object"", - ""description"": ""Key fields and their values to identify the record"" + ""description"": ""Primary or composite keys identifying the record."" }, ""fields"": { ""type"": ""object"", - ""description"": ""Fields and their new values to update"" + ""description"": ""Fields and their new values."" } }, ""required"": [""entity"", ""keys"", ""fields""] From a4871efc849f6a829a6cfeef8b939132a698b72d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 20:19:42 +0000 Subject: [PATCH 3/4] Fix incorrect comment in DescribeEntitiesTool Co-authored-by: JerryNixon <1749983+JerryNixon@users.noreply.github.com> --- .../BuiltInTools/DescribeEntitiesTool.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs index 952eff61fc..71f91b79a6 100644 --- a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs +++ b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs @@ -25,7 +25,7 @@ public class DescribeEntitiesTool : IMcpTool public ToolType ToolType { get; } = ToolType.BuiltIn; /// - /// Gets the metadata for the delete-record tool, including its name, description, and input schema. + /// Gets the metadata for the describe-entities tool, including its name, description, and input schema. /// /// public Tool GetToolMetadata() From 96107e12f3fd65dde2213fcb84ba9ee59237a954 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 20:33:12 +0000 Subject: [PATCH 4/4] Expand describe_entities parameter descriptions for better clarity Co-authored-by: JerryNixon <1749983+JerryNixon@users.noreply.github.com> --- .../BuiltInTools/DescribeEntitiesTool.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs index 71f91b79a6..14e1e4db85 100644 --- a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs +++ b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs @@ -40,14 +40,14 @@ public Tool GetToolMetadata() ""properties"": { ""nameOnly"": { ""type"": ""boolean"", - ""description"": ""True: names and summaries only. False (default): full metadata."" + ""description"": ""If true, the response includes only entity names and short summaries, omitting detailed metadata such as fields, parameters, and permissions. Use this when the database contains many entities and the full payload would be too large. The usual strategy is: first call describe_entities with nameOnly=true to get a lightweight list, then call describe_entities again with nameOnly=false for specific entities that require full metadata. This flag is meant for discovery, not execution planning. The model must not assume that nameOnly=true provides enough detail for CRUD or EXECUTE operations."" }, ""entities"": { ""type"": ""array"", ""items"": { ""type"": ""string"" }, - ""description"": ""Optional: specific entity names. Omit for all."" + ""description"": ""Optional list of entity names to describe in full detail. Use this to reduce payload size when only certain entities are relevant. Do NOT pass both entities[] and nameOnly=true together, as that combination is nonsensical: nameOnly=true ignores detailed metadata, while entities[] explicitly requests it. Choose one approach—broad discovery with nameOnly=true OR targeted metadata with entities[]."" } } }"