Skip to content

fix: preserve open capability and subscription fields - #1170

Open
muxammadreza wants to merge 6 commits into
modelcontextprotocol:mainfrom
muxammadreza:feat/open-world-capability-preservation
Open

fix: preserve open capability and subscription fields#1170
muxammadreza wants to merge 6 commits into
modelcontextprotocol:mainfrom
muxammadreza:feat/open-world-capability-preservation

Conversation

@muxammadreza

Copy link
Copy Markdown

Summary

  • preserve unknown top-level entries in ClientCapabilities and ServerCapabilities through serde round trips
  • preserve extension-owned SubscriptionFilter fields without teaching core RMCP extension semantics
  • keep the handler-provided accepted value authoritative for requested extension-owned subscription fields while retaining existing core capability filtering

MCP capability objects are open sets, and extension contracts may augment subscription filters. Intermediaries otherwise lose protocol data during typed decode/re-encode.

Tests

  • cargo test -p rmcp --lib model::capabilities::test -- --nocapture
  • cargo test -p rmcp --test test_subscriptions_model -- --nocapture
  • cargo test -p rmcp --test test_subscriptions --features client,server,transport-io -- --nocapture
  • cargo fmt --all -- --check
  • git diff --check

@muxammadreza
muxammadreza requested a review from a team as a code owner August 13, 2026 01:57
Copilot AI lite review requested due to automatic review settings August 13, 2026 01:57
@github-actions github-actions Bot added T-test Testing related changes T-core Core library changes T-handler Handler implementation changes T-model Model/data structure changes labels Aug 13, 2026

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.

Pull request overview

This PR updates RMCP’s MCP model handling to preserve open-set capability objects and extension-owned subscription filter fields across serde round trips, ensuring intermediaries don’t drop unknown protocol data and that handler-accepted extension fields remain authoritative.

Changes:

  • Preserve unknown top-level fields in ClientCapabilities and ServerCapabilities via flattened JSON object storage.
  • Preserve extension-owned SubscriptionFilter fields and ensure they survive intersection/capability filtering flows.
  • Add tests covering serde round-trips for extension fields and handler-accepted subscription acknowledgements.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
crates/rmcp/tests/test_subscriptions.rs Adds an integration test ensuring extension-owned subscription fields are acknowledged exactly as accepted by the handler.
crates/rmcp/tests/test_subscriptions_model.rs Adds a unit test verifying extension-owned subscription fields survive serde deserialize/serialize.
crates/rmcp/src/model/capabilities.rs Adds #[serde(flatten)] storage for unknown capability fields and adjusts builder construction to remain forward-compatible.
crates/rmcp/src/model.rs Adds SubscriptionFilter support for extension-owned fields and updates subset/intersection/support filtering logic accordingly.
crates/rmcp/src/handler/server.rs Updates server subscription acceptance flow to preserve handler-accepted extension fields while still filtering core categories by advertised capabilities.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread crates/rmcp/src/model.rs
Comment on lines +1965 to +1969
let additional_fields = other
.additional_fields
.iter()
.filter(|(key, _)| self.additional_fields.contains_key(*key))
.map(|(key, value)| (key.clone(), value.clone()))
Comment thread crates/rmcp/src/model.rs
Comment on lines 1927 to +1936
#[serde(default, skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "schemars", schemars(with = "Vec<String>"))]
pub resource_subscriptions: Option<Vec<String>>,
/// Extension-owned subscription filter entries not modeled by the core SDK.
///
/// The server handler remains responsible for validating and accepting
/// these values. Core capability filtering preserves handler-accepted
/// extension fields instead of interpreting their schemas.
#[serde(flatten)]
pub additional_fields: JsonObject,
@github-actions github-actions Bot added T-dependencies Dependencies related changes T-config Configuration file changes T-service Service layer changes labels Aug 13, 2026
@muxammadreza
muxammadreza force-pushed the feat/open-world-capability-preservation branch from ef57c12 to 3e42416 Compare August 13, 2026 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-config Configuration file changes T-core Core library changes T-dependencies Dependencies related changes T-handler Handler implementation changes T-model Model/data structure changes T-service Service layer changes T-test Testing related changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants