mock

package
v0.1.40 Latest Latest
Warning

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

Go to latest
Published: Mar 12, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

Documentation

Overview

Package mock provides mock MCP server functionality for testing muster components.

This package contains the implementation of mock MCP servers that can be used in test scenarios to simulate external MCP servers with predefined behaviors.

The mock MCP server functionality allows test scenarios to define: - Mock tools with configurable responses - Conditional responses based on input args - Simulated delays and error conditions - Template-based response generation - OAuth 2.1 authentication flows for testing protected servers

Key Components

Server: The main mock MCP server that implements the MCP protocol. It can be configured with a set of tools and their expected behaviors. By default, it uses stdio transport for subprocess communication.

HTTPServer: Wraps a mock MCP server with HTTP transport capabilities. Supports both SSE (Server-Sent Events) and Streamable HTTP transports. Use this for testing URL-based MCP server configurations.

OAuthServer: A mock OAuth 2.1 authorization server for testing OAuth flows. Supports authorization code flow with PKCE, token exchange, refresh tokens, and configurable error simulation. Use this for testing OAuth-protected MCP servers without requiring a real identity provider.

ProtectedMCPServer: An MCP server that requires OAuth authentication. It validates bearer tokens against a mock OAuth server and returns 401 with WWW-Authenticate headers when authentication is required. Tools are only accessible after successful authentication.

ToolHandler: Handles individual tool calls with configurable responses based on input args and conditions.

ToolConfig & ToolResponse: Configuration structures that define how mock tools should behave, including input schemas, response conditions, and template-based response generation.

Supported Transports

The mock package supports three transport types:

  • stdio: Standard input/output for subprocess communication (default)
  • streamable-http: HTTP-based streaming protocol
  • sse: Server-Sent Events protocol

Usage

Mock MCP servers can be used in three ways:

  1. Embedded stdio mock in test scenarios: The test framework automatically starts stdio mock MCP servers based on scenario pre-configuration that includes MCP servers with "tools" in config:

    pre_configuration: mcp_servers: - name: "my-mock" config: tools: - name: "my_tool" ...

  2. Embedded HTTP mock in test scenarios: For URL-based transports, add a "type" field to the config:

    pre_configuration: mcp_servers: - name: "my-http-mock" config: type: "streamable-http" # or "sse" tools: - name: "my_tool" ...

  3. Standalone mock server mode: Use `muster test --mock-mcp-server --mock-config=path/to/config.yaml` to run a standalone mock MCP server for manual testing or external integration.

Configuration Format

Mock MCP servers are configured using YAML files that define the tools and their expected behaviors:

tools:
  - name: example-tool
    description: "An example mock tool"
    input_schema:
      type: object
      properties:
        param1:
          type: string
          default: "default-value"
    responses:
      - condition:
          param1: "special"
        response: "Special response for param1=special"
      - response: "Default response: {{.param1}}"

The responses support Go template syntax and can reference input args. Conditional responses allow different behaviors based on input values.

OAuth Testing

For testing OAuth-protected MCP servers, the package provides a complete mock OAuth 2.1 infrastructure. Configure OAuth in test scenarios as follows:

pre_configuration:
  mock_oauth_servers:
    - name: "test-idp"
      scopes: ["openid", "profile", "mcp:read"]
      auto_approve: true
      pkce_required: true
      token_lifetime: "1h"

  mcp_servers:
    - name: "protected-api"
      config:
        type: "streamable-http"
        oauth:
          required: true
          mock_oauth_server_ref: "test-idp"
          scope: "mcp:read"
        tools:
          - name: "secure_tool"
            description: "A tool requiring authentication"
            responses:
              - response: { "status": "authenticated" }

The mock OAuth server automatically: - Serves OAuth 2.1 metadata at /.well-known/oauth-authorization-server - Handles authorization code flow with PKCE support - Issues and validates access tokens - Returns WWW-Authenticate headers for unauthorized requests

Integration

