Skip to content

Conversation

@souvikghosh04
Copy link
Contributor

@souvikghosh04 souvikghosh04 commented Jan 22, 2026

Why make this change?

With custom tools, stored procedure entities could get listed in describe_entities even when they are configured as custom-tool-only (with dml-tools: false). This creates duplication since they already appear in tools/list. We need to filter stored procedures with dml-tools: false from describe_entities to avoid this duplication.

What is this change?

  • Added filtering logic to exclude stored procedure entities when dml-tools is explicitly set to false
  • The filtering ensures stored procedures are removed from describe_entities only when they are custom-tool-only (not available for DML operations)
  • Stored procedures with dml-tools: true (or null/default) continue to appear in describe_entities even if they have custom-tool: true, allowing dual exposure when needed

How was this tested?

  • Unit Tests
  • Manual Tests

Sample Request(s)

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "describe_entities"
  },
  "id": 1
}
@souvikghosh04 souvikghosh04 requested a review from Copilot January 22, 2026 08:14
@souvikghosh04 souvikghosh04 self-assigned this Jan 22, 2026
@souvikghosh04 souvikghosh04 added mssql an issue thats specific to mssql mcp-server labels Jan 22, 2026
@souvikghosh04 souvikghosh04 added this to the Jan 2026 milestone Jan 22, 2026
@souvikghosh04 souvikghosh04 linked an issue Jan 22, 2026 that may be closed by this pull request
@souvikghosh04 souvikghosh04 moved this from Todo to In Progress in Data API builder Jan 22, 2026
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 PR prevents stored-procedure entities that are already exposed as dedicated custom MCP tools from being duplicated in the describe_entities response.

Changes:

  • Added filtering in DescribeEntitiesTool to skip stored procedures with entity.Mcp.CustomToolEnabled == true.
  • Added new MSTest coverage validating stored procedure filtering and ensuring tables/views remain unaffected.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/Azure.DataApiBuilder.Mcp/BuiltInTools/DescribeEntitiesTool.cs Filters out custom-tool-enabled stored procedures from describe_entities results.
src/Service.Tests/Mcp/DescribeEntitiesFilteringTests.cs Adds tests verifying filtering behavior across stored procedures, tables/views, and nameOnly mode.

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

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

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.


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

@souvikghosh04
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 6 pipeline(s).
@JerryNixon
Copy link
Contributor

JerryNixon commented Jan 22, 2026

Desired logic

DML TOOLS = TRUE DML TOOLS = FALSE
CUSTOM TOOL = TRUE ✔ describe_entities
✔ tools/list
✘ describe_entities
✔ tools/list
CUSTOM TOOL = FALSE ✔ describe_entities
✘ tools/list
✘ describe_entities
✘ tools/list
@souvikghosh04 souvikghosh04 changed the title [MCP] Prevent duplicating tool list between custom tools and describe Jan 23, 2026
@RubenCerna2079 RubenCerna2079 self-assigned this Jan 28, 2026
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.

Waiting on what needs to be done for non stored proc entities

@github-project-automation github-project-automation bot moved this from In Progress to Review In Progress in Data API builder Jan 29, 2026
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

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.


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

Comment on lines +162 to +170
// Filter out entities when dml-tools is explicitly disabled (false).
// This applies to all entity types (tables, views, stored procedures).
// When dml-tools is false, the entity is not exposed via DML tools
// (read_records, create_record, etc.) and should not appear in describe_entities.
if (entity.Mcp?.DmlToolEnabled == false)
{
filteredDmlDisabledCount++;
continue;
}
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The new filtering block excludes any entity with entity.Mcp?.DmlToolEnabled == false, regardless of entity type or CustomToolEnabled. This is broader than the PR description (stored-procedure, custom-tool-only de-duplication). If the intent is only to avoid duplication with custom tools, restrict the condition to stored procedures where CustomToolEnabled == true and DmlToolEnabled == false; otherwise, please update the PR description/tests to reflect the expanded behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +166 to 173
if (entity.Mcp?.DmlToolEnabled == false)
{
filteredDmlDisabledCount++;
continue;
}

if (!ShouldIncludeEntity(entityName, entityFilter))
{
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

filteredDmlDisabledCount is incremented before applying ShouldIncludeEntity(entityName, entityFilter). When callers pass the entities filter argument, this can count (and later log) entities that were never requested, making the filtered/returned counts misleading. Consider moving the entityFilter check before this block, or only increment/log for entities that pass the filter.

Suggested change
if (entity.Mcp?.DmlToolEnabled == false)
{
filteredDmlDisabledCount++;
continue;
}
if (!ShouldIncludeEntity(entityName, entityFilter))
{
if (!ShouldIncludeEntity(entityName, entityFilter))
{
continue;
}
if (entity.Mcp?.DmlToolEnabled == false)
{
filteredDmlDisabledCount++;
Copilot uses AI. Check for mistakes.
logger?.LogInformation(
"DescribeEntitiesTool: {FilteredCount} entity(ies) filtered with DML tools disabled (dml-tools: false). " +
"These entities are not exposed via DML tools and do not appear in describe_entities response. " +
"Returned {ReturnedCount} entities, filtered {FilteredCount}.",
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The log template repeats the {FilteredCount} placeholder name twice and requires passing the same argument twice. Consider removing the duplicate placeholder (or renaming one of them) to avoid duplicate structured-log keys and to simplify the call site.

Suggested change
"Returned {ReturnedCount} entities, filtered {FilteredCount}.",
"Returned {ReturnedCount} entities, filtered {FilteredCountTotal}.",
Copilot uses AI. Check for mistakes.
Comment on lines +23 to +28
/// <summary>
/// Tests for DescribeEntitiesTool filtering logic (GitHub issue #3043).
/// Ensures stored procedures with custom-tool enabled are excluded from describe_entities results
/// to prevent duplication (they appear in tools/list instead).
/// Regular entities (tables, views, non-custom-tool SPs) remain visible in describe_entities.
/// </summary>
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The XML doc comments describe the behavior as “custom-tool stored procedures are excluded”, but the tests in this file also cover (and the implementation enforces) filtering any entity with dml-tools: false (including tables/views). Please update the class/test comments to match the actual behavior being validated.

Copilot uses AI. Check for mistakes.

/// <summary>
/// Test that NoEntitiesConfigured error is returned when runtime config truly has no entities.
/// This is different from AllEntitiesFilteredAsCustomTools where entities exist but are filtered.
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

This comment references AllEntitiesFilteredAsCustomTools, but the implementation/test suite uses AllEntitiesFilteredDmlDisabled. Please update the comment to avoid confusion.

Suggested change
/// This is different from AllEntitiesFilteredAsCustomTools where entities exist but are filtered.
/// This is different from AllEntitiesFilteredDmlDisabled where entities exist but are filtered.
Copilot uses AI. Check for mistakes.
Comment on lines +178 to +183
/// Verifies that when some (but not all) entities are filtered as custom-tool-only,
/// the filtering is logged but does not affect the response content.
/// The response should contain only the non-filtered entities.
/// </summary>
[TestMethod]
public async Task DescribeEntities_LogsFilteringInfo_WhenSomeEntitiesFiltered()
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

DescribeEntities_LogsFilteringInfo_WhenSomeEntitiesFiltered doesn’t currently assert anything about logging (it only validates response content/count). Either capture/assert log output (e.g., via a test logger) or rename/reword the test to reflect what it actually verifies.

Suggested change
/// Verifies that when some (but not all) entities are filtered as custom-tool-only,
/// the filtering is logged but does not affect the response content.
/// The response should contain only the non-filtered entities.
/// </summary>
[TestMethod]
public async Task DescribeEntities_LogsFilteringInfo_WhenSomeEntitiesFiltered()
/// Verifies that when some (but not all) entities are configured as custom-tool-only,
/// those entities are filtered from the describe_entities response while others remain.
/// The response should contain only the non-filtered entities and the count should match.
/// </summary>
[TestMethod]
public async Task DescribeEntities_FiltersCustomToolOnlyEntities_WhenSomeEntitiesFiltered()
Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mcp-server mssql an issue thats specific to mssql

5 participants