Skip to content

Dev/backport mcp entity level config#3251

Open
anushakolan wants to merge 3 commits intorelease/1.7from
dev/backport-mcp-entity-level-config
Open

Dev/backport mcp entity level config#3251
anushakolan wants to merge 3 commits intorelease/1.7from
dev/backport-mcp-entity-level-config

Conversation

@anushakolan
Copy link
Contributor

@anushakolan anushakolan commented Mar 13, 2026

Why make this change?

This backport fixes MCP behavior where create_record incorrectly rejected view-backed entities with the error that the tool is only available for tables.

Views are a required workaround for unsupported SQL data types in some scenarios (e.g., vector columns), so this fix restores expected INSERT behavior for those entities.

Note: This backport includes prerequisite PRs #2989 and #3084 which were not previously in release/1.7 but are required for the test infrastructure.

What is this change?

Cherry-picked PR:

  1. Add entity-level MCP configuration support Add entity-level MCP configuration support #2989
  2. Entity level check if MCP Tool is enabled Entity level check if MCP Tool is enabled #3084
  3. fix(mcp): allow create_record for views and add tests to verify behavior fix(mcp): allow create_record for views and added tests to verify the same. #3196

How was this tested?

  1. Existing and newly added tests in the source PR.
  2. Manual verification of create_record against view-backed entities.

Sample Request(s)

N/A

souvikghosh04 and others added 3 commits March 13, 2026 12:35
This change allows entity-level MCP configuration to control which
entities participate in MCP runtime tools, providing granular control
over DML operations and custom tool exposure.

- Closes on #2948

This change introduces an optional mcp property at the entity level that
controls participation in MCP's runtime tools. This is a prerequisite
for custom tools support.

The MCP property supports two formats:

- **Boolean shorthand**: `"mcp": true` or `"mcp": false`
- **Object format**: `{"dml-tools": boolean, "custom-tool": boolean}`

Property Behavior:

1. Boolean Shorthand (`"mcp": true/false`)

- `"mcp": true`: Enables DML tools only; custom tools remain disabled.
- `"mcp": false`: Disables all MCP functionality for the entity.

2. Object Format `("mcp": { ... })`

- `{ "dml-tools": true, "custom-tool": true }`: Enables both (valid only
for stored procedures).
- `{ "dml-tools": true, "custom-tool": false }`: DML only.
- `{ "dml-tools": false, "custom-tool": true }`: Custom tool only
(stored procedures).
- `{ "dml-tools": false, "custom-tool": false }`: Fully disabled.

Single-property cases:

- `{"dml-tools": true}`: Enables DML only; auto-serializes to `"mcp":
true`.
- `{"custom-tool": true}`: Enables custom tool only; serializes as
given.

3. No MCP Configuration in Entity (default)
- `dml-tools` will still be enabled by default and no other change is
behavior

- [x] Unit Tests
- [x] Integrations Tests
- [x] CLI Command Testing

Sample CLI commands:

Add table with DML tools enabled

`dab add Book --source books --permissions "anonymous:*" --mcp.dml-tools
true`

Add stored procedure with custom tool enabled

`dab add GetBookById --source dbo.get_book_by_id --source.type
stored-procedure --permissions "anonymous:execute" --mcp.custom-tool
true`

Add stored procedure with both properties

`dab add UpdateBook --source dbo.update_book --source.type
stored-procedure --permissions "anonymous:execute" --mcp.custom-tool
true --mcp.dml-tools false`
- Closes on #3017

The entity-level MCP configuration (`Entity.Mcp.DmlToolEnabled` or
`Entity.Mcp.CustomToolEnabled`) can override runtime-level settings.
`DmlToolEnabled` defaults to true when unspecified, while
`CustomToolEnabled` defaults to false.
However, this entity-level configuration was not being checked by the
MCP tools when they execute. The tools only checked the runtime-level
configuration (e.g. `RuntimeConfig.McpDmlTools.ReadRecords`, etc.).
This change addresses this gap for both built-in/DML tools and custom
tools by adding entity-level validation before tool execution.

- Added entity-level configuration checks to all 6 MCP tools (5 DML
tools + 1 custom tool) that validate entity-specific flags before
executing operations
- DML tools (read_records, create_record, update_record, delete_record,
execute_entity) now check `entity.Mcp.DmlToolEnabled` and return a
`ToolDisabled` error when disabled at the entity level.
- DynamicCustomTool checks `entity.Mcp.CustomToolEnabled` and return a
`ToolDisabled` error
- Tests covering various scenarios

- [ ] Integration Tests
- [x] Unit Tests

Not applicable since it's a config level change and have been tested
based on config settings.

---------

