Skip to content

Commit e18d0c4

Browse files
CopilotJerryNixonAniruddh25
authored andcommitted
Improve MCP tool descriptions for ChatGPT compatibility (#2937)
MCP `list_tools` descriptions were insufficiently clear for ChatGPT to understand tool usage patterns and workflows, while Claude handled them adequately. ## Changes Updated descriptions and input schemas for all 6 MCP tools: - **describe_entities**: Added "ALWAYS CALL FIRST" directive and clarified permissions structure (`'ALL'` expands by type: data→CREATE, READ, UPDATE, DELETE). Expanded `nameOnly` and `entities` parameter descriptions to include detailed usage guidance: - `nameOnly`: Explains when to use it (for discovery with many entities), the two-call strategy (first with `nameOnly=true`, then with specific entities), and warns that it doesn't provide enough detail for CRUD/EXECUTE operations - `entities`: Clarifies its purpose for targeted metadata retrieval and explicitly warns against combining it with `nameOnly=true` - **CRUD tools** (create_record, read_records, update_record, delete_record): Added explicit STEP 1→STEP 2 workflow (describe_entities first, then call with matching permissions/fields) - **execute_entity**: Added workflow guidance and clarified use case (actions/computed results) - **All tools**: Condensed parameter descriptions (e.g., "Comma-separated field names" vs. "A comma-separated list of field names to include in the response. If omitted, all fields are returned. Optional.") ## Example Before: ```csharp Description = "Creates a new record in the specified entity." ``` After: ```csharp Description = "STEP 1: describe_entities -> find entities with CREATE permission and their fields. STEP 2: call this tool with matching field names and values." ``` All changes are metadata-only; no functional code modified. <!-- START COPILOT CODING AGENT SUFFIX --> <details> <summary>Original prompt</summary> ---- *This section details on the original issue you should resolve* <issue_title>[BUG]: MCP `list_tools` need more comprehensive descriptions.</issue_title> <issue_description>## What? Our tools have descriptions already. They need better to help models. > Claude works but ChatGPT struggles to understand with our current descriptions. ## New descriptions ```json { "tools": [ { "name": "describe_entities", "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": { "type": "object", "properties": { "nameOnly": { "type": "boolean", "description": "True: names and summaries only. False (default): full metadata." }, "entities": { "type": "array", "items": { "type": "string" }, "description": "Optional: specific entity names. Omit for all." } } } }, { "name": "create_record", "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": { "type": "object", "properties": { "entity": { "type": "string", "description": "Entity name with CREATE permission." }, "data": { "type": "object", "description": "Required fields and values for the new record." } }, "required": ["entity", "data"] } }, { "name": "read_records", "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": { "type": "object", "properties": { "entity": { "type": "string", "description": "Entity name with READ permission." }, "select": { "type": "string", "description": "Comma-separated field names." }, "filter": { "type": "string", "description": "OData expression: eq, ne, gt, ge, lt, le, and, or, not." }, "orderby": { "type": "array", "items": { "type": "string" }, "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": "Cursor token for next page." } }, "required": ["entity"] } }, { "name": "update_record", "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": { "type": "object", "properties": { "entity": { "type": "string", "description": "Entity name with UPDATE permission." }, "keys": { "type": "object", "description": "Primary or composite keys identifying the record." }, "fields": { "type": "object", "description": "Fields and their new values." } }, "required": ["entity", "keys", "fields"] } }, { "name": "delete_record", "description": "STEP 1: describe_entities -> find entities with DELETE permission and their key fields. STEP 2: call this tool with full key values.", "inputSchema": { "type": "object", "properties": { "entity": { "type": "string", "description": "Entity name with DELETE permission." }, "keys": { "type": "object", "description": "All key fields identifying the record." } }, "required": ["entity", "keys"] } }, { "name": "execute_entity", "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": { "type": "object", "properties": { "entity": { "type": "string", "description": "Entity name with EXECUTE permission." }, "parameters": { "type": "object", "description": "Optional parameter names and values." } }, "required": ["entity"] } } ] } ``` </issue_description> <agent_instruction... </details> - Fixes #2936 <!-- START COPILOT CODING AGENT TIPS --> --- ✨ Let Copilot coding agent [set things up for you](https://github.com/Azure/data-api-builder/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo. --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: JerryNixon <[email protected]> Co-authored-by: Aniruddh Munde <[email protected]>
1 parent 5ba8682 commit e18d0c4

File tree

6 files changed

+29
-28
lines changed

6 files changed

+29
-28
lines changed

src/Azure.DataApiBuilder.Mcp/BuiltInTools/CreateRecordTool.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,18 @@ public Tool GetToolMetadata()
3131
return new Tool
3232
{
3333
Name = "create_record",
34-
Description = "Creates a new record in the specified entity.",
34+
Description = "STEP 1: describe_entities -> find entities with CREATE permission and their fields. STEP 2: call this tool with matching field names and values.",
3535
InputSchema = JsonSerializer.Deserialize<JsonElement>(
3636
@"{
3737
""type"": ""object"",
3838
""properties"": {
3939
""entity"": {
4040
""type"": ""string"",
41-
""description"": ""The name of the entity""
41+
""description"": ""Entity name with CREATE permission.""
4242
},
4343
""data"": {
4444
""type"": ""object"",
45-
""description"": ""The data for the new record""
45+
""description"": ""Required fields and values for the new record.""
4646
}
4747
},
4848
""required"": [""entity"", ""data""]

src/Azure.DataApiBuilder.Mcp/BuiltInTools/DeleteRecordTool.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,18 @@ public Tool GetToolMetadata()
4444
return new Tool
4545
{
4646
Name = "delete_record",
47-
Description = "Deletes a record from a table based on primary key or composite key",
47+
Description = "STEP 1: describe_entities -> find entities with DELETE permission and their key fields. STEP 2: call this tool with full key values.",
4848
InputSchema = JsonSerializer.Deserialize<JsonElement>(
4949
@"{
5050
""type"": ""object"",
5151
""properties"": {
5252
""entity"": {
5353
""type"": ""string"",
54-
""description"": ""The name of the entity (table) as configured in dab-config. Required.""
54+
""description"": ""Entity name with DELETE permission.""
5555
},
5656
""keys"": {
5757
""type"": ""object"",
58-
""description"": ""Primary key values to identify the record to delete. For composite keys, provide all key columns as properties. Required.""
58+
""description"": ""All key fields identifying the record.""
5959
}
6060
},
6161
""required"": [""entity"", ""keys""]

src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,29 @@ public class DescribeEntitiesTool : IMcpTool
2525
public ToolType ToolType { get; } = ToolType.BuiltIn;
2626

2727
/// <summary>
28-
/// Gets the metadata for the delete-record tool, including its name, description, and input schema.
28+
/// Gets the metadata for the describe-entities tool, including its name, description, and input schema.
2929
/// </summary>
3030
/// <returns></returns>
3131
public Tool GetToolMetadata()
3232
{
3333
return new Tool
3434
{
3535
Name = "describe_entities",
36-
Description = "Lists and describes all entities in the database, including their types and available operations.",
36+
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.",
3737
InputSchema = JsonSerializer.Deserialize<JsonElement>(
3838
@"{
3939
""type"": ""object"",
4040
""properties"": {
4141
""nameOnly"": {
4242
""type"": ""boolean"",
43-
""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.""
43+
""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.""
4444
},
4545
""entities"": {
4646
""type"": ""array"",
4747
""items"": {
4848
""type"": ""string""
4949
},
50-
""description"": ""Optional list of specific entity names to filter by. If empty, all entities will be described.""
50+
""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[].""
5151
}
5252
}
5353
}"

src/Azure.DataApiBuilder.Mcp/BuiltInTools/ExecuteEntityTool.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,18 @@ public Tool GetToolMetadata()
4444
return new Tool
4545
{
4646
Name = "execute_entity",
47-
Description = "Executes a stored procedure or function, returns the results (if any)",
47+
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.",
4848
InputSchema = JsonSerializer.Deserialize<JsonElement>(
4949
@"{
5050
""type"": ""object"",
5151
""properties"": {
5252
""entity"": {
5353
""type"": ""string"",
54-
""description"": ""The entity name of the procedure or function to execute. Must match a stored-procedure entity as configured in dab-config. Required.""
54+
""description"": ""Entity name with EXECUTE permission.""
5555
},
5656
""parameters"": {
5757
""type"": ""object"",
58-
""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.""
58+
""description"": ""Optional parameter names and values.""
5959
}
6060
},
6161
""required"": [""entity""]

src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,37 +35,38 @@ public Tool GetToolMetadata()
3535
return new Tool
3636
{
3737
Name = "read_records",
38-
Description = "Retrieves records from a given entity.",
38+
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.",
3939
InputSchema = JsonSerializer.Deserialize<JsonElement>(
4040
@"{
4141
""type"": ""object"",
4242
""properties"": {
4343
""entity"": {
4444
""type"": ""string"",
45-
""description"": ""The name of the entity to read, as provided by the describe_entities tool. Required.""
45+
""description"": ""Entity name with READ permission.""
4646
},
4747
""select"": {
4848
""type"": ""string"",
49-
""description"": ""A comma-separated list of field names to include in the response. If omitted, all fields are returned. Optional.""
49+
""description"": ""Comma-separated field names.""
5050
},
5151
""filter"": {
5252
""type"": ""string"",
53-
""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.""
54-
},
55-
""first"": {
56-
""type"": ""integer"",
57-
""description"": ""The maximum number of records to return in the current page. Optional.""
53+
""description"": ""OData expression: eq, ne, gt, ge, lt, le, and, or, not.""
5854
},
5955
""orderby"": {
6056
""type"": ""array"",
6157
""items"": { ""type"": ""string"" },
62-
""description"": ""A list of field names and directions for sorting, for example 'name asc' or 'year desc'. Optional.""
58+
""description"": ""Sort fields and directions, e.g., ['name asc', 'year desc'].""
59+
},
60+
""first"": {
61+
""type"": ""integer"",
62+
""description"": ""Max number of records (page size).""
6363
},
6464
""after"": {
6565
""type"": ""string"",
66-
""description"": ""A cursor token for retrieving the next page of results. Returned as 'after' in the previous response. Optional.""
66+
""description"": ""Cursor token for next page.""
6767
}
68-
}
68+
},
69+
""required"": [""entity""]
6970
}"
7071
)
7172
};

src/Azure.DataApiBuilder.Mcp/BuiltInTools/UpdateRecordTool.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,22 @@ public Tool GetToolMetadata()
4646
return new Tool
4747
{
4848
Name = "update_record",
49-
Description = "Updates an existing record in the specified entity. Requires 'keys' to locate the record and 'fields' to specify new values.",
49+
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.",
5050
InputSchema = JsonSerializer.Deserialize<JsonElement>(
5151
@"{
5252
""type"": ""object"",
5353
""properties"": {
5454
""entity"": {
5555
""type"": ""string"",
56-
""description"": ""The name of the entity""
56+
""description"": ""Entity name with UPDATE permission.""
5757
},
5858
""keys"": {
5959
""type"": ""object"",
60-
""description"": ""Key fields and their values to identify the record""
60+
""description"": ""Primary or composite keys identifying the record.""
6161
},
6262
""fields"": {
6363
""type"": ""object"",
64-
""description"": ""Fields and their new values to update""
64+
""description"": ""Fields and their new values.""
6565
}
6666
},
6767
""required"": [""entity"", ""keys"", ""fields""]

0 commit comments

Comments
 (0)