This package is designed to work seamlessly with the muster testing framework and supports the same MCP protocol implementation used by real MCP servers. The HTTPServer automatically allocates ports and provides endpoint URLs for muster to connect to during test scenario execution. OAuth servers are automatically started and stopped as part of the test scenario lifecycle.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExtractBearerToken

func ExtractBearerToken(authHeader string) string

ExtractBearerToken extracts a bearer token from an Authorization header

Types

type Clock

type Clock interface {
	// Now returns the current time according to this clock
	Now() time.Time
}

Clock provides an interface for time operations to enable testing without relying on real time. This allows tests to simulate token expiry without waiting for actual time to pass.

type HTTPServer

type HTTPServer struct {
	// contains filtered or unexported fields
}

HTTPServer wraps a mock MCP server with HTTP transport capabilities. It can serve either SSE or streamable-http transport types.

func NewHTTPServer

func NewHTTPServer(mockServer *Server, transport HTTPTransportType, debug bool) *HTTPServer

NewHTTPServer creates a new HTTP mock server from an existing mock server

func NewHTTPServerFromConfig

func NewHTTPServerFromConfig(configPath string, transport HTTPTransportType, debug bool) (*HTTPServer, error)

NewHTTPServerFromConfig creates a new HTTP mock server from a config file

func (*HTTPServer) Endpoint

func (s *HTTPServer) Endpoint() string

Endpoint returns the full endpoint URL for the server

func (*HTTPServer) GetError

func (s *HTTPServer) GetError() error

GetError returns any error that occurred during server operation

func (*HTTPServer) IsRunning

func (s *HTTPServer) IsRunning() bool

IsRunning returns whether the server is currently running

func (*HTTPServer) Port

func (s *HTTPServer) Port() int

Port returns the port the server is listening on

func (*HTTPServer) Start

func (s *HTTPServer) Start(ctx context.Context) (int, error)

Start starts the HTTP server on a dynamically allocated port. Returns the port number the server is listening on.

func (*HTTPServer) StartOnPort

func (s *HTTPServer) StartOnPort(ctx context.Context, port int) error

StartOnPort starts the HTTP server on a specific port. This is useful when you need to control the port (e.g., for deterministic testing).

func (*HTTPServer) Stop

func (s *HTTPServer) Stop(ctx context.Context) error

Stop gracefully shuts down the HTTP server

func (*HTTPServer) Transport

func (s *HTTPServer) Transport() HTTPTransportType

Transport returns the transport type used by the server

func (*HTTPServer) WaitForReady

func (s *HTTPServer) WaitForReady(ctx context.Context) error

WaitForReady waits for the server to be ready to accept connections

type HTTPTransportType

type HTTPTransportType string

HTTPTransportType represents the type of HTTP transport for mock servers

const (
	// HTTPTransportStreamableHTTP uses streamable HTTP protocol
	HTTPTransportStreamableHTTP HTTPTransportType = "streamable-http"
	// HTTPTransportSSE uses Server-Sent Events protocol
	HTTPTransportSSE HTTPTransportType = "sse"
)

type MCPServerConfig

type MCPServerConfig struct {
	Name   string                 `yaml:"name"`
	Config map[string]interface{} `yaml:"config"`
}

MCPServerConfig is a minimal copy needed for the mock server

type MockClock

type MockClock struct {
	// contains filtered or unexported fields
}

MockClock implements Clock with a controllable time value. This enables testing time-sensitive operations like token expiry without waiting for real time to pass.

func NewMockClock

func NewMockClock(t time.Time) *MockClock

NewMockClock creates a new mock clock initialized to the given time. If t is zero, the clock is initialized to the current time.

func (*MockClock) Add

func (m *MockClock) Add(d time.Duration)

Add is an alias for Advance for API familiarity.

func (*MockClock) Advance

func (m *MockClock) Advance(d time.Duration)

Advance moves the clock forward by the given duration.

func (*MockClock) Now

func (m *MockClock) Now() time.Time

Now returns the current time according to this mock clock.

func (*MockClock) Set

func (m *MockClock) Set(t time.Time)

Set sets the clock to a specific time.

type OAuthErrorSimulation

type OAuthErrorSimulation struct {
	// TokenEndpointError returns this error from /token
	TokenEndpointError string

	// AuthorizeEndpointDelay adds delay to /authorize
	AuthorizeEndpointDelay time.Duration

	// InvalidGrant rejects all token exchanges
	InvalidGrant bool

	// InvalidToken rejects all token validations
	InvalidToken bool
}

OAuthErrorSimulation allows simulating error conditions

type OAuthServer

type OAuthServer struct {
	// contains filtered or unexported fields
}

OAuthServer is a mock OAuth 2.1 authorization server

func NewOAuthServer

func NewOAuthServer(config OAuthServerConfig) *OAuthServer

NewOAuthServer creates a new mock OAuth server

func (*OAuthServer) AddToken

func (s *OAuthServer) AddToken(accessToken, refreshToken, scope, clientID string, expiresAt time.Time)

AddToken directly adds a token to the server (for testing)

func (*OAuthServer) GenerateAuthCode

func (s *OAuthServer) GenerateAuthCode(clientID, redirectURI, scope, state, codeChallenge, codeChallengeMethod string) string

GenerateAuthCode generates an authorization code for testing This simulates a user completing the OAuth flow

func (*OAuthServer) GenerateTestToken

func (s *OAuthServer) GenerateTestToken(clientID, scope string) *TokenResponse

GenerateTestToken generates a test access token directly without going through the OAuth flow. This is useful for testing scenarios where the test framework needs to authenticate with muster's OAuth server without implementing the full browser-based OAuth flow.

func (*OAuthServer) GetAuthorizeURL

func (s *OAuthServer) GetAuthorizeURL() string

GetAuthorizeURL returns the authorization endpoint URL

func (*OAuthServer) GetCACertPEM

func (s *OAuthServer) GetCACertPEM() []byte

GetCACertPEM returns the PEM-encoded CA certificate for TLS mode. This can be used by clients to trust the self-signed certificate. Returns nil if the server is not running in TLS mode.

func (*OAuthServer) GetClientID

func (s *OAuthServer) GetClientID() string

GetClientID returns the configured client ID

func (*OAuthServer) GetClock

func (s *OAuthServer) GetClock() Clock

GetClock returns the clock used by this server

func (*OAuthServer) GetIssuerURL

func (s *OAuthServer) GetIssuerURL() string

GetIssuerURL returns the full issuer URL

func (*OAuthServer) GetMetadataURL

func (s *OAuthServer) GetMetadataURL() string

GetMetadataURL returns the OAuth metadata URL

func (*OAuthServer) GetPendingAuthCode

func (s *OAuthServer) GetPendingAuthCode(state string) string

GetPendingAuthCode returns a pending auth code if one exists for the given state

func (*OAuthServer) GetScopes

func (s *OAuthServer) GetScopes() []string

GetScopes returns the accepted scopes for this OAuth server

func (*OAuthServer) GetTokenInfo

func (s *OAuthServer) GetTokenInfo(accessToken string) *issuedToken

GetTokenInfo returns information about a token

func (*OAuthServer) GetTokenURL

func (s *OAuthServer) GetTokenURL() string

GetTokenURL returns the token endpoint URL

func (*OAuthServer) IsRunning

func (s *OAuthServer) IsRunning() bool

IsRunning returns whether the server is currently running

func (*OAuthServer) IsTLS

func (s *OAuthServer) IsTLS() bool

IsTLS returns whether the server is running in TLS mode.

func (*OAuthServer) Port

func (s *OAuthServer) Port() int

Port returns the port the server is listening on

func (*OAuthServer) RevokeAllTokens

func (s *OAuthServer) RevokeAllTokens() int

RevokeAllTokens removes all tokens from the server. This is used for testing scenarios where all tokens need to be invalidated. Returns the number of tokens that were revoked.

func (*OAuthServer) RevokeToken

func (s *OAuthServer) RevokeToken(accessToken string) bool

RevokeToken removes a token from the server, making it invalid for future requests. This is used for testing scenarios where a token is revoked server-side but the client still has the token cached locally. Returns true if the token was found and revoked, false if the token didn't exist.

func (*OAuthServer) SetClock

func (s *OAuthServer) SetClock(clock Clock)

SetClock sets the clock used by this server (primarily for testing)

func (*OAuthServer) SetTrustedIssuers

func (s *OAuthServer) SetTrustedIssuers(trustedIssuers map[string]string)

SetTrustedIssuers sets the trusted issuers for RFC 8693 token exchange. This should be called after all OAuth servers are started, so their issuer URLs are known.

func (*OAuthServer) SimulateCallback

func (s *OAuthServer) SimulateCallback(code string) (*TokenResponse, error)

SimulateCallback simulates a user completing OAuth flow This is called by tests to complete authentication without a real browser

func (*OAuthServer) Start

func (s *OAuthServer) Start(ctx context.Context) (int, error)

Start starts the OAuth server on a random available port

func (*OAuthServer) Stop

func (s *OAuthServer) Stop(ctx context.Context) error

Stop stops the OAuth server

func (*OAuthServer) ValidateToken

func (s *OAuthServer) ValidateToken(accessToken string) bool

ValidateToken checks if a token is valid

func (*OAuthServer) WWWAuthenticateHeader

func (s *OAuthServer) WWWAuthenticateHeader() string

WWWAuthenticateHeader returns the WWW-Authenticate header value for this server

func (*OAuthServer) WaitForReady

func (s *OAuthServer) WaitForReady(ctx context.Context) error

WaitForReady waits for the OAuth server to be ready

type OAuthServerConfig

type OAuthServerConfig struct {
	// Issuer is the OAuth issuer identifier (e.g., "http://localhost:9999")
	Issuer string

	// AcceptedScopes lists scopes the server will accept
	AcceptedScopes []string

	// TokenLifetime is how long tokens remain valid
	TokenLifetime time.Duration

	// SimulateErrors can be set to simulate various error conditions
	SimulateErrors *OAuthErrorSimulation

	// Debug enables debug logging
	Debug bool

	// PKCERequired enforces PKCE flow
	PKCERequired bool

	// AutoApprove skips user consent in tests
	AutoApprove bool

	// ClientID is the expected OAuth client ID
	ClientID string

	// ClientSecret is the expected OAuth client secret (optional)
	ClientSecret string

	// Clock is the clock to use for time operations (defaults to RealClock)
	// Set this to a MockClock for testing token expiry without waiting
	Clock Clock

	// UseTLS enables HTTPS mode with a self-signed certificate.
	// This is required for testing muster's OAuth server integration,
	// as the Dex provider enforces HTTPS for security.
	UseTLS bool

	// TrustedIssuers maps connector IDs to trusted issuer URLs for RFC 8693 token exchange.
	// When a token exchange request is received with a connector_id, this map is used
	// to look up the trusted issuer and validate the subject token.
	// Key: connector_id, Value: issuer URL
	TrustedIssuers map[string]string
}

OAuthServerConfig configures the mock OAuth server behavior

type PreConfiguration

type PreConfiguration struct {
	MCPServers []MCPServerConfig `yaml:"mcp_servers,omitempty"`
}

PreConfiguration is a minimal copy needed for the mock server

type ProtectedMCPServer

type ProtectedMCPServer struct {
	// contains filtered or unexported fields
}

ProtectedMCPServer is a mock MCP server that requires OAuth authentication

func NewProtectedMCPServer

func NewProtectedMCPServer(config ProtectedMCPServerConfig) (*ProtectedMCPServer, error)

NewProtectedMCPServer creates a new OAuth-protected mock MCP server

func (*ProtectedMCPServer) Endpoint

func (s *ProtectedMCPServer) Endpoint() string

Endpoint returns the MCP endpoint URL

func (*ProtectedMCPServer) GetIssuer

func (s *ProtectedMCPServer) GetIssuer() string

GetIssuer returns the OAuth issuer for this server

func (*ProtectedMCPServer) GetName

func (s *ProtectedMCPServer) GetName() string

GetName returns the server name

func (*ProtectedMCPServer) IsRunning

func (s *ProtectedMCPServer) IsRunning() bool

IsRunning returns whether the server is currently running

func (*ProtectedMCPServer) Port

func (s *ProtectedMCPServer) Port() int

Port returns the port the server is listening on

func (*ProtectedMCPServer) Start

func (s *ProtectedMCPServer) Start(ctx context.Context) (int, error)

Start starts the protected MCP server on a random available port

func (*ProtectedMCPServer) Stop

func (s *ProtectedMCPServer) Stop(ctx context.Context) error

Stop stops the protected MCP server

func (*ProtectedMCPServer) WaitForReady

func (s *ProtectedMCPServer) WaitForReady(ctx context.Context) error

WaitForReady waits for the server to be ready to accept connections

type ProtectedMCPServerConfig

type ProtectedMCPServerConfig struct {
	// Name is the name of this MCP server
	Name string

	// OAuthServer is the mock OAuth server to validate tokens against
	OAuthServer *OAuthServer

	// Issuer is the expected token issuer (used for WWW-Authenticate header)
	Issuer string

	// RequiredScope is the OAuth scope required to access this server
	RequiredScope string

	// Tools are the tools to expose when authenticated
	Tools []ToolConfig

	// Transport is the HTTP transport type (sse or streamable-http)
	Transport HTTPTransportType

	// Debug enables debug logging
	Debug bool
}

ProtectedMCPServerConfig configures an OAuth-protected mock MCP server

type RealClock

type RealClock struct{}

RealClock implements Clock using the actual system time.

func (RealClock) Now

func (RealClock) Now() time.Time

Now returns the current time.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server represents a mock MCP server for testing

func NewServerFromFile

func NewServerFromFile(configPath string, debug bool) (*Server, error)

NewServerFromFile creates a new mock MCP server from a configuration file

func (*Server) Start

func (s *Server) Start(ctx context.Context) error

Start starts the mock MCP server using stdio transport

type TestScenario

type TestScenario struct {
	PreConfiguration *PreConfiguration `yaml:"pre_configuration,omitempty"`
}

TestScenario is needed for loadServerConfig function - importing from parent would cause circular dependency This is a minimal copy of the required fields

type TokenResponse

type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token,omitempty"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int    `json:"expires_in"`
	Scope        string `json:"scope,omitempty"`
	IDToken      string `json:"id_token,omitempty"`
}

TokenResponse is the OAuth token response

type ToolConfig

type ToolConfig struct {
	// Name is the unique identifier for the tool
	Name string `yaml:"name"`
	// Description describes what the tool does
	Description string `yaml:"description"`
	// InputSchema defines the expected input schema (JSON Schema)
	InputSchema map[string]interface{} `yaml:"input_schema"`
	// Responses defines possible responses for this tool
	Responses []ToolResponse `yaml:"responses"`
}

ToolConfig defines configuration for a mock tool

type ToolHandler

type ToolHandler struct {
	// contains filtered or unexported fields
}

ToolHandler handles mock tool calls with configurable responses

func NewToolHandler

func NewToolHandler(config ToolConfig, templateEngine *template.Engine, debug bool) *ToolHandler

NewToolHandler creates a new mock tool handler

func (*ToolHandler) GetDescription

func (h *ToolHandler) GetDescription() string

GetDescription returns the tool description

func (*ToolHandler) GetName

func (h *ToolHandler) GetName() string

GetName returns the tool name

func (*ToolHandler) HandleCall

func (h *ToolHandler) HandleCall(args map[string]interface{}) (interface{}, error)

HandleCall processes a tool call and returns the configured response

type ToolResponse

type ToolResponse struct {
	// Condition defines arg matching for this response (optional)
	// If empty, this response is used as a fallback
	Condition map[string]interface{} `yaml:"condition,omitempty"`
	// Response is the response data to return
	Response interface{} `yaml:"response,omitempty"`
	// Error is the error message to return instead of response
	Error string `yaml:"error,omitempty"`
	// Delay simulates response latency (e.g., "2s", "500ms")
	Delay string `yaml:"delay,omitempty"`
}

ToolResponse defines a conditional response for a mock tool

Jump to

Keyboard shortcuts

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