vmcp

package
v0.8.1 Latest Latest
Warning

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

Go to latest
Published: Jan 27, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package vmcp provides the Virtual MCP Server implementation.

Virtual MCP Server aggregates multiple MCP servers from a ToolHive group into a single unified interface. This package contains the core domain models and interfaces that are platform-agnostic (work for both CLI and Kubernetes deployments).

Architecture

The vmcp package follows Domain-Driven Design (DDD) principles with clear separation of concerns into bounded contexts:

pkg/vmcp/
├── types.go              // Shared domain types (BackendTarget, Tool, etc.)
├── errors.go             // Domain errors
├── router/               // Request routing
│   └── router.go         // Router interface + routing strategies
├── aggregator/           // Capability aggregation
│   └── aggregator.go     // Aggregator interface + conflict resolution
├── auth/                 // Authentication (incoming & outgoing)
│   └── auth.go           // Auth interfaces + strategies
├── composer/             // Composite tool workflows
│   └── composer.go       // Composer interface + workflow engine
├── config/               // Configuration model
│   └── config.go         // Config types + loaders
└── cache/                // Token caching
    └── cache.go          // Cache interface + implementations

Core Concepts

**Routing**: Forward MCP protocol requests (tools, resources, prompts) to appropriate backend workloads. Supports session affinity and load balancing.

**Aggregation**: Discover backend capabilities, resolve naming conflicts, and merge into a unified view. Three-stage process: discovery, conflict resolution, merging.

**Authentication**: Two-boundary model:

  • Incoming: Clients authenticate to virtual MCP (OIDC, local, anonymous)
  • Outgoing: Virtual MCP authenticates to backends (extensible strategies)

**Composition**: Execute multi-step workflows across multiple backends. Supports sequential and parallel execution, elicitation, error handling.

**Configuration**: Platform-agnostic config model with adapters for CLI (YAML) and Kubernetes (CRDs).

**Caching**: Token caching to reduce auth overhead. Pluggable backends (memory, Redis).

Key Interfaces

Router (pkg/vmcp/router):

type Router interface {
	RouteTool(ctx context.Context, toolName string) (*vmcp.BackendTarget, error)
	RouteResource(ctx context.Context, uri string) (*vmcp.BackendTarget, error)
	RoutePrompt(ctx context.Context, name string) (*vmcp.BackendTarget, error)
}

Aggregator (pkg/vmcp/aggregator):

type Aggregator interface {
	DiscoverBackends(ctx context.Context) ([]vmcp.Backend, error)
	QueryCapabilities(ctx context.Context, backend vmcp.Backend) (*BackendCapabilities, error)
	ResolveConflicts(ctx context.Context, capabilities map[string]*BackendCapabilities) (*ResolvedCapabilities, error)
	MergeCapabilities(ctx context.Context, resolved *ResolvedCapabilities) (*AggregatedCapabilities, error)
}

Composer (pkg/vmcp/composer):

type Composer interface {
	ExecuteWorkflow(ctx context.Context, def *WorkflowDefinition, params map[string]any) (*WorkflowResult, error)
	ValidateWorkflow(ctx context.Context, def *WorkflowDefinition) error
	GetWorkflowStatus(ctx context.Context, workflowID string) (*WorkflowStatus, error)
	CancelWorkflow(ctx context.Context, workflowID string) error
}

IncomingAuthenticator (pkg/vmcp/auth):

type IncomingAuthenticator interface {
	Authenticate(ctx context.Context, r *http.Request) (*Identity, error)
	Middleware() func(http.Handler) http.Handler
}

OutgoingAuthRegistry (pkg/vmcp/auth):

type OutgoingAuthRegistry interface {
	GetStrategy(name string) (Strategy, error)
	RegisterStrategy(name string, strategy Strategy) error
}

Design Principles

  1. Platform Independence: Core domain logic works for both CLI and Kubernetes
  2. Interface Segregation: Small, focused interfaces for better testability
  3. Dependency Inversion: Depend on abstractions, not concrete implementations
  4. Modularity: Each bounded context can be developed and tested independently
  5. Extensibility: Plugin architecture for auth strategies, routing strategies, etc.
  6. Type Safety: Shared types at package root avoid circular dependencies

Usage Example

import (
	"github.com/stacklok/toolhive/pkg/vmcp"
	"github.com/stacklok/toolhive/pkg/vmcp/router"
	"github.com/stacklok/toolhive/pkg/vmcp/aggregator"
	"github.com/stacklok/toolhive/pkg/vmcp/auth"
)

// Load configuration
cfg, err := loadConfig("vmcp-config.yaml")
if err != nil {
	return err
}

// Create components
agg := createAggregator(cfg)
rtr := createRouter(cfg)
inAuth := createIncomingAuth(cfg)
outAuth := createOutgoingAuth(cfg)

// Discover and aggregate backends
backends, err := agg.DiscoverBackends(ctx)
capabilities, err := agg.AggregateCapabilities(ctx, backends)

// With lazy discovery, capabilities are stored in request context
// by the discovery middleware, not in the router

// Handle incoming requests
http.Handle("/tools/call", inAuth.Middleware()(
	http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Authenticate request
		identity, err := inAuth.Authenticate(ctx, r)

		// Route to backend (router gets capabilities from context)
		target, err := rtr.RouteTool(ctx, toolName)

		// Authenticate to backend (resolve strategy and call it)
		backendReq := createBackendRequest(...)
		strategy, err := outAuth.GetStrategy(target.AuthConfig.Type)
		err = strategy.Authenticate(ctx, backendReq, target.AuthConfig)

		// Forward request and return response
		// ...
	}),
))

- Proposal: docs/proposals/THV-2106-virtual-mcp-server.md - GitHub Issues: #146-159 in stacklok/stacklok-epics - MCP Specification: https://modelcontextprotocol.io/specification

See individual subpackage documentation for detailed usage and examples.

Index

Constants

View Source
const (
	ConditionTypeBackendsDiscovered = "BackendsDiscovered"
	ConditionTypeReady              = "Ready"
	ConditionTypeAuthConfigured     = "AuthConfigured"
)

Condition type constants for common vMCP conditions.

View Source
const (
	ReasonBackendDiscoverySucceeded = "BackendDiscoverySucceeded"
	ReasonBackendDiscoveryFailed    = "BackendDiscoveryFailed"
	ReasonServerReady               = "ServerReady"
	ReasonServerStarting            = "ServerStarting"
	ReasonServerDegraded            = "ServerDegraded"
	ReasonServerFailed              = "ServerFailed"
)

Reason constants for condition reasons.

Variables

View Source
var (
	// ErrNotFound indicates a requested resource (tool, resource, prompt, workflow) was not found.
	// Wrapping errors should provide specific details about what was not found.
	ErrNotFound = errors.New("not found")

	// ErrInvalidConfig indicates invalid configuration was provided.
	// Wrapping errors should provide specific details about what is invalid.
	ErrInvalidConfig = errors.New("invalid configuration")

	// ErrAuthenticationFailed indicates authentication failure.
	// Wrapping errors should include the underlying authentication error.
	ErrAuthenticationFailed = errors.New("authentication failed")

	// ErrAuthorizationFailed indicates authorization failure.
	// Wrapping errors should include the policy or permission that was denied.
	ErrAuthorizationFailed = errors.New("authorization failed")

	// ErrWorkflowFailed indicates workflow execution failed.
	// Wrapping errors should include the step ID and failure reason.
	ErrWorkflowFailed = errors.New("workflow execution failed")

	// ErrTimeout indicates an operation timed out.
	// Wrapping errors should include the operation type and timeout duration.
	ErrTimeout = errors.New("operation timed out")

	// ErrCancelled indicates an operation was cancelled.
	// Context cancellation should wrap this error with context.Cause().
	ErrCancelled = errors.New("operation cancelled")

	// ErrInvalidInput indicates invalid input parameters.
	// Wrapping errors should specify which parameter is invalid and why.
	ErrInvalidInput = errors.New("invalid input")

	// ErrUnsupportedTransport indicates an unsupported MCP transport type.
	// Wrapping errors should specify which transport type is not supported.
	ErrUnsupportedTransport = errors.New("unsupported transport type")

	// ErrToolExecutionFailed indicates an MCP tool execution failed (domain error).
	// This represents the tool running but returning an error result (IsError=true in MCP).
	// These errors should be forwarded to the client transparently as the LLM needs to see them.
	// Wrapping errors should include the tool name and error message from MCP.
	ErrToolExecutionFailed = errors.New("tool execution failed")

	// ErrBackendUnavailable indicates a backend MCP server is unreachable (operational error).
	// This represents infrastructure issues (network down, server not responding, etc.).
	// These errors may be retried, circuit-broken, or handled differently from domain errors.
	// Wrapping errors should include the backend ID and underlying cause.
	ErrBackendUnavailable = errors.New("backend unavailable")

	// ErrToolNameConflict indicates a composite tool name conflicts with a backend tool name.
	// This prevents ambiguity in routing/execution where the same name could refer to
	// either a backend tool or a composite workflow tool.
	// Wrapping errors should list the conflicting tool names.
	ErrToolNameConflict = errors.New("tool name conflict")
)

