Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 29, 2025

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:

Description = "Creates a new record in the specified entity."

After:

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.

Original prompt

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

{
  "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...


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits October 29, 2025 20:17
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] Improve descriptions for MCP list_tools Improve MCP tool descriptions for ChatGPT compatibility Oct 29, 2025
Copilot AI requested a review from JerryNixon October 29, 2025 20:26
Copilot finished work on behalf of JerryNixon October 29, 2025 20:26
@JerryNixon
Copy link
Contributor

@copilot Can we make describe even more clear?

{
  "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": "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 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[]."
      }
    }
  }
}

Co-authored-by: JerryNixon <1749983+JerryNixon@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Oct 29, 2025

@copilot Can we make describe even more clear?

...

Updated the describe_entities parameter descriptions with the more comprehensive explanations in commit 96107e1.

The nameOnly description now includes:

  • When to use it (for discovery with many entities)
  • The two-call strategy (first with nameOnly=true, then with specific entities)
  • Warning that it's not sufficient for CRUD/EXECUTE operations

The entities description now includes:

  • Guidance on reducing payload size
  • Explicit warning not to combine with nameOnly=true
  • Clear choice between broad discovery vs targeted metadata approaches

Copilot finished work on behalf of JerryNixon October 29, 2025 20:34
Copy link
Contributor

@JerryNixon JerryNixon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just as requested.

@JerryNixon JerryNixon marked this pull request as ready for review October 29, 2025 20:46
Copilot AI review requested due to automatic review settings October 29, 2025 20:46
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request enhances the tool descriptions and parameter documentation across all built-in MCP tools to provide clearer guidance for AI agents. The changes emphasize a two-step workflow pattern and make parameter descriptions more concise.

  • Introduced consistent "STEP 1: describe_entities → STEP 2: call this tool" workflow across CRUD and execute operations
  • Simplified and clarified parameter descriptions to be more concise while maintaining necessary information
  • Added explicit permission requirements to entity descriptions and corrected a comment typo in DescribeEntitiesTool

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
UpdateRecordTool.cs Updated tool and parameter descriptions to emphasize two-step workflow and clarify UPDATE permission requirement
ReadRecordsTool.cs Streamlined descriptions, added two-step workflow pattern, moved first parameter position, and added required fields
ExecuteEntityTool.cs Enhanced description with two-step workflow and clarified EXECUTE permission context
DescribeEntitiesTool.cs Fixed comment typo, expanded main description with permission details, and significantly enhanced nameOnly and entities parameter documentation
DeleteRecordTool.cs Updated to follow two-step workflow pattern and simplified parameter descriptions
CreateRecordTool.cs Added two-step workflow guidance and clarified CREATE permission requirements
Comments suppressed due to low confidence (2)

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

  • This description is excessively long for a JSON schema field description (over 500 characters). Consider condensing it to focus on the essential behavior: what the flag does and when to use it. The detailed usage strategy and warnings could be documented in code comments or external documentation instead.
// Copyright (c) Microsoft Corporation.

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

  • This description is overly verbose (over 400 characters) and contains prescriptive guidance about parameter combinations that would be better enforced through input validation or documented elsewhere. Consider simplifying to: 'Optional list of specific entity names to describe in detail. Filters the response to only the specified entities.'
// Copyright (c) Microsoft Corporation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Collaborator

@Aniruddh25 Aniruddh25 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/azp run

@Aniruddh25
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 6 pipeline(s).

@JerryNixon JerryNixon self-requested a review October 31, 2025 17:01
Copy link
Contributor

@aaronburtle aaronburtle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@Aniruddh25 Aniruddh25 enabled auto-merge (squash) October 31, 2025 18:42
@Aniruddh25 Aniruddh25 merged commit 21dde31 into main Oct 31, 2025
11 checks passed
@Aniruddh25 Aniruddh25 deleted the copilot/improve-list-tools-descriptions branch October 31, 2025 19:07
souvikghosh04 pushed a commit that referenced this pull request Nov 10, 2025
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] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: JerryNixon <1749983+JerryNixon@users.noreply.github.com>
Co-authored-by: Aniruddh Munde <anmunde@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: MCP list_tools need more comprehensive descriptions.

5 participants