modelcontextprotocol / modelcontextprotocol/kotlin-sdk

[Proposal] SEP-2133: Extensions framework architecture & integration design (#804)

Open
#1,006 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Kotlin
Stars
1.5k
Forks
248
Avg merge
1d 20h
Merged PRs (30d)
23

Description

Proposal: SEP-2133 Extensions Framework Architecture & Integration Design (#804)
Motivation & Context

Tracking implementation of SEP-2133 in kotlin-sdk for the 2026-07-28 MCP specification release (aligned with umbrella issue #842).

As the MCP ecosystem grows, standard features such as MCP Apps (SEP-1865), Tasks (SEP-2663), and Enterprise Managed Authorization (SEP-990) are developed as official and third-party extensions. Without a standardized extension framework:

  1. Capability Fragmentation: SDKs had ad-hoc, inconsistent locations for experimental features in ClientCapabilities and ServerCapabilities.
  2. Identifier Clashes: Without a unified naming scheme, third-party and community capabilities risked naming collisions with core protocol methods.
  3. Ergonomics & Modularity: Core SDK modules risked bloat if every domain extension had to be baked directly into kotlin-sdk-core.

SEP-2133 establishes:

  • Standard reverse-domain extension identifiers (e.g., io.modelcontextprotocol/tasks, io.modelcontextprotocol/apps).
  • Standard capability negotiation via the extensions field in ClientCapabilities and ServerCapabilities.
  • Extensible dispatch for extension-defined JSON-RPC methods and notifications.

This proposal outlines the Kotlin Multiplatform architecture to implement the SEP-2133 Extensions Framework in kotlin-sdk (kotlin-sdk-core, kotlin-sdk-server, and kotlin-sdk-client).


Proposed Architecture & Component Design
1. Capability Negotiation & Data Models (kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/)

In schema.kt:

  • Capabilities Enhancement:
    Add extensions mapping to both ClientCapabilities and ServerCapabilities:
    @Serializable
    public data class ClientCapabilities(
        // ... existing core capabilities (roots, sampling, elicitation)
        val extensions: Map<String, JsonElement>? = null,
        @SerialName("_meta")
        override val meta: JsonObject? = null,
    ) : WithMeta
    
    @Serializable
    public data class ServerCapabilities(
        // ... existing core capabilities (logging, prompts, resources, tools)
        val extensions: Map<String, JsonElement>? = null,
        @SerialName("_meta")
        override val meta: JsonObject? = null,
    ) : WithMeta
    
  • Extension Identifier Validation:
    Provide validation utility ensuring reverse-domain conventions (e.g. regex ^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$):
    public fun isValidExtensionId(id: String): Boolean
    
2. Extension Abstraction & Plugin SPI (kotlin-sdk-core)

Define a modular Kotlin Multiplatform extension contract:

public interface McpExtension {
    /** Reverse domain identifier, e.g. "io.modelcontextprotocol/tasks" */
    public val id: String

    /** Semantic version of the extension supported */
    public val version: String

    /** Parameters or feature sub-capabilities advertised during handshake */
    public fun createCapabilityDescriptor(): JsonElement? = buildJsonObject {
        put("version", version)
    }
}
3. Extension Management on Sessions (kotlin-sdk-server & kotlin-sdk-client)
  • Server-Side Extension Registration & Method Routing:
    In ServerSession:

    public class ServerSession(...) {
        private val registeredExtensions = mutableMapOf<String, McpExtension>()
        private val extensionMethodHandlers = mutableMapOf<Method, suspend (JsonRPCRequest) -> JsonRPCResponse>()
    
        public fun registerExtension(extension: McpExtension) {
            registeredExtensions[extension.id] = extension
        }
    
        public fun registerExtensionMethod(
            method: String,
            handler: suspend (JsonRPCRequest) -> JsonRPCResponse
        ) {
            extensionMethodHandlers[Method.Custom(method)] = handler
        }
    }
    
    • Incoming requests with unknown methods are checked against registered extension method handlers before falling back to MethodNotFound (-32601).
    • During the initialize handshake, advertised ServerCapabilities.extensions are automatically synthesized from registeredExtensions.
  • Client-Side Negotiation & Inspection:
    In ClientSession:

    public class ClientSession(...) {
        public fun isExtensionSupportedByServer(extensionId: String): Boolean =
            serverCapabilities?.extensions?.containsKey(extensionId) == true
    
        public fun getServerExtensionMetadata(extensionId: String): JsonElement? =
            serverCapabilities?.extensions?.get(extensionId)
    }
    
4. Idiomatic Builder DSL (kotlin-sdk-client / kotlin-sdk-server)

Provide an idiomatic, modular DSL for installing extensions:

// Server builder
val server = McpServer {
    install(TasksExtension) {
        ttl = 3600_000L
    }
    install(McpAppsExtension)
}

// Client builder
val client = McpClient {
    install(TasksExtension)
}
5. Testing & Verification Plan
  • Unit Tests:
    • Serialization / deserialization of ClientCapabilities and ServerCapabilities containing extensions.
    • Extension handshake negotiation between client and server (verifying matching capability advertisement).
    • Dispatching custom extension methods and error isolation.
    • Backward compatibility: ensure connecting to legacy servers lacking extensions handles gracefully with null safety.
  • Conformance Suite:
    • Verify capability negotiation conformance tests across supported SDK fixtures.

Next Steps

Upon review and consensus on the extension framework design:

  1. Add extensions field to ClientCapabilities and ServerCapabilities in kotlin-sdk-core.
  2. Implement McpExtension interface and session registration plumbing.
  3. Update server request dispatcher to support dynamically routed extension methods.
  4. Add unit test suite for capability negotiation.

AI assistance disclosure: AI was used to discover this opportunity and draft the change or text. The submission was checked against the prepared artifact and recorded verification evidence.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/schema.kt and the existing ClientCapabilities and ServerCapabilities models. Then inspect ServerSession and ClientSession to understand handshake and request dispatch behavior. Done means the proposed extension negotiation, registration, routing, DSL, and unit or conformance tests are agreed and implemented across the named modules.

Written by the indexing model from the issue text.

Assessment

Tech stack
kotlin
Domain
api, backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.