Skip to content

.NET: Support MCP skills cacheScope with per-key cache partitions - #9986

Merged
SergeyMenshykh merged 12 commits into
feature-mcp-skills-nextfrom
sergeymenshykh-mcp-skill-cache-scope
Nov 3, 2026
Merged

SergeyMenshykh merged 12 commits into
feature-mcp-skills-nextfrom
sergeymenshykh-mcp-skill-cache-scope

Conversation

@SergeyMenshykh

@SergeyMenshykh SergeyMenshykh commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

The MCP skills extension spec requires skills/list, skills/get, and resources/read responses to declare a cacheScope: public responses may be shared between callers, while private ones are specific to the caller's credentials. Add scope validation and separate caches per authorization context so a shared MCP skills source does not reuse one caller's private responses for another caller.

Description

  • Read and validate cacheScope on skills/list (all pages must agree), skills/get, and resources/read responses. Missing or null scopes are treated as public because not all servers follow the spec yet. Unknown values in skills/list and skills/get are rejected.
  • Add AgentMcpSkillsSourceOptions.CacheIsolationKeySelector, aligned with the naming in CachingAgentSkillsSourceOptions. Each key gets its own skills cache. Without a selector, callers share one cache and private responses throw InvalidOperationException. A configured selector must return a non-empty key.
  • Store keyed partitions in a MemoryCache. MaxCachedPartitions defaults to 100; explicitly setting it to null allows unlimited partitions. Optional PartitionSlidingExpiration and PartitionAbsoluteExpiration control partition retention independently of response TTLs.
  • Replace the catalog's refresh queue with a per-skill refresh flag and make scope validation static. Skills no longer reference their catalog, so retaining one skill does not keep the catalog or sibling resource caches alive. Catalogs no longer implement IDisposable; in-flight discovery and retained resource reads remain supported.
  • Keep authentication and credential selection the application's responsibility. Document the required .DisableCaching() builder configuration so discovery reaches the MCP source's isolation selector and TTL checks on every call.
  • Update XML docs and sample guidance, and fix the sample's ttlMs and cacheScope placement so both apply to the outer skills/list response.
  • Add coverage for scope validation, partition isolation and retention, the default limit and unlimited mode, refresh retries and concurrency, and garbage collection while a skill is retained.

Related Issue

Validate cacheScope on skills/list, skills/get and resources/read responses. Treat missing or null scopes as public, and reject private responses unless CachePartitionKeySelector is configured. Keep a separate skills cache per partition key in a MemoryCache with optional count and expiration limits.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI 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.

🟡 Changes recommended

Catalog cleanup is missing on source disposal and partition eviction, retaining related resources, while misplaced sample cache fields are ignored and cause repeated discovery requests.

2 open issues
What changed in this PR

This PR adds caller-specific cache partitions to .NET MCP skills, preventing private responses from being reused across callers with different partition keys.

Changes:

  • Validate response cache scopes and reject private responses when no partition key is configured.
  • Add per-key caches with optional capacity and expiration limits.
  • Expand tests, API documentation, and the sample to explain cache isolation and authentication responsibilities.
File Description
dotnet/​tests/​Microsoft.Agents.AI.Mcp.UnitTests/​Skills/​AgentMcpSkillTests.cs Default test resource responses to public scope.
dotnet/​tests/​Microsoft.Agents.AI.Mcp.UnitTests/​Skills/​AgentMcpSkillsTests.Ttl.cs Add wall-clock support to the test clock.
dotnet/​tests/​Microsoft.Agents.AI.Mcp.UnitTests/​Skills/​AgentMcpSkillsTests.Refresh.cs Use public scopes in refresh fixtures.
dotnet/​tests/​Microsoft.Agents.AI.Mcp.UnitTests/​Skills/​AgentMcpSkillsTests.cs Default shared resource fixtures to public scope.
dotnet/​tests/​Microsoft.Agents.AI.Mcp.UnitTests/​Skills/​AgentMcpSkillsTests.CacheScope.cs Test scope validation, partition isolation, retention, and concurrency.
dotnet/​tests/​Microsoft.Agents.AI.Mcp.UnitTests/​Skills/​AgentMcpSkillsSerializationTests.cs Test scope serialization and invalid-value rejection.
dotnet/​src/​Microsoft.Agents.AI.Mcp/​Skills/​McpSkillsListResult.cs Add listing response cache scope.
dotnet/​src/​Microsoft.Agents.AI.Mcp/​Skills/​McpSkillsGetResult.cs Add metadata response cache scope.
dotnet/​src/​Microsoft.Agents.AI.Mcp/​Skills/​McpSkillsCatalog.cs Validate scopes and enforce consistency across list pages.
dotnet/​src/​Microsoft.Agents.AI.Mcp/​Skills/​McpSkillCacheScopeConverter.cs Parse known scopes and reject unsupported values.
dotnet/​src/​Microsoft.Agents.AI.Mcp/​Skills/​AgentSkillsProviderBuilderMcpExtensions.cs Document partition configuration.
dotnet/​src/​Microsoft.Agents.AI.Mcp/​Skills/​AgentMcpSkillsSourceOptions.cs Expose partition key and retention settings.
dotnet/​src/​Microsoft.Agents.AI.Mcp/​Skills/​AgentMcpSkillsSource.cs Select and cache catalogs by caller key.
dotnet/​src/​Microsoft.Agents.AI.Mcp/​Skills/​AgentMcpSkill.cs Validate resource response scope before caching.
dotnet/​src/​Microsoft.Agents.AI.Mcp/​Microsoft.Agents.AI.Mcp.csproj Add the memory-cache dependency.
dotnet/​samples/​02-agents/​AgentSkills/​Agent_Step06_McpBasedSkills/​README.md Explain isolation, retention, and credential responsibilities.
dotnet/​samples/​02-agents/​AgentSkills/​Agent_Step06_McpBasedSkills/​Program.cs Disable provider caching and add sample scope and TTL metadata.

Review effort: Balanced

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

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (1 commit(s)): 8b69fe48f360
Model: gpt-5.6-sol

Overview

The change adds strict scope parsing, per-key catalogs, bounded-retention options, and extensive tests for pagination, concurrency, expiration, and private-response rejection. However, the provider builder's default outer cache can bypass the new selector and expose one caller's private skill objects to another, while the partition store remains unbounded by default and can retain attacker-created entries for the source lifetime.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
2 verified findings remained after source verification (2 high) across 2 files. Details are attached to the affected lines below.

Affected areas: dotnet/src/Microsoft.Agents.AI.Mcp/Skills/AgentMcpSkillsSource.cs, dotnet/src/Microsoft.Agents.AI.Mcp/Skills/AgentMcpSkillsSourceOptions.cs

@github-code-quality

github-code-quality Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Code coverage overview

Languages: C#

C# / code-coverage/dotnet

feature-mcp-skills-n... 8837192 sergeymenshykh-mcp-s... 8c25758 +/-
86% 85% -1%
View coverage of the 10 most impacted files.
File feature-mcp-skills-n... 8837192 sergeymenshykh-mcp-s... 8c25758 +/-
/home/runner/wo...ntAIFunction.cs 93% 0% -93%
/home/runner/wo...toryProvider.cs 95% 31% -64%
/home/runner/wo...SessionStore.cs 100% 53% -47%
/home/runner/wo...hellExecutor.cs 90% 73% -17%
/home/runner/wo...SkillsSource.cs 89% 83% -6%
/home/runner/wo...ctionVisitor.cs 81% 75% -6%
/home/runner/wo...opeConverter.cs 0% 82% +82%
/home/runner/wo...killsCatalog.cs 0% 99% +99%
/home/runner/wo...lls/McpCache.cs 0% 100% +100%
/home/runner/wo...ueExtensions.cs 0% 100% +100%

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.


Updated November 03, 2026 15:46 UTC

semenshi-m (semenshi) and others added 3 commits November 2, 2026 19:01
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
semenshi-m (semenshi) and others added 3 commits November 3, 2026 11:08
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
semenshi-m (semenshi) and others added 2 commits November 3, 2026 15:01
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@SergeyMenshykh
SergeyMenshykh merged commit 5f3cb30 into feature-mcp-skills-next Nov 3, 2026
15 checks passed
@SergeyMenshykh
SergeyMenshykh deleted the sergeymenshykh-mcp-skill-cache-scope branch November 3, 2026 15:51
@github-project-automation github-project-automation Bot moved this from In Review to Done in Agent Framework Nov 3, 2026

This branch was previously deployed

2 inactive deployments
github-app-auth — 8c257588 Deployed Nov 3, 2026 by SergeyMenshykh via add_label #26980
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs .NET Usage: [Issues, PRs], Target: .Net

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants