Skip to content

Filter resources with resource.excludeFromMcp from CLI MCP tools - #18106

Merged
Ankit Jain (radical) merged 6 commits into
mainfrom
feature/mcp-exclude-from-mcp-filtering
Jun 11, 2026
Merged

Filter resources with resource.excludeFromMcp from CLI MCP tools#18106
Ankit Jain (radical) merged 6 commits into
mainfrom
feature/mcp-exclude-from-mcp-filtering

Conversation

@JamesNK

@JamesNKJames Newton-King (JamesNK) commented Jun 11, 2026

Copy link
Copy Markdown
Member

Description

Resources marked with the resource.excludeFromMcp property are now filtered out from all CLI MCP tool results:

  • ListResourcesTool filters excluded resources from resource listings
  • ListConsoleLogsTool and ExecuteResourceCommandTool reject requests targeting excluded resources with a "not available" error
  • ListStructuredLogsTool, ListTracesTool, and ListTraceStructuredLogsTool filter out telemetry data from excluded resources (both when querying a specific resource and when returning all data)
  • McpResourceToolRefreshService skips excluded resources when refreshing tool registrations

Added McpToolHelpers with the following internal methods:

  • IsExcludedFromMcp(ResourceSnapshot) — checks the property value (supports bool and string representations)
  • CheckResourceExcludedAsync(...) — returns an error CallToolResult if excluded
  • GetExcludedResourceNamesAsync(...) — returns the set of excluded resource names
  • GetResourceNotAvailableMessage(resourceName) — produces the standard error message

Follow-up changes based on review feedback:

  • Added ListTraceStructuredLogsTool unit coverage for excluded-resource filtering
  • Added an end-to-end CLI MCP test that verifies list_resources excludes a resource marked with ExcludeFromMcp()
  • Updated the exclusion helpers so tools that already have an IAppHostAuxiliaryBackchannel can reuse that connection instead of doing an extra lookup
  • Adjusted the new E2E test to avoid an unrelated Redis health-check dependency in CI

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

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.
@github-actions

github-actionsBot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 18106

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 18106"

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 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 McpToolHelpers methods (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.cs covering 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
FileDescription
src/Aspire.Cli/Mcp/Tools/McpToolHelpers.csAdds IsExcludedFromMcp, GetResourceNotAvailableMessage, CheckResourceExcludedAsync, and GetExcludedResourceNamesAsync helper methods
src/Aspire.Cli/Mcp/Tools/ListResourcesTool.csFilters excluded resources from the snapshot list before rendering
src/Aspire.Cli/Mcp/Tools/ListConsoleLogsTool.csRejects requests for excluded resources with an error
src/Aspire.Cli/Mcp/Tools/ExecuteResourceCommandTool.csRejects commands targeting excluded resources with an error
src/Aspire.Cli/Mcp/Tools/ListStructuredLogsTool.csAdds IAuxiliaryBackchannelMonitor? parameter; checks specific resource exclusion early and filters post-fetch when unscoped
src/Aspire.Cli/Mcp/Tools/ListTracesTool.csAdds IAuxiliaryBackchannelMonitor? parameter; checks specific resource exclusion early and filters spans post-fetch when unscoped
src/Aspire.Cli/Mcp/Tools/ListTraceStructuredLogsTool.csAdds IAuxiliaryBackchannelMonitor? parameter; filters excluded resource logs post-fetch
src/Aspire.Cli/Mcp/McpResourceToolRefreshService.csExcludes resources with excludeFromMcp from tool registration
src/Aspire.Cli/Commands/AgentMcpCommand.csPasses IAuxiliaryBackchannelMonitor (or null in dashboard-only mode) to telemetry tool constructors
tests/Aspire.Cli.Tests/Mcp/ExcludeFromMcpTests.csNew test file covering exclusion logic for helper methods and 6 tools
tests/Aspire.Cli.Tests/Mcp/ListTracesToolTests.csUpdates CreateTool helper to pass the new monitor parameter
tests/Aspire.Cli.Tests/Mcp/ListStructuredLogsToolTests.csUpdates CreateTool helper to pass the new monitor parameter

Comment threadsrc/Aspire.Cli/Mcp/Tools/ListTraceStructuredLogsTool.cs
@JamesNK

Copy link
Copy Markdown
MemberAuthor

PR E2E Testing Report

Setup

  • Built CLI from source (dotnet build src/Aspire.Cli/Aspire.Cli.csproj /p:SkipNativeBuild=true)
  • CLI version: 13.5.0-dev
  • Created Aspire starter project with apiservice.ExcludeFromMcp() applied in AppHost
  • Started AppHost, waited for resources to be healthy
  • Connected to aspire agent mcp via JSON-RPC stdin/stdout

Test Results

ScenarioStatusDetails
list_resources filtering✅ Passapiservice (Project) excluded from results; webfrontend visible
list_console_logs for excluded resource✅ PassReturns isError: true with "Resource 'apiservice' is not available."
list_console_logs for non-excluded resource✅ PassReturns 15 console log lines for webfrontend successfully

Details

list_resources

The response contains 4 resources: apiservice-rebuilder, aspire-dashboard, webfrontend, and webfrontend-rebuilder. The main apiservice Project resource (which has .ExcludeFromMcp()) is correctly excluded.

The apiservice-rebuilder child resource (Executable type) still appears because ExcludeFromMcp() is applied to the parent project resource only — child resources don't inherit the annotation. This is expected behavior.

list_console_logs("apiservice")

{"isError": true, "content": [{"text": "Resource 'apiservice' is not available."}]}

list_console_logs("webfrontend")

Returned 15 console logs.

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()
CopilotAI review requested due to automatic review settings June 11, 2026 05:17

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 14 out of 14 changed files in this pull request and generated 1 comment.

Comment threadsrc/Aspire.Cli/Mcp/Tools/McpToolHelpers.cs
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.
CopilotAI review requested due to automatic review settings June 11, 2026 05:37
@JamesNK
James Newton-King (JamesNK) marked this pull request as ready for review June 11, 2026 05:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 14 out of 14 changed files in this pull request and generated no new comments.

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.
@github-actions

Copy link
Copy Markdown
Contributor

CLI E2E Tests failed — 113 passed, 1 failed, 2 unknown (commit 266cc03)

❌ Failed Tests

-TestDetail
DeployK8sWithValkeyRecording · Job · CLI logs
View all recordings
-TestDetail
AddPackageInteractiveWhileAppHostRunningDetachedRecording · Job · CLI logs
AddPackageWhileAppHostRunningDetachedRecording · Job · CLI logs
AgentCommands_AllHelpOutputs_AreCorrectRecording · Job · CLI logs
AgentInitCommand_DefaultSelection_InstallsDefaultSkillsRecording · Job · CLI logs
AgentInitCommand_MigratesDeprecatedConfigRecording · Job · CLI logs
AgentInit_NonInteractive_BundleOnlySkillsNotInCatalogRecording · Job · CLI logs
AgentMcpListResources_ExcludesResourceMarkedWithExcludeFromMcpRecording · Job · CLI logs
AgentMcpListStructuredLogsReturnsLogsFromStarterAppRecording · Job · CLI logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_DevLocalhostRecording · Job · CLI logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_IsolatedRecording · Job · CLI logs
AllPublishMethodsBuildDockerImagesRecording · Job · CLI logs
AspireAddAndStartWorkAgainstLegacyAppHostTsRecording · Job · CLI logs
AspireAddPackageVersionToDirectoryPackagesPropsRecording · Job · CLI logs
AspireInitSingleFileAppHostRunsViaDotnetRunAppHostRecording · Job · CLI logs
AspireInit_ExistingAppHostDir_RecreatesNuGetConfigKeepsFilesRecording · Job · CLI logs
AspireInit_SolutionFile_BuildsAgainstChannelHiveRecording · Job · CLI logs
AspireStartUpdatesStaleTypeScriptAppHostPathRecording · Job · CLI logs
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesPropsRecording · Job · CLI logs
AspireUpdateRemovesOrphanAppHostPackageVersionWhenSdkAlreadyCurrentRecording · Job · CLI logs
Banner_DisplayedOnFirstRunRecording · Job · CLI logs
Banner_DisplayedWithExplicitFlagRecording · Job · CLI logs
Banner_NotDisplayedWithNoLogoFlagRecording · Job · CLI logs
CertificatesClean_RemovesCertificatesRecording · Job · CLI logs
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificateRecording · Job · CLI logs
CertificatesTrust_WithUntrustedCert_TrustsCertificateRecording · Job · CLI logs
ConfigSetGet_CreatesNestedJsonFormatRecording · Job · CLI logs
CreateAndRunAspireStarterProjectRecording · Job · CLI logs
CreateAndRunAspireStarterProjectWithBundleRecording · Job · CLI logs
CreateAndRunEmptyAppHostProjectRecording · Job · CLI logs
CreateAndRunJavaEmptyAppHostProjectRecording · Job · CLI logs
CreateAndRunJsReactProjectRecording · Job · CLI logs
CreateAndRunPolyglotAppHostWithDevLocalhostUrlsRecording · Job · CLI logs
CreateAndRunPythonReactProjectRecording · Job · CLI logs
CreateAndRunTypeScriptEmptyAppHostProjectRecording · Job · CLI logs
CreateAndRunTypeScriptStarterProjectRecording · Job · CLI logs
CreateJavaAppHostWithViteAppRecording · Job · CLI logs
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchainRecording · Job · CLI logs
DashboardRunWithAgentMcpListTracesReturnsNoTracesRecording · Job · CLI logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces_DevLocalhostRecording · Job · CLI logs
DashboardRunWithOtelTracesReturnsNoTracesRecording · Job · CLI logs
DashboardRunWithOtelTracesReturnsNoTraces_DevLocalhostRecording · Job · CLI logs
DeployK8sBasicApiServiceRecording · Job · CLI logs
DeployK8sWithExternalHelmChartRecording · Job · CLI logs
DeployK8sWithGarnetRecording · Job · CLI logs
DeployK8sWithMongoDBRecording · Job · CLI logs
DeployK8sWithMySqlRecording · Job · CLI logs
DeployK8sWithPostgresRecording · Job · CLI logs
DeployK8sWithRabbitMQRecording · Job · CLI logs
DeployK8sWithRedisRecording · Job · CLI logs
DeployK8sWithSqlServerRecording · Job · CLI logs
DeployK8sWithValkeyRecording · Job · CLI logs
DeployTypeScriptAppToKubernetesRecording · Job · CLI logs
DescribeCommandResolvesReplicaNamesRecording · Job · CLI logs
DescribeCommandShowsRunningResourcesRecording · Job · CLI logs
DetachFormatJsonProducesValidJsonRecording · Job · CLI logs
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstanceRecording · Job · CLI logs
DoPublishAndDeployListStepsWorkRecording · Job · CLI logs
DocsCommand_RendersInteractiveMarkdownFromLocalSourceRecording · Job · CLI logs
DoctorCommand_DetectsDeprecatedAgentConfigRecording · Job · CLI logs
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchainRecording · Job · CLI logs
DoctorCommand_WithSslCertDir_ShowsTrustedRecording · Job · CLI logs
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrustedRecording · Job · CLI logs
DotNetRunFileBasedAppHostUsesAspireCliBundleRecording · Job · CLI logs
DotNetRunProjectAppHostUsesAspireCliBundleRecording · Job · CLI logs
GatewayWithoutExternalEndpoint_FailsPublishWithGuidanceRecording · Job · CLI logs
GeneratedAspireDevScript_StartsWatchMode_WithConfiguredToolchainRecording · Job · CLI logs
GlobalMigration_HandlesCommentsAndTrailingCommasRecording · Job · CLI logs
GlobalMigration_HandlesMalformedLegacyJsonRecording · Job · CLI logs
GlobalMigration_PreservesAllValueTypesRecording · Job · CLI logs
GlobalMigration_SkipsWhenNewConfigExistsRecording · Job · CLI logs
GlobalSettings_MigratedFromLegacyFormatRecording · Job · CLI logs
IngressWithoutExternalEndpoint_FailsPublishWithGuidanceRecording · Job · CLI logs
InitTypeScriptAppHost_AugmentsExistingViteRepoInWorkspaceSubdirectoryRecording · Job · CLI logs
InteractiveCSharpInitCreatesExpectedFilesRecording · Job · CLI logs
InvalidAppHostPathWithComments_IsHealedOnRunRecording · Job · CLI logs
JavaScriptHostingApisRunFromTypeScriptAppHostRecording · Job · CLI logs
LatestCliCanStartStableChannelAppHostRecording · Job · CLI logs
LatestCliCanStartStableChannelTypeScriptAppHostRecording · Job · CLI logs
LegacySettingsMigration_AdjustsRelativeAppHostPathRecording · Job · CLI logs
LogsCommandShowsResourceLogsRecording · Job · CLI logs
OtelLogsReturnsStructuredLogsFromStarterAppRecording · Job · CLI logs
OtelLogsReturnsStructuredLogsFromStarterAppIsolatedRecording · Job · CLI logs
ProcessCommandCallbackReceivesCliArgumentsRecording · Job · CLI logs
PsCommandListsRunningAppHostRecording · Job · CLI logs
PsFormatJsonOutputsOnlyJsonToStdoutRecording · Job · CLI logs
PublishJavaScriptPatternsGeneratesExpectedDockerComposeArtifactsRecording · Job · CLI logs
PublishWithConfigureEnvFileUpdatesEnvOutputRecording · Job · CLI logs
PublishWithDockerComposeServiceCallbackSucceedsRecording · Job · CLI logs
PublishWithoutOutputPathUsesAppHostDirectoryDefaultRecording · Job · CLI logs
ResourceCommand_FailedExec_ShowsLogPathAndLogHasEntriesRecording · Job · CLI logs
ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutputRecording · Job · CLI logs
RestoreGeneratesSdkFilesRecording · Job · CLI logs
RestoreGeneratesSdkFiles_WithConfiguredToolchainRecording · Job · CLI logs
RestoreRefreshesGeneratedSdkAfterAddingIntegrationRecording · Job · CLI logs
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypesRecording · Job · CLI logs
RunFromParentDirectory_UsesExistingConfigNearAppHostRecording · Job · CLI logs
RunReportsSyntaxErrorsForDotNetAppHostRecording · Job · CLI logs
RunReportsSyntaxErrorsForTypeScriptAppHostRecording · Job · CLI logs
SecretCrudOnDotNetAppHostRecording · Job · CLI logs
SecretCrudOnTypeScriptAppHostRecording · Job · CLI logs
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannelsRecording · Job · CLI logs
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssetsRecording · Job · CLI logs
StartReportsSyntaxErrorsForDotNetAppHostRecording · Job · CLI logs
StartReportsSyntaxErrorsForTypeScriptAppHostRecording · Job · CLI logs
StopAllAppHostsFromAppHostDirectoryRecording · Job · CLI logs
StopJavaPolyglotAppHostUsingApphostDirectoryRecording · Job · CLI logs
StopNonInteractiveSingleAppHostRecording · Job · CLI logs
StopTypeScriptPolyglotAppHostUsingApphostDirectoryRecording · Job · CLI logs
StopWithNoRunningAppHostExitsSuccessfullyRecording · Job · CLI logs
TypeScriptAppHostRunDoesNotDeadlockWhenLazyOptionsInvokeAsyncCallbackRecording · Job · CLI logs
TypeScriptAppHostWithVite_AllowsDifferentGuestPkgManagerRecording · Job · CLI logs
UnAwaitedChainsCompileWithAutoResolvePromisesRecording · Job · CLI logs
UpdateToStable_CSharpEmptyAppHost_KeepsConfigChannelRecording · Job · CLI logs
UpdateToStable_CSharpSingleFileInit_KeepsConfigChannelRecording · Job · CLI logs
UpdateToStable_TypeScriptSingleFileInit_KeepsConfigChannelRecording · Job · CLI logs
UpdateToStable_TypeScript_PreviewsStablePkgsAndKeepsChannelRecording · Job · CLI logs

📹 Recordings uploaded automatically from CI run #27328001371

@mitchdennyMitch Denny (mitchdenny) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approved. You may want to look at the seemingly false alarm in the CLI E2E test output.

@radical

Copy link
Copy Markdown
Member

Copilot verify if the failing Cli E2E test in #18106 (comment) is related to this PR.

CopilotAI commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

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 DeployK8sWithValkey, which exercises Kubernetes deployment with Valkey (tests/Aspire.Cli.EndToEnd.Tests/KubernetesDeployWithValkeyTests.cs). This PR only changes MCP filtering code plus the new AgentMcpExcludeFromMcp E2E test, and that PR-specific test passed in the same report. So the failure in that comment does not appear related to this PR.

@radical
Ankit Jain (radical) merged commit d613ebe into mainJun 11, 2026
665 of 668 checks passed
@radical
Ankit Jain (radical) deleted the feature/mcp-exclude-from-mcp-filtering branch June 11, 2026 17:36
@github-actionsgithub-actionsBot added this to the 13.5 milestone Jun 11, 2026
@JamesNK

Copy link
Copy Markdown
MemberAuthor

/backport to release/13.4

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/13.4 (link to workflow run)

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@JamesNK@radical@mitchdenny