Skip to content

feat: add extensions attribute to ClientCapabilities and ServerCapabilities#1064

Open
YousefHaggy wants to merge 3 commits into
modelcontextprotocol:mainfrom
YousefHaggy:feat/client-capabilities-extensions
Open

feat: add extensions attribute to ClientCapabilities and ServerCapabilities#1064
YousefHaggy wants to merge 3 commits into
modelcontextprotocol:mainfrom
YousefHaggy:feat/client-capabilities-extensions

Conversation

@YousefHaggy

@YousefHaggy YousefHaggy commented Jul 17, 2026

Copy link
Copy Markdown

Add the optional extensions field to ClientCapabilities and ServerCapabilities, mirroring the MCP extensions framework (SEP-2133) as declared in the draft schema and already shipped by the TypeScript, Python, C#, Go, Rust, and Kotlin SDKs.

Refs #785

Motivation and Context

Spec + cross-SDK precedent

  • Spec: defined on ClientCapabilities (and ServerCapabilities) in the
    draft schema — schema/draft/schema.ts#L785
    (server twin at #L882) —
    introduced by SEP-2133
    (merged into the spec 2026-01-26). Type: { [key: string]: object }. Keys are
    extension identifiers following _meta naming rules; an empty object means
    "supported, no settings". See also the
    extensions overview docs.
  • Other SDKs already ship it on ClientCapabilities. Java is the only major
    SDK without it:
    • TypeScriptextensions?: { [key: string]: JSONObject };
    • Pythonextensions: dict[str, dict[str, Any]] | None = None
    • C#/.NETIDictionary<string, object>? Extensions
    • GoExtensions map[string]any
    • Rustextensions: Option<ExtensionCapabilities>
    • KotlinMap<String, JsonObject>? = null

How Has This Been Tested?

Added 3 tests per new field per the contributing guidelines.

  • Deserialize JSON without the field → succeeds, field is null.
  • Serialize an instance with the field unset (null) → the key is absent from output.
  • Deserialize JSON with an extra unknown field → succeeds.

Breaking Changes

No breaking changes

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Yugi-2 and others added 3 commits July 17, 2026 11:03
Add the optional `extensions` field to `ClientCapabilities`, mirroring the
MCP extensions framework (SEP-2133) as declared in the draft schema and
already shipped by the TypeScript, Python, C#, Go, Rust, and Kotlin SDKs.

Keys are extension identifiers (e.g.
"io.modelcontextprotocol/oauth-client-credentials") and values are
per-extension settings objects; an empty object indicates support with no
settings. The field is optional, defaults to null, and is omitted from the
wire when unset, so it is backward compatible with existing peers.

Follows CONTRIBUTING.md "Evolving wire-serialized records" Case A: the new
component is appended, annotated with @JsonProperty, boxed/nullable, and the
prior 4-arg constructor is retained as a source-compatible overload. Adds a
builder `extensions(Map)` setter plus an `extension(id, settings)` helper
that normalizes null settings to an empty object. Includes the required
absent/omit/unknown-field tests plus a round-trip test in SchemaEvolutionTests.

Refs modelcontextprotocol#785

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirror the ClientCapabilities `extensions` change on ServerCapabilities, as
the MCP extensions framework (SEP-2133) declares the field on both capability
objects. Same Case A treatment: appended optional component, retained 6-arg
constructor overload, builder `extensions(Map)` + `extension(id, settings)`
helper, and `mutate()` carries the new field. Adds absent/omit/round-trip
tests in SchemaEvolutionTests.

Refs modelcontextprotocol#785

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keep only the whole-map extensions(Map) setter on both capability builders,
matching the existing experimental(Map) convention. The per-entry
extension(id, settings) helper was a novel API for a single field, duplicated
verbatim across both builders, with copy-on-write merge semantics no sibling
setter has. Callers pass Map.of(id, Map.of()) for "supported, no settings".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant