Skip to content

Comments

Remove server back-references from protocol DTO types#1345

Open
Copilot wants to merge 5 commits intomainfrom
copilot/remove-back-reference-properties
Open

Remove server back-references from protocol DTO types#1345
Copilot wants to merge 5 commits intomainfrom
copilot/remove-back-reference-properties

Conversation

Copy link
Contributor

Copilot AI commented Feb 21, 2026

The protocol DTOs (Tool, Prompt, Resource, ResourceTemplate) each had a [JsonIgnore] property referencing their corresponding server primitive (McpServerTool, McpServerPrompt, McpServerResource), coupling the protocol layer to server-side concerns.

Changes

  • Protocol DTOs — Removed McpServerTool, McpServerPrompt, and McpServerResource back-reference properties and the now-unused using ModelContextProtocol.Server imports from Tool.cs, Prompt.cs, Resource.cs, and ResourceTemplate.cs. Also removed the McpServerResource = McpServerResource copy in ResourceTemplate.AsResource().

  • AIFunction constructors* — Removed the back-reference assignments (ProtocolTool.McpServerTool = this, etc.) from AIFunctionMcpServerTool, AIFunctionMcpServerPrompt, and AIFunctionMcpServerResource.

  • AuthorizationFilterSetup — Replaced back-reference navigation (tool.McpServerTool, prompt.McpServerPrompt, resource.McpServerResource) with O(1) name-based lookups against the collections already available on McpServerOptions:

// Before
result.Tools, static tool => tool.McpServerTool, ...

// After — collection reference captured once in filter factory scope
var toolCollection = options.ToolCollection;
result.Tools, tool => toolCollection is not null && toolCollection.TryGetPrimitive(tool.Name, out var t) ? t : null, ...

The CallTool, GetPrompt, and ReadResource filters are unchanged — they already use context.MatchedPrimitive set directly by the server infrastructure.

  • Tests — Added tests in AuthorizeAttributeTests covering the new authorization filter code paths:
    • When ToolCollection/PromptCollection/ResourceCollection is null (custom handler only), items are not filtered since no collection lookup is possible.
    • When a tool is returned from a custom handler but is not present in ToolCollection, it is not subject to auth filtering; only items found in the collection are checked.
Original prompt

Problem

The protocol DTO types Tool, Prompt, Resource, and ResourceTemplate each have a [JsonIgnore] back-reference property pointing to their corresponding server primitive (McpServerTool, McpServerPrompt, McpServerResource). These properties pollute the protocol layer with server-side concerns:

Required Changes

1. Remove the back-reference properties from the protocol DTOs

Delete these properties:

  • Tool.McpServerTool from src/ModelContextProtocol.Core/Protocol/Tool.cs
  • Prompt.McpServerPrompt from src/ModelContextProtocol.Core/Protocol/Prompt.cs
  • Resource.McpServerResource from src/ModelContextProtocol.Core/Protocol/Resource.cs
  • ResourceTemplate.McpServerResource from src/ModelContextProtocol.Core/Protocol/ResourceTemplate.cs (if it exists)

Also remove the using ModelContextProtocol.Server; import from these files if it becomes unused after removing the property.

2. Remove the back-reference assignments

In src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs, the constructor has this line:

ProtocolTool.McpServerTool = this;

Remove it. Find and remove equivalent assignments for prompts and resources in their respective AIFunction* implementation files (e.g., AIFunctionMcpServerPrompt.cs, AIFunctionMcpServerResource.cs or similar).

3. Update AuthorizationFilterSetup.cs to use collection-based lookups

In src/ModelContextProtocol.AspNetCore/AuthorizationFilterSetup.cs, the authorization filters currently navigate from protocol DTO → server primitive via the back-reference (e.g., tool.McpServerTool). Replace these with name-based lookups against the McpServerOptions collections that are already available.

For toolsConfigureListToolsFilter and CheckListToolsFilter:

Replace static tool => tool.McpServerTool with a lookup against options.ToolCollection:

tool => options.ToolCollection is { } tc && tc.TryGetPrimitive(tool.Name, out var serverTool) ? serverTool : null

For promptsConfigureListPromptsFilter and CheckListPromptsFilter:

Replace static prompt => prompt.McpServerPrompt with a lookup against options.PromptCollection:

prompt => options.PromptCollection is { } pc && pc.TryGetPrimitive(prompt.Name, out var serverPrompt) ? serverPrompt : null

For resourcesConfigureListResourcesFilter and CheckListResourcesFilter:

Replace static resource => resource.McpServerResource with a lookup against options.ResourceCollection:

resource => options.ResourceCollection is { } rc && rc.TryGetPrimitive(resource.Uri, out var serverResource) ? serverResource : null

For resource templatesConfigureListResourceTemplatesFilter and CheckListResourceTemplatesFilter:

Replace static resourceTemplate => resourceTemplate.McpServerResource with a lookup against options.ResourceCollection:

resourceTemplate => options.ResourceCollection is { } rc && rc.TryGetPrimitive(resourceTemplate.UriTemplate, out var serverResource) ? serverResource : null

Note: The CallTool, GetPrompt, and ReadResource filters already use context.MatchedPrimitive (which is set directly by the server infrastructure in McpServerImpl), so those filters do NOT need changes.

4. Fix any other compilation errors

Search the entire codebase for any other references to .McpServerTool, .McpServerPrompt, or .McpServerResource on the protocol DTO types and update or remove them. This includes test files. The test server in tests/ModelContextProtocol.TestServer/Program.cs creates Tool objects manually (without McpServerTool) so it should be unaffected, but verify.

Key context

  • McpServerPrimitiveCollection<T> has a TryGetPrimitive(string, out T) method for O(1) lookup by name/key.
  • McpServerOptions.ToolCollection, McpServerOptions.PromptCollection, and McpServerOptions.ResourceCollection are the collections.
  • The AuthorizationFilterSetup class already receives McpServerOptions via IConfigureOptions<McpServerOptions> / IPostConfigureOptions<McpServerOptions>, so the options parameter is available in the filter configuration methods.

This pull request was created from Copilot chat.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…izationFilterSetup to use collection-based lookups

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copilot AI changed the title [WIP] Remove back-reference properties from DTO types Remove server back-references from protocol DTO types Feb 21, 2026
Copy link
Contributor

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

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

@copilot are there tests fully validating all of these modified code paths? If not, please augment existing tests / test classes to provide full coverage, e.g. when collections are and are not available, when the primitives are and are not in the collection, etc.

@@ -102,9 +101,4 @@ public sealed class Resource : IBaseMetadata
[JsonPropertyName("_meta")]
public JsonObject? Meta { get; set; }

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in commit a9ef1f7.

@stephentoub stephentoub marked this pull request as ready for review February 21, 2026 17:21
@stephentoub stephentoub added the breaking-change This issue or PR introduces a breaking change label Feb 21, 2026
…ests for null collections and primitives not in collections

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 21, 2026

@copilot are there tests fully validating all of these modified code paths? If not, please augment existing tests / test classes to provide full coverage, e.g. when collections are and are not availab...

Added 5 new tests in AuthorizeAttributeTests.cs (commit a9ef1f7):

  • ListTools_WithHandlerAndNullCollection_AllToolsVisible — when ToolCollection is null (custom handler only), tools are not filtered
  • ListTools_WithMixedCollectionAndHandler_HandlerToolsNotFiltered — tools from a custom handler not in the collection pass through; only tools in the collection are subject to auth filtering
  • ListPrompts_WithHandlerAndNullCollection_AllPromptsVisible — same for null PromptCollection
  • ListResources_WithHandlerAndNullCollection_AllResourcesVisible — same for null ResourceCollection
  • ListResourceTemplates_WithHandlerAndNullCollection_AllResourceTemplatesVisible — same for null ResourceCollection with templates

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change This issue or PR introduces a breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants