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:
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" ...
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" ...
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 ¶
- func ExtractBearerToken(authHeader string) string
- type Clock
- type HTTPServer
- func (s *HTTPServer) AddDynamicTool(toolConfig ToolConfig)
- func (s *HTTPServer) Endpoint() string
- func (s *HTTPServer) GetError() error
- func (s *HTTPServer) IsRunning() bool
- func (s *HTTPServer) Port() int
- func (s *HTTPServer) RemoveDynamicTool(toolName string)
- func (s *HTTPServer) Start(ctx context.Context) (int, error)
- func (s *HTTPServer) StartOnPort(ctx context.Context, port int) error
- func (s *HTTPServer) Stop(ctx context.Context) error
- func (s *HTTPServer) Transport() HTTPTransportType
- func (s *HTTPServer) WaitForReady(ctx context.Context) error
- type HTTPTransportType
- type MCPServerConfig
- type MockClock
- type OAuthErrorSimulation
- type OAuthServer
- func (s *OAuthServer) AddToken(accessToken, refreshToken, scope, clientID string, expiresAt time.Time)
- func (s *OAuthServer) GenerateAuthCode(...) string
- func (s *OAuthServer) GenerateAuthCodeWithSubject(...) string
- func (s *OAuthServer) GenerateTestToken(clientID, scope string) *TokenResponse
- func (s *OAuthServer) GetAuthorizeURL() string
- func (s *OAuthServer) GetCACertPEM() []byte
- func (s *OAuthServer) GetClientID() string
- func (s *OAuthServer) GetClock() Clock
- func (s *OAuthServer) GetIssuerURL() string
- func (s *OAuthServer) GetMetadataURL() string
- func (s *OAuthServer) GetPendingAuthCode(state string) string
- func (s *OAuthServer) GetScopes() []string
- func (s *OAuthServer) GetTokenInfo(accessToken string) *issuedToken
- func (s *OAuthServer) GetTokenURL() string
- func (s *OAuthServer) IsRunning() bool
- func (s *OAuthServer) IsTLS() bool
- func (s *OAuthServer) Port() int
- func (s *OAuthServer) RevokeAllTokens() int
- func (s *OAuthServer) RevokeToken(accessToken string) bool
- func (s *OAuthServer) SetClock(clock Clock)
- func (s *OAuthServer) SetTrustedIssuers(trustedIssuers map[string]string)
- func (s *OAuthServer) SimulateCallback(code string) (*TokenResponse, error)
- func (s *OAuthServer) Start(ctx context.Context) (int, error)
- func (s *OAuthServer) Stop(ctx context.Context) error
- func (s *OAuthServer) ValidateToken(accessToken string) bool
- func (s *OAuthServer) WWWAuthenticateHeader() string
- func (s *OAuthServer) WaitForReady(ctx context.Context) error
- type OAuthServerConfig
- type PreConfiguration
- type ProtectedMCPServer
- func (s *ProtectedMCPServer) AddDynamicTool(toolConfig ToolConfig)
- func (s *ProtectedMCPServer) Endpoint() string
- func (s *ProtectedMCPServer) GetIssuer() string
- func (s *ProtectedMCPServer) GetName() string
- func (s *ProtectedMCPServer) IsRunning() bool
- func (s *ProtectedMCPServer) Port() int
- func (s *ProtectedMCPServer) RemoveDynamicTool(toolName string)
- func (s *ProtectedMCPServer) Start(ctx context.Context) (int, error)
- func (s *ProtectedMCPServer) Stop(ctx context.Context) error
- func (s *ProtectedMCPServer) WaitForReady(ctx context.Context) error
- type ProtectedMCPServerConfig
- type RealClock
- type Server
- type TestScenario
- type TokenResponse
- type ToolConfig
- type ToolHandler
- type ToolResponse
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExtractBearerToken ¶
ExtractBearerToken extracts a bearer token from an Authorization header
Types ¶
type Clock ¶
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) AddDynamicTool ¶ added in v0.1.62
func (s *HTTPServer) AddDynamicTool(toolConfig ToolConfig)
AddDynamicTool adds a tool to the running mock server at runtime. This triggers a notifications/tools/list_changed notification to connected clients.
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) RemoveDynamicTool ¶ added in v0.1.62
func (s *HTTPServer) RemoveDynamicTool(toolName string)
RemoveDynamicTool removes a tool from the running mock server at runtime. This triggers a notifications/tools/list_changed notification to connected clients.
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 ¶
NewMockClock creates a new mock clock initialized to the given time. If t is zero, the clock is initialized to the current 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, nonce string) string
GenerateAuthCode generates an authorization code for testing This simulates a user completing the OAuth flow
func (*OAuthServer) GenerateAuthCodeWithSubject ¶ added in v0.1.50
func (s *OAuthServer) GenerateAuthCodeWithSubject(clientID, redirectURI, scope, state, codeChallenge, codeChallengeMethod, subject, nonce string) string
GenerateAuthCodeWithSubject generates an authorization code with a custom subject claim. If subject is empty, the default "test-user-123" is used. The nonce, when non-empty, is echoed back in the issued id_token to satisfy OIDC nonce-echo verification.
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) AddDynamicTool ¶ added in v0.1.62
func (s *ProtectedMCPServer) AddDynamicTool(toolConfig ToolConfig)
AddDynamicTool adds a tool to the running protected MCP server at runtime. This triggers a notifications/tools/list_changed notification to connected clients.
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) RemoveDynamicTool ¶ added in v0.1.62
func (s *ProtectedMCPServer) RemoveDynamicTool(toolName string)
RemoveDynamicTool removes a tool from the running protected MCP server at runtime. This triggers a notifications/tools/list_changed notification to connected clients.
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 Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server represents a mock MCP server for testing
func NewServerFromFile ¶
NewServerFromFile creates a new mock MCP server from a configuration file
func (*Server) AddDynamicTool ¶ added in v0.1.62
func (s *Server) AddDynamicTool(toolConfig ToolConfig)
AddDynamicTool adds a tool to the running MCP server at runtime. The mcp-go library automatically sends a notifications/tools/list_changed notification to all connected clients.
func (*Server) RemoveDynamicTool ¶ added in v0.1.62
RemoveDynamicTool removes a tool from the running MCP server at runtime. The mcp-go library automatically sends a notifications/tools/list_changed notification to all connected clients.
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) 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