Functions

func IsAuthenticationError added in v0.6.16

func IsAuthenticationError(err error) bool

IsAuthenticationError checks if an error message indicates an authentication failure. Uses case-insensitive pattern matching to detect various auth error formats from HTTP libraries, MCP protocol errors, and authentication middleware.

func IsConnectionError added in v0.6.16

func IsConnectionError(err error) bool

IsConnectionError checks if an error message indicates a connection failure. Detects network-level errors like connection refused, reset, unreachable, etc.

func IsTimeoutError added in v0.6.16

func IsTimeoutError(err error) bool

IsTimeoutError checks if an error message indicates a timeout. Detects various timeout formats from context deadlines, HTTP timeouts, and network timeout errors.

Types

type Backend

type Backend struct {
	// ID is the unique identifier for this backend.
	ID string

	// Name is the human-readable name.
	Name string

	// BaseURL is the backend's MCP server URL.
	BaseURL string

	// TransportType is the MCP transport protocol.
	TransportType string

	// HealthStatus is the current health state.
	HealthStatus BackendHealthStatus

	// AuthConfig contains the typed authentication configuration for this backend.
	// The actual authentication is handled by OutgoingAuthRegistry interface.
	// If nil, the backend requires no authentication.
	AuthConfig *authtypes.BackendAuthStrategy

	// AuthConfigRef is the name of the MCPExternalAuthConfig resource (if any).
	// This field is populated during backend discovery and is useful for
	// debugging and status reporting.
	// +optional
	AuthConfigRef string

	// Metadata stores additional backend information.
	Metadata map[string]string
}

Backend represents a discovered backend MCP server workload.

type BackendClient

type BackendClient interface {
	// CallTool invokes a tool on the backend MCP server.
	// The meta parameter contains _meta fields from the client request that should be forwarded to the backend.
	// Returns the complete tool result including _meta field from the backend response.
	CallTool(
		ctx context.Context, target *BackendTarget, toolName string, arguments map[string]any, meta map[string]any,
	) (*ToolCallResult, error)

	// ReadResource retrieves a resource from the backend MCP server.
	// Returns the complete resource result including _meta field.
	ReadResource(ctx context.Context, target *BackendTarget, uri string) (*ResourceReadResult, error)

	// GetPrompt retrieves a prompt from the backend MCP server.
	// Returns the complete prompt result including _meta field.
	GetPrompt(ctx context.Context, target *BackendTarget, name string, arguments map[string]any) (*PromptGetResult, error)

	// ListCapabilities queries a backend for its capabilities.
	// Returns tools, resources, and prompts exposed by the backend.
	ListCapabilities(ctx context.Context, target *BackendTarget) (*CapabilityList, error)
}

BackendClient abstracts MCP protocol communication with backend servers. This interface handles the protocol-level details of calling backend MCP servers, supporting multiple transport types (HTTP, SSE, stdio, streamable-http).

All methods return wrapper types that preserve the _meta field from backend MCP server responses. Protocol-level metadata (progress tokens, trace context, custom metadata) is forwarded to clients where supported (tools and prompts). Note: Resource _meta forwarding is not currently supported due to MCP SDK handler signature limitations; the Meta field is preserved for future SDK improvements.

type BackendHealthStatus

type BackendHealthStatus string

BackendHealthStatus represents the health state of a backend.

const (
	// BackendHealthy indicates the backend is healthy and accepting requests.
	BackendHealthy BackendHealthStatus = "healthy"

	// BackendDegraded indicates the backend is operational but experiencing issues.
	// This occurs when:
	// - Health checks succeed but response times exceed the degraded threshold (slow but working)
	// - Backend just recovered from failures and is in a stabilizing state
	BackendDegraded BackendHealthStatus = "degraded"

	// BackendUnhealthy indicates the backend is not responding to health checks.
	BackendUnhealthy BackendHealthStatus = "unhealthy"

	// BackendUnknown indicates the backend health status is unknown.
	BackendUnknown BackendHealthStatus = "unknown"

	// BackendUnauthenticated indicates the backend is not authenticated.
	BackendUnauthenticated BackendHealthStatus = "unauthenticated"
)

func (BackendHealthStatus) ToCRDStatus added in v0.8.1

func (s BackendHealthStatus) ToCRDStatus() string

ToCRDStatus converts BackendHealthStatus to CRD-friendly status string. This maps internal health states to user-facing status values:

  • healthy → ready
  • degraded → degraded
  • unhealthy → unavailable
  • unauthenticated → unavailable (unauthenticated is a reason, not a status)
  • unknown → unknown

type BackendRegistry

type BackendRegistry interface {
	// Get retrieves a backend by ID.
	// Returns nil if the backend is not found.
	// This method is safe for concurrent reads.
	//
	// Example:
	//   backend := registry.Get(ctx, "github-mcp")
	//   if backend == nil {
	//       return fmt.Errorf("backend not found")
	//   }
	Get(ctx context.Context, backendID string) *Backend

	// List returns all registered backends.
	// The returned slice is a snapshot and safe to iterate without additional locking.
	// Order is not guaranteed unless specified by the implementation.
	//
	// Example:
	//   backends := registry.List(ctx)
	//   for _, backend := range backends {
	//       fmt.Printf("Backend: %s\n", backend.Name)
	//   }
	List(ctx context.Context) []Backend

	// Count returns the number of registered backends.
	// This is more efficient than len(List()) for large registries.
	Count() int
}

BackendRegistry provides thread-safe access to discovered backends. This is a shared kernel interface used across vmcp bounded contexts (aggregator, router, health monitoring).

The registry serves as the single source of truth for backend information during the lifecycle of a virtual MCP server instance. It supports both immutable (Phase 1) and mutable (future phases) implementations.

Design Philosophy:

  • Phase 1: Immutable registry (backends discovered once, never change)
  • Future: Mutable registry with health monitoring and dynamic updates
  • Thread-safe for concurrent reads across all implementations
  • Implementations may support concurrent writes with appropriate locking

func NewImmutableRegistry

func NewImmutableRegistry(backends []Backend) BackendRegistry

NewImmutableRegistry creates a registry from a static list of backends.

This implementation is used in Phase 1 where backends are discovered once at startup and don't change during the virtual MCP server's lifetime. The registry is thread-safe for concurrent reads.

Parameters:

  • backends: List of discovered backends to register

Returns:

  • BackendRegistry: An immutable registry instance

Example:

backends := discoverer.Discover(ctx, "engineering-team")
registry := vmcp.NewImmutableRegistry(backends)
backend := registry.Get(ctx, "github-mcp")

type BackendTarget

type BackendTarget struct {
	// WorkloadID is the unique identifier for the backend workload.
	WorkloadID string

	// WorkloadName is the human-readable name of the workload.
	WorkloadName string

	// BaseURL is the base URL for the backend's MCP server.
	// For local deployments: http://localhost:PORT
	// For Kubernetes: http://service-name.namespace.svc.cluster.local:PORT
	BaseURL string

	// TransportType specifies the MCP transport protocol.
	// Supported: "stdio", "http", "sse", "streamable-http"
	TransportType string

	// OriginalCapabilityName is the original name of the capability (tool/resource/prompt)
	// as known by the backend. This is used when forwarding requests to the backend.
	//
	// When conflict resolution renames capabilities, this field preserves the original name:
	// - Prefix strategy: "fetch" → "fetch_fetch" (OriginalCapabilityName="fetch")
	// - Priority strategy: usually unchanged (OriginalCapabilityName="tool_name")
	// - Manual strategy: "fetch" → "custom_name" (OriginalCapabilityName="fetch")
	//
	// If empty, the resolved name is used when forwarding to the backend.
	//
	// IMPORTANT: Do NOT access this field directly when forwarding requests to backends.
	// Use GetBackendCapabilityName() method instead, which handles both renamed and
	// non-renamed capabilities correctly. Direct access can lead to incorrect behavior
	// when capabilities are not renamed (OriginalCapabilityName will be empty).
	//
	// Example (WRONG):
	//   client.CallTool(ctx, target, target.OriginalCapabilityName, args) // BUG: fails when empty
	//
	// Example (CORRECT):
	//   client.CallTool(ctx, target, target.GetBackendCapabilityName(toolName), args)
	OriginalCapabilityName string

	// AuthConfig contains the typed authentication configuration for this backend.
	// The actual authentication is handled by OutgoingAuthRegistry interface.
	// If nil, the backend requires no authentication.
	AuthConfig *authtypes.BackendAuthStrategy

	// SessionAffinity indicates if requests from the same session
	// must be routed to this specific backend instance.
	SessionAffinity bool

	// HealthStatus indicates the current health of the backend.
	HealthStatus BackendHealthStatus

	// Metadata stores additional backend-specific information.
	Metadata map[string]string
}

BackendTarget identifies a specific backend workload and provides the information needed to forward requests to it.

func BackendToTarget

func BackendToTarget(backend *Backend) *BackendTarget

BackendToTarget converts a Backend to a BackendTarget for routing. This helper is used when populating routing tables during capability aggregation.

The BackendTarget contains all information needed to forward requests to a specific backend workload, including authentication strategy and metadata.

func (*BackendTarget) GetBackendCapabilityName added in v0.6.0

func (t *BackendTarget) GetBackendCapabilityName(resolvedName string) string

GetBackendCapabilityName returns the name to use when forwarding a request to the backend. If conflict resolution renamed the capability, this returns the original name that the backend expects. Otherwise, it returns the resolved name as-is.

This method encapsulates the name translation logic for all capability types (tools, resources, prompts).

ALWAYS use this method when forwarding capability calls to backends. Do NOT access OriginalCapabilityName directly, as it may be empty when no renaming occurred.

Usage example:

target, _ := router.RouteTool(ctx, "fetch_fetch")  // Prefixed name from client
backendName := target.GetBackendCapabilityName("fetch_fetch")  // Returns "fetch"
client.CallTool(ctx, target, backendName, args)  // Backend receives original name

This ensures correct behavior regardless of conflict resolution strategy:

  • Prefix strategy: "fetch_fetch" → "fetch" (renamed, uses OriginalCapabilityName)
  • Priority strategy: "list_issues" → "list_issues" (not renamed, returns resolvedName)
  • Manual strategy: "custom_fetch" → "fetch" (renamed, uses OriginalCapabilityName)

type CapabilityList

type CapabilityList struct {
	// Tools available on this backend.
	Tools []Tool

	// Resources available on this backend.
	Resources []Resource

	// Prompts available on this backend.
	Prompts []Prompt

	// SupportsLogging indicates if the backend supports MCP logging.
	SupportsLogging bool

	// SupportsSampling indicates if the backend supports MCP sampling.
	SupportsSampling bool
}

CapabilityList contains the capabilities from a backend's MCP server. This is returned by BackendClient.ListCapabilities().

type Condition added in v0.8.1

type Condition = metav1.Condition

Condition represents a specific aspect of vMCP server status.

type ConflictResolutionStrategy

type ConflictResolutionStrategy string

ConflictResolutionStrategy defines how to handle capability name conflicts. Placed in vmcp root package to be shared by config and aggregator packages.

const (
	// ConflictStrategyPrefix prefixes all tools with workload identifier.
	ConflictStrategyPrefix ConflictResolutionStrategy = "prefix"

	// ConflictStrategyPriority uses explicit priority ordering (first wins).
	ConflictStrategyPriority ConflictResolutionStrategy = "priority"

	// ConflictStrategyManual requires explicit overrides for all conflicts.
	ConflictStrategyManual ConflictResolutionStrategy = "manual"
)

type Content added in v0.8.1

type Content struct {
	// Type indicates the content type: "text", "image", "audio", "resource"
	Type string

	// Text is the content text (for TextContent)
	Text string

	// Data is the base64-encoded data (for ImageContent/AudioContent)
	Data string

	// MimeType is the MIME type (for ImageContent/AudioContent)
	MimeType string

	// URI is the resource URI (for EmbeddedResource)
	URI string
}

Content represents MCP content (text, image, audio, embedded resource). This is used by ToolCallResult to preserve the full content structure from backends.

type DiscoveredBackend added in v0.8.1

type DiscoveredBackend struct {
	// Name is the name of the backend MCPServer
	Name string `json:"name"`

	// URL is the URL of the backend MCPServer
	// +optional
	URL string `json:"url,omitempty"`

	// Status is the current status of the backend (ready, degraded, unavailable, unknown).
	// Use BackendHealthStatus.ToCRDStatus() to populate this field.
	// +optional
	Status string `json:"status,omitempty"`

	// AuthConfigRef is the name of the discovered MCPExternalAuthConfig (if any)
	// +optional
	AuthConfigRef string `json:"authConfigRef,omitempty"`

	// AuthType is the type of authentication configured
	// +optional
	AuthType string `json:"authType,omitempty"`

	// LastHealthCheck is the timestamp of the last health check
	// +optional
	LastHealthCheck metav1.Time `json:"lastHealthCheck,omitempty"`

	// Message provides additional information about the backend status
	// +optional
	Message string `json:"message,omitempty"`
}

DiscoveredBackend represents a backend server discovered by vMCP runtime. This type is shared with the Kubernetes operator CRD (VirtualMCPServer.Status.DiscoveredBackends).

func (*DiscoveredBackend) DeepCopy added in v0.8.1

func (in *DiscoveredBackend) DeepCopy() *DiscoveredBackend

DeepCopy creates a deep copy of DiscoveredBackend. Required for Kubernetes CRD types.

func (*DiscoveredBackend) DeepCopyInto added in v0.8.1

func (in *DiscoveredBackend) DeepCopyInto(out *DiscoveredBackend)

DeepCopyInto copies the receiver into out. Required for Kubernetes CRD types.

type DynamicRegistry added in v0.6.17

type DynamicRegistry interface {
	BackendRegistry

	// Upsert adds or updates a backend atomically.
	// Idempotent - calling with the same backend multiple times is safe.
	// Increments Version() on every call.
	//
	// Parameters:
	//   - backend: The backend to add or update
	//
	// Returns:
	//   - error: Returns error if backend has empty ID
	//
	// Example:
	//   err := registry.Upsert(vmcp.Backend{
	//       ID: "github-mcp",
	//       Name: "GitHub MCP",
	//       BaseURL: "http://github-mcp.default.svc.cluster.local:8080",
	//   })
	Upsert(backend Backend) error

	// Remove deletes a backend by ID.
	// Idempotent - removing non-existent backends returns nil.
	// Increments Version() on every call.
	//
	// Parameters:
	//   - backendID: The ID of the backend to remove
	//
	// Returns:
	//   - error: Always returns nil (operation is always successful)
	//
	// Example:
	//   err := registry.Remove("github-mcp")
	Remove(backendID string) error

	// Version returns the current registry version.
	// Increments on every mutation (Upsert/Remove).
	// Used for cache invalidation in discovery manager.
	//
	// Returns:
	//   - uint64: Monotonic version counter
	//
	// Example:
	//   version := registry.Version()
	//   // Cache entries tagged with this version
	Version() uint64
}

DynamicRegistry extends BackendRegistry with mutable operations. This implementation supports thread-safe backend updates with version-based cache invalidation for dynamic discovery mode.

The registry maintains a monotonic version counter that increments on every mutation (Upsert/Remove). This enables lazy cache invalidation in the discovery manager without thundering herd problems.

Design Philosophy:

  • Thread-safe for concurrent reads and writes using RWMutex
  • Idempotent operations (Upsert/Remove safe to call multiple times)
  • Version-based cache invalidation (no event callbacks needed)
  • Used in dynamic discovery mode for K8s-aware vMCP servers

func NewDynamicRegistry added in v0.6.17

func NewDynamicRegistry(backends []Backend) DynamicRegistry

NewDynamicRegistry creates a new mutable registry with optional initial backends.

This implementation is used in dynamic discovery mode where backends can change during the virtual MCP server's lifetime (e.g., K8s-aware vMCP servers). The registry is thread-safe for concurrent reads and writes.

Version Tracking: The registry starts at version 0 regardless of the number of initial backends. Initial backends are considered the baseline state, not mutations. This ensures:

  • Cache coherence: Discovery manager caches capabilities with version 0 at startup
  • Consistency: All servers starting with same backends have same initial version
  • Predictability: Version only increments for runtime changes (Upsert/Remove)

Version increments only occur when backends are added/removed AFTER initialization, which triggers cache invalidation in the discovery manager.

Parameters:

  • backends: Optional list of initial backends to register

Returns:

  • DynamicRegistry: A mutable registry instance starting at version 0

Example:

// Start with 2 backends, version = 0
registry := vmcp.NewDynamicRegistry([]Backend{backend1, backend2})
// Add a third backend, version = 1 (triggers cache invalidation)
err := registry.Upsert(backend3)

type HealthChecker

type HealthChecker interface {
	// CheckHealth checks if a backend is healthy and responding.
	// Returns the current health status and any error encountered.
	CheckHealth(ctx context.Context, target *BackendTarget) (BackendHealthStatus, error)
}

HealthChecker performs health checks on backend MCP servers.

type Phase added in v0.8.1

type Phase string

Phase represents the operational lifecycle phase of a vMCP server.

const (
	PhasePending  Phase = "Pending"
	PhaseReady    Phase = "Ready"
	PhaseDegraded Phase = "Degraded"
	PhaseFailed   Phase = "Failed"
)

Phase constants for vMCP server lifecycle.

type Prompt

type Prompt struct {
	// Name is the prompt name (may conflict with other backends).
	Name string

	// Description describes the prompt.
	Description string

	// Arguments are the prompt parameters.
	Arguments []PromptArgument

	// BackendID identifies the backend that provides this prompt.
	BackendID string
}

Prompt represents an MCP prompt capability.

type PromptArgument

type PromptArgument struct {
	// Name is the argument name.
	Name string

	// Description describes the argument.
	Description string

	// Required indicates if the argument is mandatory.
	Required bool
}

PromptArgument represents a prompt parameter.

type PromptGetResult added in v0.8.1

type PromptGetResult struct {
	// Messages is the concatenated prompt text from all messages.
	Messages string

	// Description is an optional description of the prompt.
	Description string

	// Meta contains protocol-level metadata from the backend (_meta field).
	// This includes progressToken, trace context, and custom backend metadata.
	// Per MCP specification, this field is optional and may be nil.
	Meta map[string]any
}

PromptGetResult wraps a prompt response with metadata. This preserves both the prompt messages AND the _meta field from the backend MCP server.

type Resource

type Resource struct {
	// URI is the resource URI (should be globally unique).
	URI string

	// Name is a human-readable name.
	Name string

	// Description describes the resource.
	Description string

	// MimeType is the resource's MIME type (optional).
	MimeType string

	// BackendID identifies the backend that provides this resource.
	BackendID string
}

Resource represents an MCP resource capability.

type ResourceReadResult added in v0.8.1

type ResourceReadResult struct {
	// Contents is the concatenated resource data.
	// When a resource has multiple contents (text or blob), they are concatenated
	// directly without separators. Text contents are converted to bytes, blob contents
	// are base64-decoded before concatenation.
	Contents []byte

	// MimeType is the content type of the resource.
	MimeType string

	// Meta contains protocol-level metadata from the backend (_meta field).
	// NOTE: Due to MCP SDK limitations, resources/read handlers cannot forward _meta
	// because they return []ResourceContents directly, not a result wrapper.
	// This field is preserved for future SDK improvements but may be nil.
	Meta map[string]any
}

ResourceReadResult wraps a resource read response with metadata. This preserves both the resource data AND the _meta field from the backend MCP server.

type RoutingTable

type RoutingTable struct {
	// Tools maps tool names to their backend targets.
	// After conflict resolution, tool names are unique.
	Tools map[string]*BackendTarget

	// Resources maps resource URIs to their backend targets.
	Resources map[string]*BackendTarget

	// Prompts maps prompt names to their backend targets.
	Prompts map[string]*BackendTarget
}

RoutingTable contains the mappings from capability names to backend targets. This is the output of the aggregation phase and input to the router. Placed in vmcp root package to avoid circular dependencies between aggregator and router packages.

Note: Composite tools are NOT included here. They are executed by the composer package and do not route to a single backend.

type Status added in v0.8.1

type Status struct {
	Phase              Phase               `json:"phase"`
	Message            string              `json:"message,omitempty"`
	Conditions         []Condition         `json:"conditions,omitempty"`
	DiscoveredBackends []DiscoveredBackend `json:"discoveredBackends,omitempty"`
	BackendCount       int                 `json:"backendCount,omitempty"`
	ObservedGeneration int64               `json:"observedGeneration,omitempty"`
	Timestamp          time.Time           `json:"timestamp"`
}

Status represents the runtime status of a vMCP server.

type Tool

type Tool struct {
	// Name is the tool name (may conflict with other backends).
	Name string

	// Description describes what the tool does.
	Description string

	// InputSchema is the JSON Schema for tool parameters.
	InputSchema map[string]any

	// OutputSchema is the JSON Schema for tool output (optional).
	// Per MCP specification, this describes the structure of the tool's response.
	OutputSchema map[string]any

	// BackendID identifies the backend that provides this tool.
	BackendID string
}

Tool represents an MCP tool capability.

type ToolCallResult added in v0.8.1

type ToolCallResult struct {
	// Content is the tool output (text, image, etc.)
	// This is the array of content items returned by the backend.
	Content []Content

	// StructuredContent is structured output (preferred for composite tools and workflows).
	// If the backend MCP server provides StructuredContent, it is used directly.
	// Otherwise, this is populated by converting the Content array to a map:
	//   - First text item: key="text"
	//   - Additional text items: key="text_1", "text_2", etc.
	//   - Image items: key="image_0", "image_1", etc.
	// This allows templates to access fields via {{.steps.stepID.output.text}}.
	// Note: No JSON parsing is performed - backends must provide structured data explicitly.
	StructuredContent map[string]any

	// IsError indicates if the tool call failed.
	IsError bool

	// Meta contains protocol-level metadata from the backend (_meta field).
	// This includes progressToken, trace context, and custom backend metadata.
	// Per MCP specification, this field is optional and may be nil.
	Meta map[string]any
}

ToolCallResult wraps a tool call response with metadata. This preserves both the tool output AND the _meta field from the backend MCP server.

Directories

Path Synopsis
Package aggregator provides capability aggregation for Virtual MCP Server.
Package aggregator provides capability aggregation for Virtual MCP Server.
mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
Package auth provides authentication for Virtual MCP Server.
Package auth provides authentication for Virtual MCP Server.
converters
Package converters provides functions to convert external authentication configurations to typed vMCP BackendAuthStrategy configurations.
Package converters provides functions to convert external authentication configurations to typed vMCP BackendAuthStrategy configurations.
factory
Package factory provides factory functions for creating vMCP authentication components.
Package factory provides factory functions for creating vMCP authentication components.
mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
strategies
Package strategies provides authentication strategy implementations for Virtual MCP Server.
Package strategies provides authentication strategy implementations for Virtual MCP Server.
types
Package types provides shared auth-related types for Virtual MCP Server.
Package types provides shared auth-related types for Virtual MCP Server.
Package cache provides token caching interfaces for Virtual MCP Server.
Package cache provides token caching interfaces for Virtual MCP Server.
Package client provides MCP protocol client implementation for communicating with backend servers.
Package client provides MCP protocol client implementation for communicating with backend servers.
mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
Package composer provides composite tool workflow execution for Virtual MCP Server.
Package composer provides composite tool workflow execution for Virtual MCP Server.
mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
Package config provides configuration types and validation for VirtualMCP.
Package config provides configuration types and validation for VirtualMCP.
Package conversion provides utilities for converting between MCP SDK types and vmcp wrapper types.
Package conversion provides utilities for converting between MCP SDK types and vmcp wrapper types.
Package discovery provides lazy per-user capability discovery for vMCP servers.
Package discovery provides lazy per-user capability discovery for vMCP servers.
mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
Package health provides health monitoring for vMCP backend MCP servers.
Package health provides health monitoring for vMCP backend MCP servers.
Package k8s provides Kubernetes integration for Virtual MCP Server dynamic mode.
Package k8s provides Kubernetes integration for Virtual MCP Server dynamic mode.
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
Package optimizer provides the Optimizer interface for intelligent tool discovery and invocation in the Virtual MCP Server.
Package optimizer provides the Optimizer interface for intelligent tool discovery and invocation in the Virtual MCP Server.
Package router provides request routing for Virtual MCP Server.
Package router provides request routing for Virtual MCP Server.
mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
Package schema provides typed JSON Schema structures for type coercion and defaults.
Package schema provides typed JSON Schema structures for type coercion and defaults.
Package server implements the Virtual MCP Server that aggregates multiple backend MCP servers into a unified interface.
Package server implements the Virtual MCP Server that aggregates multiple backend MCP servers into a unified interface.
adapter
Package adapter provides a layer between aggregator and SDK.
Package adapter provides a layer between aggregator and SDK.
adapter/mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
Package session provides vMCP-specific session types that extend transport sessions with domain logic.
Package session provides vMCP-specific session types that extend transport sessions with domain logic.
Package status provides the StatusReporter interface for vMCP.
Package status provides the StatusReporter interface for vMCP.
Package workloads provides the WorkloadDiscoverer interface for discovering backend workloads in both CLI and Kubernetes environments.
Package workloads provides the WorkloadDiscoverer interface for discovering backend workloads in both CLI and Kubernetes environments.
mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.

Jump to

Keyboard shortcuts

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