Documentation
¶
Overview ¶
Package mockmcp is a minimal MCP test fixture. It exposes a small set of tools (echo, add_numbers, get_time) over the streamable-HTTP transport, optionally with TLS, so end-to-end tests have a non-trivial MCP server to point at without depending on a real upstream.
The library is designed for two usage shapes:
- As an in-process fixture from Go tests: construct via NewServer, call Start to begin serving and obtain the base URL, defer Stop.
- As a standalone binary spawned as a subprocess: see the cmd/mockmcp entrypoint, which wires the same Options from flags.
Transport is plaintext HTTP unless both Options.CertPath and Options.KeyPath are set, in which case the server serves HTTPS with the operator-supplied cert. Asymmetric configuration (one set, the other empty) is rejected by NewServer.
Index ¶
- Constants
- Variables
- func HeaderLoggingMiddleware(next http.Handler, logger *log.Logger) http.Handler
- func NewSelfSignedCertsForTest(hosts ...string) (caPEM, certPEM, keyPEM []byte, err error)
- func RegisterDefaultTools(server *mcp.Server)
- type AddNumbersParams
- type EchoParams
- type GetTimeParams
- type Options
- type RecordedRequest
- type Server
Constants ¶
const ( // DefaultAddr is the listen address used when Options.Addr is empty. DefaultAddr = ":13443" // MCPPath is the fixed URL path the streamable-HTTP handler binds // under. Not configurable — /mcp is the MCP convention and no real- // world test needs a different path. MCPPath = "/mcp" // SSEPath is the fixed URL path the SSE handler binds under. Not // configurable for the same reason as MCPPath. SSEPath = "/sse" )
const ServerIDHeader = "Mockmcp-Server-Id"
ServerIDHeader is the response header populated when Options.ServerID is non-empty. Tests running multiple fixture instances disambiguate which one handled a given request by reading this header.
Variables ¶
var ErrAlreadyStarted = errors.New("mockmcp: server already started")
ErrAlreadyStarted is returned by Server.Start when called more than once.
Functions ¶
func HeaderLoggingMiddleware ¶
HeaderLoggingMiddleware wraps the given handler with a logger that prints every inbound request's headers in sorted order with values verbatim. Each request produces one multi-line log entry so test runs have deterministic, grep-able output.
Test-only. Values are logged unredacted; do not enable in any setup that could see real credentials.
func NewSelfSignedCertsForTest ¶
NewSelfSignedCertsForTest mints a self-signed CA, a leaf certificate signed by that CA, and the leaf's private key — all PEM-encoded — using only the Go standard library. The leaf is suitable for an HTTPS server whose clients verify against the returned CA.
hosts are SANs embedded in the leaf certificate. Inputs that parse as IP literals (e.g. "127.0.0.1", "::1") land in IPAddresses; the rest land in DNSNames. At least one host is required.
The helper is deliberately parameter-free beyond hosts and uses fixed cryptographic choices (ECDSA P-256, SHA-256, ~1y validity, 1h backdating to tolerate small verifier clock skew). Callers that need different parameters should mint their own certificates with crypto/x509 directly.
Test-only. Do not embed the output into production code paths.
func RegisterDefaultTools ¶
RegisterDefaultTools attaches mockmcp's default tool set (echo, add_numbers, get_time) to the supplied MCP server. Exposed so embedders can compose the default set with their own tools on a server they own.
Types ¶
type AddNumbersParams ¶
type AddNumbersParams struct {
A float64 `json:"a" jsonschema:"the first number"`
B float64 `json:"b" jsonschema:"the second number"`
}
AddNumbersParams is the input schema for the "add_numbers" tool.
type EchoParams ¶
type EchoParams struct {
Message string `json:"message" jsonschema:"the message to echo back"`
}
EchoParams is the input schema for the "echo" tool.
type GetTimeParams ¶
type GetTimeParams struct {
Timezone string `json:"timezone,omitempty" jsonschema:"IANA timezone (e.g. UTC, America/New_York); defaults to UTC"`
}
GetTimeParams is the input schema for the "get_time" tool.
type Options ¶
type Options struct {
// Addr is the TCP address to listen on (e.g. ":13443" or "127.0.0.1:0").
// Empty defaults to DefaultAddr. Use ":0" to bind a random free port;
// the actual address is reflected in the base URL returned by Start.
Addr string
// CertPath and KeyPath enable HTTPS when both are set. Asymmetric
// configuration is rejected by NewServer so an operator who omits one
// by mistake gets a fast failure instead of a silent fall-through to
// plaintext.
CertPath string
KeyPath string
// CertPEM and KeyPEM enable HTTPS via in-memory PEM-encoded certificate
// material. Like CertPath/KeyPath they must be set together. CertPEM
// may contain a leaf followed by intermediates; tls.X509KeyPair
// validates the chain. Mutually exclusive with CertPath/KeyPath —
// NewServer rejects a configuration that mixes file-based and
// in-memory cert input.
CertPEM []byte
KeyPEM []byte
// LogHeaders enables a middleware that logs every inbound request's
// headers in sorted order with values verbatim. Test-only — leave off
// in any setup that could see real credentials.
LogHeaders bool
// RecordRequests, when true, installs a middleware that captures the
// method, path, headers, and body of every inbound request into an
// internal slice. Test code reads the snapshot via Server.Requests().
// Opt-in because body capture has a per-request memory cost.
RecordRequests bool
// ServerID, when non-empty, is echoed on every response as the
// `Mockmcp-Server-Id` header (see ServerIDHeader). Useful when a test
// runs multiple fixture instances and needs to distinguish them. Empty
// leaves the header off.
ServerID string
// Logger receives header logs and startup messages. Nil falls back to
// the standard logger.
Logger *log.Logger
}
Options configures a Server.
type RecordedRequest ¶
type RecordedRequest struct {
Method string
Path string
Headers http.Header
Body []byte
ReceivedAt time.Time
}
RecordedRequest is a snapshot of an inbound HTTP request captured by the request recorder. Tests use these snapshots to make positive assertions about traffic the fixture served — "did the controller's ListTools call arrive?", "did this request carry the expected header?" — without grepping log output.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the running fixture. Zero value is not usable; construct with NewServer.
func NewServer ¶
NewServer validates options and constructs a Server. Returns an error when cert/key fields are set asymmetrically, when file-based and in-memory cert input are mixed, or when Path and SSEPath collide.
func (*Server) Addr ¶
Addr returns the actual listener address. Useful when Options.Addr was ":0" and the caller needs to discover the chosen port. Returns nil if Start has not yet succeeded.
func (*Server) Requests ¶
func (s *Server) Requests() []RecordedRequest
Requests returns a snapshot of the requests captured since the server started. Returns nil when Options.RecordRequests was false.
func (*Server) Start ¶
Start binds the listener, registers the default tool set, and begins serving in a background goroutine. Returns the base URL clients should dial (e.g. "http://127.0.0.1:13443"). Subsequent calls return ErrAlreadyStarted.
The ctx parameter is accepted for API symmetry with related fixtures (notably mockllm); the server itself runs until Stop is called.