Co-authored-by: Aniruddh Munde <anmunde@microsoft.com>
… same. (#3196)

## Why make this change?
Closes #3194 - MCP `create_record` tool incorrectly blocks views with
error `"The create_record tool is only available for tables."`
1. Views are the required workaround for unsupported SQL data types
(e.g., vector columns). Users could create views that omit unsupported
columns and perform DML operations against those views.
2. This bug prevents INSERT operations via MCP on view entities,
breaking a critical workflow for vector database scenarios.

## What is this change?

1. Modified `CreateRecordTool.cs` to allow both tables and views to pass
source type validation
2. Changed `else` block (which caught views) to`else if
(EntitySourceType.StoredProcedure)` so only stored procedures are
blocked
3. Views now fall through to the mutation engine, which already supports
INSERT on updateable views
4. Updated error message to `"The create_record tool is only available
for tables and views."`
5. Added 8 unit tests validating all DML tools (CreateRecord,
ReadRecords, UpdateRecord, DeleteRecord) work with both Table and View
source types

## How was this tested?

- [ ] Integration Tests
- [X] Unit Tests
1. `DmlTool_AllowsTablesAndViews` - 8 DataRow test cases verifying no
`InvalidCreateTarget` error for views
2. Existing REST integration tests `InsertOneInViewTest` already
validate view INSERT via same mutation engine

Manually tested via MCP Inspector, to verify `create_record` calls
succeeds on a view.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Aniruddh Munde <anmunde@microsoft.com>
@anushakolan anushakolan marked this pull request as ready for review March 13, 2026 19:45
Copilot AI review requested due to automatic review settings March 13, 2026 19:45
@anushakolan
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 6 pipeline(s).

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

Backports MCP entity-level configuration support into release/1.7, adds CLI/schema support for the new entities.<name>.mcp settings, and fixes MCP DML tooling behavior so create_record supports view-backed entities (plus associated tests).

Changes:

  • Add entity-level MCP config model + JSON (de)serialization support and expose it through CLI add/update flags.
  • Enforce entity-level enablement checks in MCP tools (DML + custom tools), and allow create_record for view entities.
  • Add/extend unit tests and JSON schema updates covering entity-level MCP config and tool behavior.

Reviewed changes

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

Show a summary per file
File Description
src/Service.Tests/ModuleInitializer.cs Updates snapshot verification settings to ignore new MCP user-provided flags.
src/Service.Tests/Mcp/EntityLevelDmlToolConfigurationTests.cs Adds MCP tool execution tests for entity-level enablement and view/table support.
src/Service.Tests/Configuration/EntityMcpConfigurationTests.cs Adds config deserialization/validation tests for entity-level mcp formats.
src/Config/RuntimeConfigLoader.cs Registers the new entity-level MCP converter for config JSON parsing/serialization.
src/Config/ObjectModel/EntityMcpOptions.cs Introduces the entity-level MCP options model and user-provided flags.
src/Config/ObjectModel/Entity.cs Adds Entity.Mcp to the object model and wires converter usage.
src/Config/Converters/EntityMcpOptionsConverterFactory.cs Implements boolean/object JSON forms for entities.<name>.mcp.
src/Cli/Utils.cs Adds CLI parsing/validation helper for MCP entity options.
src/Cli/ConfigGenerator.cs Plumbs MCP options through dab add/dab update entity generation.
src/Cli/Commands/UpdateOptions.cs Adds MCP CLI parameters to update options plumbing.
src/Cli/Commands/EntityOptions.cs Adds --mcp.dml-tools and --mcp.custom-tool options.
src/Cli/Commands/AddOptions.cs Adds MCP CLI parameters to add options plumbing.
src/Cli.Tests/UpdateEntityTests.cs Adds CLI update tests covering MCP entity option behavior/validation.
src/Cli.Tests/ModuleInitializer.cs Updates snapshot verification settings to ignore new MCP user-provided flags.
src/Cli.Tests/AddEntityTests.cs Adds CLI add tests covering MCP entity option behavior/validation.
src/Azure.DataApiBuilder.Mcp/Utils/McpErrorHelpers.cs Extends ToolDisabled helper to optionally use a custom message.
src/Azure.DataApiBuilder.Mcp/Core/DynamicCustomTool.cs Adds runtime entity-level enablement validation for custom tools (hot-reload scenario).
src/Azure.DataApiBuilder.Mcp/BuiltInTools/UpdateRecordTool.cs Adds entity-level DML enablement checks + validates table/view targets.
src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs Adds entity-level DML enablement checks + validates table/view targets.
src/Azure.DataApiBuilder.Mcp/BuiltInTools/ExecuteEntityTool.cs Adds entity-level DML enablement check and hardens null entity map handling.
src/Azure.DataApiBuilder.Mcp/BuiltInTools/DeleteRecordTool.cs Adds entity-level DML enablement checks.
src/Azure.DataApiBuilder.Mcp/BuiltInTools/CreateRecordTool.cs Allows view targets (skips table-only validation) + adds entity-level DML checks.
schemas/dab.draft.schema.json Documents/defines entity-level mcp schema and adds stored-proc constraint for custom tools.

Comment on lines +1175 to +1186
"if": {
"properties": {
"mcp": {
"properties": {
"custom-tool": {
"const": true
}
}
}
},
"required": ["mcp"]
},
Comment on lines +88 to +121
public override void Write(Utf8JsonWriter writer, EntityMcpOptions value, JsonSerializerOptions options)
{
if (value == null)
{
return;
}

// Check if we should write as boolean shorthand
// Write as boolean if: only dml-tools is set (or custom-tool is default false)
bool writeAsBoolean = !value.UserProvidedCustomToolEnabled && value.UserProvidedDmlToolsEnabled;

if (writeAsBoolean)
{
// Write as boolean shorthand
writer.WriteBooleanValue(value.DmlToolEnabled);
}
else if (value.UserProvidedCustomToolEnabled || value.UserProvidedDmlToolsEnabled)
{
// Write as object
writer.WriteStartObject();

if (value.UserProvidedCustomToolEnabled)
{
writer.WriteBoolean("custom-tool", value.CustomToolEnabled);
}

if (value.UserProvidedDmlToolsEnabled)
{
writer.WriteBoolean("dml-tools", value.DmlToolEnabled);
}

writer.WriteEndObject();
}
}
Comment on lines +1670 to +1671
// Keep existing MCP options if no updates provided
updatedMcpOptions = entity.Mcp;
// Assert
Assert.IsTrue(result.IsError == true, "Expected error when entity has DmlToolEnabled=false");

JsonElement content = await RunToolAsync(tool, arguments, serviceProvider);
CancellationToken cancellationToken = default)
{
ILogger<DynamicCustomTool>? logger = serviceProvider.GetService<ILogger<DynamicCustomTool>>();
string toolName = GetToolMetadata().Name;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants