Skip to content

Split configuration of request and message filters#1308

Open
halter73 wants to merge 7 commits intomainfrom
halter73/split-filters
Open

Split configuration of request and message filters#1308
halter73 wants to merge 7 commits intomainfrom
halter73/split-filters

Conversation

@halter73
Copy link
Contributor

@halter73 halter73 commented Feb 19, 2026

This adds WithMessageFilters and WithRequestFilters extension methods to IMcpServerBuilder which expose an IMcpMessageFilterBuilder and IMcpRequestFilterBuilder inline to their respective callbacks.

This avoids having too many similar looking, poorly sorted extension methods on IMcpServerBuilder. This also keeps incoming and outgoing message filters more closely associated.

This adds WithMessageFilters and WithRequestFilters extension methods to
IMcpServerBuilder which expose an IMcpMessageFilterBuilder and IMcpRequestFilterBuilder
to their respective callbacks. This avoids having to many similar looking,
poorly sorted extension methods on IMcpServerBuilder. This also keeps
incoming and outgoing message filters more closely associated.
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

This PR refactors the filter configuration API for MCP servers by introducing a grouped builder pattern for configuring message and request filters. Instead of having many similarly-named Add*Filter extension methods directly on IMcpServerBuilder, the PR introduces two new methods (WithMessageFilters and WithRequestFilters) that accept callbacks providing specialized builder instances for configuring filters in their respective categories.

Changes:

  • Introduces IMcpMessageFilterBuilder and IMcpRequestFilterBuilder interfaces with corresponding implementations for grouping filter configuration
  • Adds WithMessageFilters() and WithRequestFilters() extension methods to organize filter registration
  • Restructures McpServerFilters to use nested McpMessageFilters and McpRequestFilters objects for better organization
  • Marks all existing individual filter methods as [Obsolete] while maintaining backward compatibility through delegation
  • Updates all tests, samples, and documentation to use the new API pattern

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/ModelContextProtocol/McpServerBuilderExtensions.cs Adds new WithMessageFilters and WithRequestFilters methods; marks old methods obsolete
src/ModelContextProtocol/McpMessageFilterBuilderExtensions.cs New file with AddIncomingFilter and AddOutgoingFilter methods
src/ModelContextProtocol/McpRequestFilterBuilderExtensions.cs New file with all request-specific filter methods (AddListToolsFilter, AddCallToolFilter, etc.)
src/ModelContextProtocol/IMcpMessageFilterBuilder.cs New interface for message filter builder
src/ModelContextProtocol/IMcpRequestFilterBuilder.cs New interface for request filter builder
src/ModelContextProtocol/DefaultMcpMessageFilterBuilder.cs Default implementation of message filter builder
src/ModelContextProtocol/DefaultMcpRequestFilterBuilder.cs Default implementation of request filter builder
src/ModelContextProtocol.Core/Server/McpServerFilters.cs Restructured to use Message and Request nested properties
src/ModelContextProtocol.Core/Server/McpMessageFilters.cs New class containing message filter collections
src/ModelContextProtocol.Core/Server/McpRequestFilters.cs New class containing request-specific filter collections
src/ModelContextProtocol.Core/Server/McpServerImpl.cs Updated to access filters via nested properties
src/ModelContextProtocol.Core/Server/MessageContext.cs Updated XML documentation to reference new nested structure
src/ModelContextProtocol.Core/Server/McpServerOptions.cs Updated filter execution order documentation for clarity
src/ModelContextProtocol.AspNetCore/AuthorizationFilterSetup.cs Updated to use new nested filter properties
tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsMessageFilterTests.cs All tests updated to use new WithMessageFilters and WithRequestFilters APIs
tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsFilterTests.cs All tests updated to use new WithRequestFilters API
tests/ModelContextProtocol.ConformanceServer/Program.cs Updated to use new WithRequestFilters API
docs/concepts/filters.md Comprehensive documentation updates showing new API usage patterns

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@jeffhandley jeffhandley added this to the Stable public API milestone Feb 19, 2026
Copy link
Collaborator

@jeffhandley jeffhandley left a comment

Choose a reason for hiding this comment

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

Still reviewing...

Comment on lines 839 to 840
private const string MessageFilterObsoleteMessage = "Use WithMessageFilters() instead.";
private const string RequestFilterObsoleteMessage = "Use WithRequestFilters() instead.";
Copy link
Collaborator

Choose a reason for hiding this comment

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

These should be defined in src/Common/Obsoletions.cs please, with:

public const string MessageAndRequestFilter_DiagnosticId = "MCP9002";
public const string MessageAndRequestFilter_Url = "https://github.com/modelcontextprotocol/csharp-sdk/pull/1308";
public const string MessageFilter_Message = "Use WithMessageFilters() instead.";
public const string RequestFilter_Message = "Use WithRequestFilters() instead.";

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@copilot Please use Oboletions.cs with a URL and Diagnotic ID as suggested.

@jeffhandley jeffhandley added the breaking-change This issue or PR introduces a breaking change label Feb 19, 2026
Copy link
Contributor

@mikekistler mikekistler left a comment

Choose a reason for hiding this comment

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

I'm struggling a bit with this. Maybe its because I haven't had time to dig into message/request filters yet, but I think I would have trouble figuring out how to set these up and use them.

Comment on lines 12 to 13
1. **Message Filters** - Low-level filters (`AddIncomingFilter`, `AddOutgoingFilter`) configured via `WithMessageFilters(...)`.
2. **Request-Specific Filters** - Handler-level filters (e.g., `AddListToolsFilter`, `AddCallToolFilter`) configured via `WithRequestFilters(...)`.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's really important to describe what these filters do and not just how they are added.

2. **Request-Specific Filters** - Handler-level filters (e.g., `AddListToolsFilter`, `AddCallToolFilter`) configured via `WithRequestFilters(...)`.

The filters are stored in `McpServerOptions.Filters` and applied during server configuration.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we need a diagram that illustrates the flow on incoming and outgoing messages through these filters and the associated handlers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is the following bit in the "Message Filter Execution Order", but it's not part of the diff.

Request arrives
    ↓
IncomingFilter1 (before next)
    ↓
IncomingFilter2 (before next)
    ↓
Request Routing → ListToolsFilter → Handler
    ↓
IncomingFilter2 (after next)
    ↓
IncomingFilter1 (after next)
    ↓
Response sent via OutgoingFilter1 (before next)
    ↓
OutgoingFilter2 (before next)
    ↓
Transport sends message
    ↓
OutgoingFilter2 (after next)
    ↓
OutgoingFilter1 (after next)

Copy link
Contributor

Copilot AI commented Feb 19, 2026

@halter73 I've opened a new pull request, #1315, to work on those changes. Once the pull request is ready, I'll request review from you.

- We can add internal properties later to lazily check if the getters have been used to avoid allocations if we care
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.

4 participants

Comments