From dbf99bebf010731aa83328f367b821f8c12bc88e Mon Sep 17 00:00:00 2001 From: Kurt Degiorgio Date: Wed, 11 Feb 2026 23:36:11 +0000 Subject: [PATCH] Define types and architecture for a variant-aware MCP server (#2) Defines the core types and API for server variants extension, laying groundwork for multi-variant server implementation. Server.Run() is not yet implemented but architecture is designed and documented. - Add Server type with variant registration - Implement default priority-based ranking - Define ServerVariant, VariantHints, and related types per SEP spec - Add comprehensive example demonstrating intended multi-variant usage - Document implementation plan for Server.Run() dispatch architecture Next PRs: - Unit Tests - Implementation for Server.Run - Conformance Testing Signed-off-by: Kurt Degiorgio --- go/sdk/examples/server/variants/main.go | 111 +++++++++ go/sdk/go.mod | 12 +- go/sdk/go.sum | 14 ++ go/sdk/variants/ranking.go | 39 +++ go/sdk/variants/server.go | 223 ++++++++++++++++++ .../{variant_test.go => server_test.go} | 0 go/sdk/variants/types.go | 178 ++++++++++++++ go/sdk/variants/variant.go | 6 - 8 files changed, 576 insertions(+), 7 deletions(-) create mode 100644 go/sdk/examples/server/variants/main.go create mode 100644 go/sdk/go.sum create mode 100644 go/sdk/variants/ranking.go create mode 100644 go/sdk/variants/server.go rename go/sdk/variants/{variant_test.go => server_test.go} (100%) create mode 100644 go/sdk/variants/types.go delete mode 100644 go/sdk/variants/variant.go diff --git a/go/sdk/examples/server/variants/main.go b/go/sdk/examples/server/variants/main.go new file mode 100644 index 0000000..5232db3 --- /dev/null +++ b/go/sdk/examples/server/variants/main.go @@ -0,0 +1,111 @@ +// Example: Setting up a variant-aware MCP server with multiple variants. +package main + +import ( + "context" + "log" + + mcp "github.com/modelcontextprotocol/go-sdk/mcp" + + "github.com/modelcontextprotocol/experimental-ext-variants/go/sdk/variants" +) + +// -- Coding variant tool types ------------------------------------------------ + +type AnalyzeCodeInput struct { + Code string `json:"code" jsonschema:"source code to analyze"` + Language string `json:"language" jsonschema:"programming language"` +} + +type AnalyzeCodeOutput struct { + Issues []string `json:"issues"` + Suggestions []string `json:"suggestions"` +} + +func AnalyzeCode(_ context.Context, _ *mcp.CallToolRequest, in AnalyzeCodeInput) (*mcp.CallToolResult, AnalyzeCodeOutput, error) { + return nil, AnalyzeCodeOutput{ + Issues: []string{"unused variable on line 3"}, + Suggestions: []string{"consider using a switch statement"}, + }, nil +} + +type RefactorInput struct { + Code string `json:"code" jsonschema:"source code to refactor"` + Action string `json:"action" jsonschema:"refactoring action, e.g. extract-function"` +} + +type RefactorOutput struct { + Refactored string `json:"refactored"` +} + +func Refactor(_ context.Context, _ *mcp.CallToolRequest, in RefactorInput) (*mcp.CallToolResult, RefactorOutput, error) { + return nil, RefactorOutput{Refactored: "// refactored\n" + in.Code}, nil +} + +// -- Compact variant tool types ----------------------------------------------- + +type SummarizeInput struct { + Text string `json:"text" jsonschema:"text to summarize"` +} + +type SummarizeOutput struct { + Summary string `json:"summary"` +} + +func Summarize(_ context.Context, _ *mcp.CallToolRequest, in SummarizeInput) (*mcp.CallToolResult, SummarizeOutput, error) { + return nil, SummarizeOutput{Summary: in.Text[:min(len(in.Text), 50)]}, nil +} + +type LookupInput struct { + Query string `json:"query" jsonschema:"lookup query"` +} + +type LookupOutput struct { + Result string `json:"result"` +} + +func Lookup(_ context.Context, _ *mcp.CallToolRequest, in LookupInput) (*mcp.CallToolResult, LookupOutput, error) { + return nil, LookupOutput{Result: "result for: " + in.Query}, nil +} + +// ----------------------------------------------------------------------------- + +func main() { + // Server 1: coding-focused tools + server1 := mcp.NewServer(&mcp.Implementation{Name: "my-server", Version: "v1.0.0"}, nil) + mcp.AddTool(server1, &mcp.Tool{Name: "analyze_code", Description: "Perform static analysis on source code"}, AnalyzeCode) + mcp.AddTool(server1, &mcp.Tool{Name: "refactor", Description: "Apply a refactoring action to source code"}, Refactor) + + // Server 2: compact / minimal tools + server2 := mcp.NewServer(&mcp.Implementation{Name: "my-server", Version: "v1.0.0"}, nil) + mcp.AddTool(server2, &mcp.Tool{Name: "summarize", Description: "Summarize text"}, Summarize) + mcp.AddTool(server2, &mcp.Tool{Name: "lookup", Description: "Quick fact lookup"}, Lookup) + + coding := variants.ServerVariant{ + ID: "coding-assistant", + Description: "Optimized for coding workflows", + Hints: map[string]string{"useCase": "coding", "contextSize": "standard"}, + Status: variants.Stable, + } + + compact := variants.ServerVariant{ + ID: "compact", + Description: "Minimal token usage", + Hints: map[string]string{"contextSize": "small"}, + Status: variants.Experimental, + } + + vs := variants.NewServer(). + WithVariant(coding, server1, 0). + WithVariant(compact, server2, 1). + WithRanking(func(_ context.Context, _ variants.VariantHints, vs []variants.ServerVariant) []variants.ServerVariant { + // rank based on client hints, return sorted + // note: this is optional, defults to ranking by priority. + return vs + }) + + ctx := context.Background() + if err := vs.Run(ctx, nil); err != nil { + log.Fatal(err) + } +} diff --git a/go/sdk/go.mod b/go/sdk/go.mod index 917c7e8..12f14d6 100644 --- a/go/sdk/go.mod +++ b/go/sdk/go.mod @@ -1,3 +1,13 @@ module github.com/modelcontextprotocol/experimental-ext-variants/go/sdk -go 1.23.0 \ No newline at end of file +go 1.23.0 + +toolchain go1.24.3 + +require github.com/modelcontextprotocol/go-sdk v1.2.0 + +require ( + github.com/google/jsonschema-go v0.3.0 // indirect + github.com/yosida95/uritemplate/v3 v3.0.2 // indirect + golang.org/x/oauth2 v0.30.0 // indirect +) diff --git a/go/sdk/go.sum b/go/sdk/go.sum new file mode 100644 index 0000000..3bc80f3 --- /dev/null +++ b/go/sdk/go.sum @@ -0,0 +1,14 @@ +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q= +github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= +github.com/modelcontextprotocol/go-sdk v1.2.0 h1:Y23co09300CEk8iZ/tMxIX1dVmKZkzoSBZOpJwUnc/s= +github.com/modelcontextprotocol/go-sdk v1.2.0/go.mod h1:6fM3LCm3yV7pAs8isnKLn07oKtB0MP9LHd3DfAcKw10= +github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= +github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= diff --git a/go/sdk/variants/ranking.go b/go/sdk/variants/ranking.go new file mode 100644 index 0000000..9012af3 --- /dev/null +++ b/go/sdk/variants/ranking.go @@ -0,0 +1,39 @@ +// Copyright 2025 The MCP Variants Authors. All rights reserved. +// Use of this source code is governed by a Apache-2.0 +// license that can be found in the LICENSE file. + +package variants + +import ( + "context" + "slices" +) + +// defaultRankingFunc is the built-in ranking function used when no custom +// RankingFunc is provided. It sorts variants by priority (lowest first), +// using stable-before-experimental-before-deprecated as a tiebreaker. +func defaultRankingFunc(_ context.Context, _ VariantHints, vs []ServerVariant) []ServerVariant { + ranked := slices.Clone(vs) + slices.SortStableFunc(ranked, func(a, b ServerVariant) int { + if a.Priority() != b.Priority() { + return a.Priority() - b.Priority() + } + return statusWeight(a.Status) - statusWeight(b.Status) + }) + return ranked +} + +// statusWeight returns a sort weight for a VariantStatus. +// Lower is better: stable < experimental < deprecated. +func statusWeight(s VariantStatus) int { + switch s { + case Stable, "": + return 0 + case Experimental: + return 1 + case Deprecated: + return 2 + default: + return 3 + } +} diff --git a/go/sdk/variants/server.go b/go/sdk/variants/server.go new file mode 100644 index 0000000..aad7b56 --- /dev/null +++ b/go/sdk/variants/server.go @@ -0,0 +1,223 @@ +// Copyright 2025 The MCP Variants Authors. All rights reserved. +// Use of this source code is governed by a Apache-2.0 +// license that can be found in the LICENSE file. + +package variants + +import ( + "context" + "errors" + + "github.com/modelcontextprotocol/go-sdk/mcp" +) + +// variantEntry binds a ServerVariant to its backing mcp.Server. +type variantEntry struct { + variant ServerVariant + server *mcp.Server +} + +// Server is a variant-aware MCP server that multiplexes across multiple +// mcp.Server instances, each associated with a ServerVariant. During +// initialization, clients provide VariantHints and the server responds with a +// ranked list of available variants. Per-request variant selection is carried +// in the _meta field. +type Server struct { + variants []variantEntry + variantMap map[string]*mcp.Server // ID -> server for O(1) lookup + rankingFunc RankingFunc +} + +// NewServer creates a new variant-aware server with no registered variants. +func NewServer() *Server { + return &Server{ + variantMap: make(map[string]*mcp.Server), + } +} + +// WithVariant registers a ServerVariant backed by the given mcp.Server. +// priority determines the default ordering when no RankingFunc is set; +// lower values indicate higher importance (0 = highest priority). By +// default, the variant with the lowest priority value will appear first +// in the list and serve as the recommended default for clients. This +// behavior can be overridden by providing a custom RankingFunc. +// +// Per the SEP, the first variant in the ranked list MUST have status +// "stable" (unless the client explicitly requested experimental variants +// via variantHints). Priority ordering is respected within that +// constraint: variants are sorted by priority, but the first stable +// variant is always promoted to the front of the list. +// +// Variant IDs must be unique; registering a duplicate panics. +func (s *Server) WithVariant(v ServerVariant, mcpServer *mcp.Server, priority int) *Server { + if _, exists := s.variantMap[v.ID]; exists { + panic("variants: duplicate variant ID: " + v.ID) + } + v.priority = priority + s.variants = append(s.variants, variantEntry{variant: v, server: mcpServer}) + s.variantMap[v.ID] = mcpServer + return s +} + +// WithRanking sets a custom ranking function used to order variants based +// on client hints during initialization. The function should return variants +// sorted by relevance, with the most appropriate variant first. If nil, +// variants are ordered by their priority value (lowest first). +// +// The ranking function does not need to enforce the SEP's stable-first +// invariant. After the function returns, the SDK will automatically promote +// the first stable variant to the front of the list (per the SEP: "The first +// element MUST have status stable unless the client explicitly requested +// experimental variants via variantHints"). The rest of the ranking order +// is preserved. +// +// Returns the receiver for chaining. +func (s *Server) WithRanking(fn RankingFunc) *Server { + s.rankingFunc = fn + return s +} + +// Variants returns a copy of all registered ServerVariant values in +// registration order. +func (s *Server) Variants() []ServerVariant { + out := make([]ServerVariant, len(s.variants)) + for i, e := range s.variants { + out[i] = e.variant + } + return out +} + +// RankedVariants returns the registered variants ranked according to the +// configured RankingFunc (or the default priority-based ranking if none is +// set). +func (s *Server) RankedVariants(ctx context.Context, hints VariantHints) []ServerVariant { + all := s.Variants() + if len(all) == 0 { + return all + } + rankFn := s.rankingFunc + if rankFn == nil { + rankFn = defaultRankingFunc + } + return rankFn(ctx, hints, all) +} + +// ServerFor returns the mcp.Server associated with the given variant ID, or +// nil if no variant with that ID is registered. +func (s *Server) ServerFor(id string) *mcp.Server { + return s.variantMap[id] +} + +// Run starts the variant server. +func (s *Server) Run(ctx context.Context, t mcp.Transport) error { + // TODO: Implement Server.Run using a method-dispatching proxy pattern. + // + // Architecture: the variant Server acts as a "front" MCP server that owns + // the real transport, handles lifecycle/discovery methods itself, and + // dispatches tool/resource/prompt calls to the correct inner *mcp.Server + // based on _meta["io.modelcontextprotocol/server-variant"]. + // + // --------------------------------------------------------------------------- + // Constants + // --------------------------------------------------------------------------- + // + // Extension ID (plural, for capability negotiation): + // "io.modelcontextprotocol/server-variants" + // + // Per-request _meta key (singular, for variant selection): + // "io.modelcontextprotocol/server-variant" + // + // --------------------------------------------------------------------------- + // Assumptions (v1) + // --------------------------------------------------------------------------- + // + // We need to make sure the SEP's session stability invariant is satisfied: + // + // "The server MUST ensure that the same variant is recommended and selected for the entire session, unless the client explicitly requests otherwise via variantHints." + // + // For the first version we will relax this constraint to avoid maintaining state. + // + // --------------------------------------------------------------------------- + // Steps + // --------------------------------------------------------------------------- + // + // 1. Create a "front" *mcp.Server inside Run. Configure it with + // ServerOptions.Capabilities set to the union of all variants' + // capability flags. For example, if any variant has tools, set + // Capabilities.Tools = &ToolCapabilities{ListChanged: true}. This + // causes the SDK to advertise the capability during initialize + // without registering any actual tools, resources, or prompts. + // The inner *mcp.Server instances are never connected to a + // transport — they are only used as handler registries. + // + // 2. Add a receiving middleware via AddReceivingMiddleware on the + // front server. This single middleware handles all variant-aware + // dispatch: + // + // a. "initialize": read variantHints from the client's extension + // payload at capabilities.extensions[ + // "io.modelcontextprotocol/server-variants"]. Call + // RankedVariants() and call next() to let the SDK produce + // the base InitializeResult, then inject availableVariants + // (including id, description, hints, status, and + // deprecationInfo where applicable) into the response at + // capabilities.extensions[ + // "io.modelcontextprotocol/server-variants"]. Include + // moreVariantsAvailable if only a subset is returned. + // + // b. "tools/list", "resources/list", "prompts/list", + // "resources/templates/list", "completion/complete": + // read _meta["io.modelcontextprotocol/server-variant"] to + // determine the active variant (default to first-ranked if + // absent). Look up the corresponding inner *mcp.Server and + // forward the request to its handler. Return only that + // variant's items. Cursors returned in paginated responses + // MUST be variant-scoped — embed the variant ID so that + // cross-variant cursor reuse is detectable. + // + // c. "tools/call", "resources/read", "prompts/get": + // read _meta["io.modelcontextprotocol/server-variant"] from + // the request. Validate the variant ID: + // - If the ID is not in the session's availableVariants, + // return JSON-RPC error -32602 with message + // "Invalid server variant" and data containing + // { requestedVariant, availableVariants } (scoped to + // the authenticated principal's visible variants). + // - If absent, default to the first-ranked variant. + // Resolve the inner *mcp.Server via ServerFor(id) and + // forward the request. + // + // d. "resources/subscribe": read the variant from _meta, + // validate as in (c). Resource notifications for this subscription + // MUST carry _meta["io.modelcontextprotocol/server-variant"] + // matching the bound variant. If the resource disappears + // from the variant, send a resource_updated notification + // followed by list_changed. + // + // e. "notifications/tools/list_changed", + // "notifications/prompts/list_changed", + // "notifications/resources/list_changed": when an inner + // server emits a list_changed notification, the middleware + // re-emits it on the front server with + // _meta["io.modelcontextprotocol/server-variant"] set to + // the originating variant's ID. + // + // f. All other methods ("ping", etc.): + // pass through to the front server's default handler. + // + // 3. Call frontServer.Run(ctx, t) to own the transport and manage + // the session lifecycle. The front server handles the JSON-RPC + // connection, SSE streaming, progress notifications, and + // session teardown. + // + // --------------------------------------------------------------------------- + // Backward compatibility + // --------------------------------------------------------------------------- + // + // If the client does not send the extension payload during + // initialize, the server omits availableVariants from the response + // and uses the first-ranked variant for all requests. The server + // behaves identically to a non-variant-aware server. + // + return errors.New("variants: Run not implemented") +} diff --git a/go/sdk/variants/variant_test.go b/go/sdk/variants/server_test.go similarity index 100% rename from go/sdk/variants/variant_test.go rename to go/sdk/variants/server_test.go diff --git a/go/sdk/variants/types.go b/go/sdk/variants/types.go new file mode 100644 index 0000000..120dbe3 --- /dev/null +++ b/go/sdk/variants/types.go @@ -0,0 +1,178 @@ +// Copyright 2025 The MCP Variants Authors. All rights reserved. +// Use of this source code is governed by a Apache-2.0 +// license that can be found in the LICENSE file. + +package variants + +import "context" + +// --------------------------------------------------------------------------- +// Variant status +// --------------------------------------------------------------------------- + +// VariantStatus represents the stability status of a server variant. +type VariantStatus string + +const ( + // Stable indicates a production-ready variant recommended for general use. + Stable VariantStatus = "stable" + // Experimental indicates a variant that may change without notice; use for testing. + Experimental VariantStatus = "experimental" + // Deprecated indicates a variant that will be removed in a future release. + Deprecated VariantStatus = "deprecated" +) + +// --------------------------------------------------------------------------- +// Deprecation info +// --------------------------------------------------------------------------- + +// DeprecationInfo provides migration guidance for deprecated variants. +type DeprecationInfo struct { + // Message is a human-readable message explaining why this variant is + // deprecated and how to migrate. + Message string `json:"message"` + + // Replacement is the suggested replacement variant identifier. + Replacement string `json:"replacement,omitempty"` + + // RemovalDate is an optional ISO 8601 date when this variant is planned + // to be removed. Servers SHOULD continue to support the variant until + // that date. + RemovalDate string `json:"removalDate,omitempty"` +} + +// --------------------------------------------------------------------------- +// Server variant +// --------------------------------------------------------------------------- + +// ServerVariant describes a server capability variant that clients can select. +// Each variant represents a distinct configuration of all server capabilities +// (tools, resources, prompts, subscriptions). +type ServerVariant struct { + // ID is a unique identifier for this variant. Freeform string that servers + // define. Examples: "claude-optimized", "gpt-optimized", "compact", + // "agent-plan". + // + // Each variant's ID MUST be unique within availableVariants. + ID string `json:"id"` + + // Description is a human-readable description of this variant, suitable + // for display to users or for LLM reasoning about variant selection. + // + // SHOULD include: + // - Target use case or model family + // - Key characteristics or optimizations + // - Trade-offs compared to other variants + Description string `json:"description"` + + // Hints are key-value pairs providing structured metadata for intelligent + // variant selection. Clients and LLMs can use these hints to + // programmatically filter and rank variants. + // + // Unknown hint keys MUST be ignored by clients and servers. + Hints map[string]string `json:"hints,omitempty"` + + // priority determines the default ordering when no RankingFunc is set; + // lower values indicate higher importance (0 = highest priority). + // This field is set by Server.WithVariant and is readable via the + // Priority() getter for use in custom RankingFunc implementations. + priority int + + // Status is the stability status of this variant. + // Defaults to Stable if empty. + Status VariantStatus `json:"status,omitempty"` + + // DeprecationInfo provides migration guidance when Status is Deprecated. + DeprecationInfo *DeprecationInfo `json:"deprecationInfo,omitempty"` +} + +// Priority returns the variant's priority value. Lower values indicate +// higher importance (0 = highest priority). +func (v ServerVariant) Priority() int { + return v.priority +} + +// --------------------------------------------------------------------------- +// Hint keys +// --------------------------------------------------------------------------- + +// HintKey is a well-known key for use in VariantHints.Hints and +// ServerVariant.Hints. +type HintKey = string + +// Well-known hint keys defined by the SEP (Common Hint Vocabulary). +const ( + // HintModelFamily identifies the target model family/provider. + // Common values: "anthropic", "openai", "google", "meta", "local", "any". + HintModelFamily HintKey = "modelFamily" + + // HintUseCase identifies the intended usage scenario. + // Common values: "autonomous-agent", "human-assistant", "ide", "api", + // "chat", "planning", "execution". + HintUseCase HintKey = "useCase" + + // HintContextSize indicates the desired verbosity / token efficiency. + // Common values: "compact", "standard", "verbose". + HintContextSize HintKey = "contextSize" + + // HintRenderingCapabilities describes the client's rendering support. + // Common values: "rich", "markdown", "text-only". + HintRenderingCapabilities HintKey = "renderingCapabilities" + + // HintLanguageOptimization indicates natural language optimization. + // Common values: "en", "multilingual", "code-focused". + HintLanguageOptimization HintKey = "languageOptimization" +) + +// --------------------------------------------------------------------------- +// Variant hints +// --------------------------------------------------------------------------- + +// VariantHints are structured hints provided by the client to help the server +// rank available variants. +type VariantHints struct { + // Description is a human-readable description of the client's context and + // requirements. + Description string `json:"description,omitempty"` + + // Hints are key-value pairs providing structured metadata for variant + // selection. Values can be a single string or an array of strings (in + // order of preference). + // + // Unknown hint keys MUST be ignored by clients and servers. + Hints map[string]any `json:"hints,omitempty"` +} + +// HintValue retrieves a typed value from the Hints map for the given key. +// It returns the zero value and false if the key is missing, the map is nil, +// or the stored value is not assignable to T. +func HintValue[T any](h VariantHints, key string) (T, bool) { + var zero T + if h.Hints == nil { + return zero, false + } + v, ok := h.Hints[key] + if !ok { + return zero, false + } + t, ok := v.(T) + return t, ok +} + +// --------------------------------------------------------------------------- +// Ranking function +// --------------------------------------------------------------------------- + +// RankingFunc is called during initialization to rank available variants based +// on the client's hints. It receives the client-provided hints and the full +// set of registered variants, and must return them sorted by relevance with +// the highest-priority variant first. The first variant in the returned slice +// is the recommended default and will be used when a client does not +// explicitly select a variant via _meta. +// +// Each ServerVariant carries its Priority field (set via WithVariant), which +// the ranking function may use as a baseline signal alongside client hints. +// +// Note: The default (first) variant is also used when the client does not +// support variants at all. +type RankingFunc func(ctx context.Context, hints VariantHints, variants []ServerVariant) []ServerVariant diff --git a/go/sdk/variants/variant.go b/go/sdk/variants/variant.go deleted file mode 100644 index c7d3f83..0000000 --- a/go/sdk/variants/variant.go +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2025 The MCP Variants Authors. All rights reserved. -// Use of this source code is governed by a Apache-2.0 -// license that can be found in the LICENSE file. - -// Package variants implements MCP Variants for experimental extensions. -package variants