Filter resources with resource.excludeFromMcp from CLI MCP tools#18106
Conversation
Resources marked with the resource.excludeFromMcp property are now excluded from all MCP tool results: - ListResourcesTool filters them from resource listings - ListConsoleLogsTool and ExecuteResourceCommandTool reject requests targeting excluded resources - ListStructuredLogsTool, ListTracesTool, and ListTraceStructuredLogsTool filter out telemetry from excluded resources - McpResourceToolRefreshService skips excluded resources Added McpToolHelpers with IsExcludedFromMcp, CheckResourceExcludedAsync, GetExcludedResourceNamesAsync, and GetResourceNotAvailableMessage helpers. Includes comprehensive unit tests covering all filtering scenarios.
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 18106Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 18106" |
There was a problem hiding this comment.
Pull request overview
This PR adds filtering for resources marked with the resource.excludeFromMcp property across all CLI MCP tools. It introduces a central McpToolHelpers utility with methods to check exclusion status and provides consistent behavior: resource listing tools filter excluded resources out, tools requiring a resource name return an error for excluded resources, and telemetry tools filter out data from excluded resources post-fetch.
Changes:
- Added
McpToolHelpersmethods (IsExcludedFromMcp,CheckResourceExcludedAsync,GetExcludedResourceNamesAsync) for centralized exclusion logic - Integrated exclusion checks into all MCP tools (
ListResourcesTool,ListConsoleLogsTool,ExecuteResourceCommandTool,ListStructuredLogsTool,ListTracesTool,ListTraceStructuredLogsTool,McpResourceToolRefreshService) - Added comprehensive test suite in
ExcludeFromMcpTests.cscovering the helper methods and all major tool exclusion scenarios
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/Aspire.Cli/Mcp/Tools/McpToolHelpers.cs | Adds IsExcludedFromMcp, GetResourceNotAvailableMessage, CheckResourceExcludedAsync, and GetExcludedResourceNamesAsync helper methods |
| src/Aspire.Cli/Mcp/Tools/ListResourcesTool.cs | Filters excluded resources from the snapshot list before rendering |
| src/Aspire.Cli/Mcp/Tools/ListConsoleLogsTool.cs | Rejects requests for excluded resources with an error |
| src/Aspire.Cli/Mcp/Tools/ExecuteResourceCommandTool.cs | Rejects commands targeting excluded resources with an error |
| src/Aspire.Cli/Mcp/Tools/ListStructuredLogsTool.cs | Adds IAuxiliaryBackchannelMonitor? parameter; checks specific resource exclusion early and filters post-fetch when unscoped |
| src/Aspire.Cli/Mcp/Tools/ListTracesTool.cs | Adds IAuxiliaryBackchannelMonitor? parameter; checks specific resource exclusion early and filters spans post-fetch when unscoped |
| src/Aspire.Cli/Mcp/Tools/ListTraceStructuredLogsTool.cs | Adds IAuxiliaryBackchannelMonitor? parameter; filters excluded resource logs post-fetch |
| src/Aspire.Cli/Mcp/McpResourceToolRefreshService.cs | Excludes resources with excludeFromMcp from tool registration |
| src/Aspire.Cli/Commands/AgentMcpCommand.cs | Passes IAuxiliaryBackchannelMonitor (or null in dashboard-only mode) to telemetry tool constructors |
| tests/Aspire.Cli.Tests/Mcp/ExcludeFromMcpTests.cs | New test file covering exclusion logic for helper methods and 6 tools |
| tests/Aspire.Cli.Tests/Mcp/ListTracesToolTests.cs | Updates CreateTool helper to pass the new monitor parameter |
| tests/Aspire.Cli.Tests/Mcp/ListStructuredLogsToolTests.cs | Updates CreateTool helper to pass the new monitor parameter |
PR E2E Testing ReportSetup
Test Results
Detailslist_resourcesThe response contains 4 resources: The list_console_logs("apiservice"){"isError": true, "content": [{"text": "Resource 'apiservice' is not available."}]}list_console_logs("webfrontend")Overall Result✅ PR VERIFIED — ExcludeFromMcp filtering works correctly end-to-end. |
- Add two tests for ListTraceStructuredLogsTool filtering:
- FiltersExcludedResourceLogs: verifies excluded resource logs are
removed from trace-scoped structured log results
- ReturnsAllLogs_WhenNoResourcesExcluded: verifies no filtering when
no resources are excluded
- Add doesNotContainMarker parameter to CallAgentMcpToolAsync helper
- Add AgentMcpExcludeFromMcpTests E2E test that verifies list_resources
excludes resources marked with ExcludeFromMcp()
Add overloads of CheckResourceExcludedAsync and GetExcludedResourceNamesAsync that accept IAppHostAuxiliaryBackchannel directly. Update ListConsoleLogsTool and ExecuteResourceCommandTool to use the connection they already obtained, eliminating a redundant GetSelectedConnectionAsync + GetResourceSnapshotsAsync call per request.
The test was timing out because the Redis container's health check never passed in the Docker-in-Docker CI environment, causing webfrontend (which has WaitFor(cache)) to stay stuck in Waiting state. Redis is irrelevant to this test — it only verifies ExcludeFromMcp() filtering. Disabling Redis removes the container dependency.
|
❌ CLI E2E Tests failed — 113 passed, 1 failed, 2 unknown (commit ❌ Failed Tests
View all recordings
📹 Recordings uploaded automatically from CI run #27328001371 |
mitchdenny
left a comment
There was a problem hiding this comment.
Approved. You may want to look at the seemingly false alarm in the CLI E2E test output.
|
@copilot verify if the failing Cli E2E test in #18106 (comment) is related to this PR. |
I checked the CLI E2E report in that comment. The failing test is |
|
/backport to release/13.4 |
|
Started backporting to |
Description
Resources marked with the
resource.excludeFromMcpproperty are now filtered out from all CLI MCP tool results:Added
McpToolHelperswith the following internal methods:IsExcludedFromMcp(ResourceSnapshot)— checks the property value (supports bool and string representations)CheckResourceExcludedAsync(...)— returns an errorCallToolResultif excludedGetExcludedResourceNamesAsync(...)— returns the set of excluded resource namesGetResourceNotAvailableMessage(resourceName)— produces the standard error messageFollow-up changes based on review feedback:
ListTraceStructuredLogsToolunit coverage for excluded-resource filteringlist_resourcesexcludes a resource marked withExcludeFromMcp()IAppHostAuxiliaryBackchannelcan reuse that connection instead of doing an extra lookupChecklist
<remarks />and<code />elements on your triple slash comments?