sdk

module
v0.0.0-...-e1c17e0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 1, 2026 License: Apache-2.0

README

MCP Variants - Go Implementation

Go implementation of SEP-2053: Server Variants — a server-level variant mechanism for MCP that lets servers expose multiple tool/resource/prompt sets simultaneously, selectable per-request via _meta.

Quick Start

package main

import (
    "log"
    "net/http"

    "github.com/modelcontextprotocol/go-sdk/mcp"
    "github.com/modelcontextprotocol/experimental-ext-variants/go/sdk/variants"
)

func main() {
    // Code review variant: PR-focused tools
    codeReviewServer := mcp.NewServer(&mcp.Implementation{Name: "devplatform", Version: "v1.0.0"}, nil)
    mcp.AddTool(codeReviewServer, &mcp.Tool{
        Name:        "list_pull_requests",
        Description: "List open pull requests, optionally filtered by author",
    }, listPullRequests)
    mcp.AddTool(codeReviewServer, &mcp.Tool{
        Name:        "get_diff",
        Description: "Get the diff for a pull request",
    }, getDiff)

    // Project management variant: issue-focused tools
    pmServer := mcp.NewServer(&mcp.Implementation{Name: "devplatform", Version: "v1.0.0"}, nil)
    mcp.AddTool(pmServer, &mcp.Tool{
        Name:        "list_issues",
        Description: "List issues, optionally filtered by state and labels",
    }, listIssues)
    mcp.AddTool(pmServer, &mcp.Tool{
        Name:        "create_issue",
        Description: "Create a new issue with title, body, and optional labels",
    }, createIssue)

    vs := variants.NewServer(&mcp.Implementation{Name: "devplatform", Version: "v1.0.0"}).
        WithVariant(variants.ServerVariant{
            ID:          "code-review",
            Description: "Pull request and code review operations. Includes diff viewing, review comments, approval workflows, and merge controls.",
            Hints:       map[string]string{"domain": "code-review", "accessLevel": "read-write"},
            Status:      variants.Stable,
        }, codeReviewServer, 0).
        WithVariant(variants.ServerVariant{
            ID:          "project-management",
            Description: "Issue and project tracking operations. Includes issue CRUD, labels, milestones, assignments, and project boards.",
            Hints:       map[string]string{"domain": "project-management", "accessLevel": "read-write"},
            Status:      variants.Stable,
        }, pmServer, 1)

    // Serve over HTTP (or use vs.Run(ctx, &mcp.StdioTransport{}) for stdio)
    handler := variants.NewStreamableHTTPHandler(vs, nil)
    log.Fatal(http.ListenAndServe(":8080", handler))
}

Clients select a variant per-request via _meta:

{
  "method": "tools/list",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/server-variant": "code-review"
    }
  }
}

Clients that don't know about variants get the default (first-ranked) variant automatically.

How It Works

During initialize, the server responds with ranked availableVariants:

{
  "capabilities": {
    "experimental": {
      "io.modelcontextprotocol/server-variants": {
        "availableVariants": [
          {
            "id": "code-review",
            "description": "Pull request and code review operations...",
            "hints": { "domain": "code-review", "accessLevel": "read-write" },
            "status": "stable"
          },
          {
            "id": "project-management",
            "description": "Issue and project tracking operations...",
            "hints": { "domain": "project-management", "accessLevel": "read-write" },
            "status": "stable"
          }
        ],
        "moreVariantsAvailable": false
      }
    }
  }
}

Each subsequent request can target a specific variant via _meta. The server routes the request to the appropriate backing mcp.Server:

Client ── transport ──▸ variants.Server ──▸ sessionMiddleware
                                                 │
                                    ┌────────────┼────────────┐
                                    │            │            │
                              initialize    route by     pass through
                              (create        _meta       (ping, etc.)
                               per-session   variant
                               connections)     │
                                                ▼
                                           dispatcher
                                                │
                          ┌────────────┬────────┴────────┬────────────┐
                          ▼            ▼                 ▼            ▼
                    code-review  project-mgmt   security-readonly  ci-automation
                    (mcp.Server) (mcp.Server)   (mcp.Server)       (mcp.Server)

In stateful mode (default, stdio and HTTP), per-session inner connections are created during initialize and scoped to the client session's lifetime. In stateless mode (via NewStreamableHTTPHandler with Stateless: true), a single set of shared connections is created at construction and reused across all requests.

Features

  • Variant isolation: each variant is a full mcp.Server with its own tools, resources, and prompts
  • Per-request selection: variant chosen via _meta field, no session state needed
  • Default fallback: clients without variant support get the first-ranked variant
  • Custom ranking: provide a RankingFunc to rank variants based on client hints
  • Cursor scoping: pagination cursors are variant-scoped and cannot be reused across variants (per SEP-2053)
  • Namespace scoping: tool names, prompt names, and resource URIs resolve within the active variant's namespace; errors include activeVariant in error data
  • Notification forwarding: progress and logging notifications from inner servers are forwarded to the front client with variant metadata injected
  • HTTP and stdio: works with both StdioTransport and StreamableHTTPHandler

Examples

See examples/server/ for runnable examples.

API

Server
variants.NewServer(impl *mcp.Implementation) *Server

Creates a new variant-aware server with no registered variants. impl must not be nil.

(*Server).WithVariant(v ServerVariant, mcpServer *mcp.Server, priority int) *Server

Registers a variant backed by an in-memory mcp.Server. priority determines the default ordering when no RankingFunc is set — lower values rank higher (0 = highest priority). Panics on duplicate variant IDs. Returns the receiver for chaining.

(*Server).WithRanking(fn RankingFunc) *Server

Sets a custom ranking function used to order variants based on client hints during initialization. If nil, variants are ordered by priority value.

(*Server).Variants() []ServerVariant

Returns a copy of all registered variants in registration order.

(*Server).RankedVariants(ctx context.Context, hints VariantHints) []ServerVariant

Returns registered variants ranked by the configured RankingFunc (or default priority-based ranking).

(*Server).Run(ctx context.Context, t mcp.Transport) error

Starts the server on the given transport (e.g., &mcp.StdioTransport{}). For multi-client HTTP support, use NewStreamableHTTPHandler instead.

(*Server).Close() error

Releases resources held by all registered backends.

variants.NewStreamableHTTPHandler(vs *Server, opts *mcp.StreamableHTTPOptions) *mcp.StreamableHTTPHandler

Returns an http.Handler for serving multiple concurrent clients over HTTP. Pass &mcp.StreamableHTTPOptions{Stateless: true} for stateless mode.

Types
ServerVariant

Describes a selectable variant:

type ServerVariant struct {
    ID              string            `json:"id"`
    Description     string            `json:"description"`
    Hints           map[string]string `json:"hints,omitempty"`
    Status          VariantStatus     `json:"status,omitempty"`
    DeprecationInfo *DeprecationInfo  `json:"deprecationInfo,omitempty"`
}

Priority() int returns the priority value set during registration.

VariantStatus
const (
    Stable       VariantStatus = "stable"
    Experimental VariantStatus = "experimental"
    Deprecated   VariantStatus = "deprecated"
)
DeprecationInfo

Migration guidance for deprecated variants:

type DeprecationInfo struct {
    Message     string `json:"message"`
    Replacement string `json:"replacement,omitempty"`
    RemovalDate string `json:"removalDate,omitempty"`
}
VariantHints

Client-provided hints for variant selection, sent during initialize:

type VariantHints struct {
    Description string         `json:"description,omitempty"`
    Hints       map[string]any `json:"hints,omitempty"`
}
HintValue[T any](h VariantHints, key string) (T, bool)

Generic helper to extract a typed value from a VariantHints map.

RankingFunc
type RankingFunc func(ctx context.Context, hints VariantHints, variants []ServerVariant) []ServerVariant

Called during initialization to rank variants based on client hints. Must return variants sorted by relevance, most appropriate first.

Well-known hint keys
Constant Key Example values
HintModelFamily "modelFamily" "anthropic", "openai", "local", "any"
HintUseCase "useCase" "autonomous-agent", "ide", "chat"
HintContextSize "contextSize" "compact", "standard", "verbose"
HintRenderingCapabilities "renderingCapabilities" "rich", "markdown", "text-only"
HintLanguageOptimization "languageOptimization" "en", "multilingual", "code-focused"

Known Limitations

  • Default variant resolution: When a client omits _meta variant selection, the server re-ranks variants with empty hints to determine the default. This may differ from the ranking returned during initialize (where client hints were used). Per SEP-2053, the default should be the first variant from the initialize response. To fix this, the per-session ranked order needs to be stored during initialize and reused for subsequent requests.
  • List-changed notifications: Dynamic capability changes from inner servers (tool/resource/prompt list changes) are not forwarded to front clients. The Go MCP SDK does not expose generic notification sending on ServerSession. In practice this is acceptable because inner servers are typically statically configured.
  • HTTP and remote backends: WithHTTPVariant and WithRemoteVariant are not yet implemented.

Directories

Path Synopsis
examples
server/github command
Example: GitHub MCP Server — a developer productivity platform that exposes different tool sets for different agent types using MCP server variants.
Example: GitHub MCP Server — a developer productivity platform that exposes different tool sets for different agent types using MCP server variants.
server/model-optimized command
Example: Model-Optimized Weather Service — the same tools with different descriptions and schemas optimized for different LLM families.
Example: Model-Optimized Weather Service — the same tools with different descriptions and schemas optimized for different LLM families.
server/research command
Example: Research Assistant — context budget management with the same tools at different verbosity levels.
Example: Research Assistant — context budget management with the same tools at different verbosity levels.
server/trading command
Example: Trading Platform — API versioning and lifecycle management using MCP server variants.
Example: Trading Platform — API versioning and lifecycle management using MCP server variants.
server/variants-stdio command
Example: Minimal variant-aware MCP server over stdio.
Example: Minimal variant-aware MCP server over stdio.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL