launcher

package
v0.33.2 Latest Latest
Warning

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

Go to latest
Published: May 24, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package launcher manages locally-spawned upstream processes that expose their MCP endpoint over HTTP / SSE / streamable-HTTP transports.

Stdio upstreams already spawn a child process — that's how the protocol works. HTTP/SSE upstreams have historically required the user to start the process themselves before mcpproxy connected. The launcher decouples "how to start the process" from "how to talk to it", so the same {command, args, env, working_dir, docker isolation} configuration that stdio servers use can also drive an HTTP/SSE server's lifecycle.

This file owns URL-readiness probing. See launcher.go for spawn/stop.

Index

Constants

View Source
const DefaultStopGrace = 5 * time.Second

DefaultStopGrace is the time we wait between SIGTERM and SIGKILL when stopping a launched child. Tunable via Handle.SetStopGrace if a particular upstream needs longer (e.g. a Docker container with a slow shutdown hook). Five seconds is a common default for "graceful" in this codebase (see processGracefulTimeout in internal/upstream/core).

Variables

This section is empty.

Functions

func WaitForURL

func WaitForURL(ctx context.Context, rawURL string, timeout time.Duration) error

WaitForURL blocks until rawURL's host:port accepts a TCP connection, or until the context is canceled or timeout elapses (whichever comes first).

The check is deliberately a TCP dial, not an HTTP GET. SSE endpoints serve a streaming response that never closes; an HTTP GET against one will either hang or return a non-2xx status the moment the server's stream handler is hit, neither of which actually proves "the listener is up". TCP-dial just proves the bind happened, which is what we need before handing off to the transport-level connect.

timeout=0 means "use no overall deadline beyond ctx.Done()". Negative timeouts are coerced to 0 to keep callers from accidentally producing an already-expired deadline.

Types

type Handle

type Handle interface {
	// Stop signals the child to exit (SIGTERM → grace → SIGKILL on
	// timeout). Blocks until the child is reaped or ctx fires. Calling
	// Stop more than once is safe — subsequent calls return the result
	// of the first.
	Stop(ctx context.Context) error

	// Wait blocks until the child exits. Returns the exit error from
	// exec.Cmd.Wait() (nil on clean exit, *exec.ExitError on non-zero).
	Wait() error

	// Done is closed when the child has exited for any reason. Useful
	// for select{}-driven supervision.
	Done() <-chan struct{}

	// Pid returns the OS process id, or 0 if the child has exited.
	Pid() int
}

Handle represents a running child managed by the launcher. Stop, Wait, and Done are safe to call from multiple goroutines.

func Spawn

func Spawn(ctx context.Context, spec *Spec, log *zap.Logger) (Handle, error)

Spawn starts spec.Cmd and returns a Handle owning its lifecycle.

stdout+stderr are line-buffered into spec.LogSink (or discarded if nil). On Unix, the child is placed in its own process group so Stop can signal the entire group, not just the immediate child — this matters when the command shells out (e.g. `sh -c 'docker run …'`) and the actual server is a grandchild.

The supplied ctx is NOT used to bound the child's runtime — once Spawn returns, the child outlives ctx. ctx is only used to abort cmd.Start() itself if it's slow (rare). Callers who want ctx-tied lifetime should call Stop from a goroutine watching ctx.Done().

type Spec

type Spec struct {
	// Cmd is the command to start. The launcher will set Stdout/Stderr
	// pipes and call cmd.Start(). Callers MUST NOT have started cmd
	// already; calling Start again is undefined.
	Cmd *exec.Cmd

	// LogSink receives the child's combined stdout+stderr, line by line.
	// May be nil to discard output (tests).
	LogSink io.Writer

	// Name is used in log messages to identify which upstream's launcher
	// is doing the talking. Optional; defaults to cmd.Path basename.
	Name string

	// StopGrace overrides DefaultStopGrace if non-zero.
	StopGrace time.Duration
}

Spec describes the command to launch.

Spec is intentionally narrow: it doesn't replicate the full ServerConfig surface — the caller is responsible for assembling the final exec.Cmd (env, working dir, Docker shell-wrap, process-group attrs). The launcher only owns the lifecycle once Cmd is started.

Jump to

Keyboard shortcuts

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