sources

package
v0.22.170 Latest Latest
Warning

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

Go to latest
Published: May 26, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package sources spawns configured source MCP servers as child processes and proxies tools/list + tools/call between them and clawtool's own MCP server. Per ADR-006 each child's tools are exposed as `<instance>__<tool>` so multi-instance setups (two GitHubs etc.) cannot collide. Per ADR-007 we wrap mark3labs/mcp-go's client rather than reimplement MCP transport.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoSuchInstance = errors.New("no such source instance")

Errors that callers care about by identity.

Functions

func SplitWireName

func SplitWireName(wire string) (instance, tool string, ok bool)

SplitWireName parses a `<instance>__<tool>` selector back into its parts. Used by callers that already received an aggregated tool name and need to route. Per ADR-006 the separator is two underscores and instance names don't contain underscores.

Types

type HealthReport

type HealthReport struct {
	Name      string
	Status    Status
	Reason    string
	ToolCount int
	Package   string // best-effort: command[1] when command[0] is a runner
}

HealthReport is a snapshot used by future surface (`clawtool source list --runtime`). Each row carries enough info to print the same way every time without exposing implementation internals.

type Instance

type Instance struct {
	Name      string         // kebab-case instance name (selector form)
	Spec      Spec           // immutable spawn spec
	Client    *client.Client // nil when status != Running
	Tools     []mcp.Tool     // snapshot from ListTools at start
	StartedAt time.Time
	// contains filtered or unexported fields
}

Instance is one spawned source MCP server.

Lifetime model:

  • Created via Manager.startInstance(); Initialize + ListTools cache the advertised tool surface.
  • Concurrent CallTool calls are mediated by mark3labs/mcp-go's client which is itself goroutine-safe over a single stdio transport.
  • Stop closes the client which kills the child process.

func (*Instance) Status

func (i *Instance) Status() (Status, string)

Status returns the current lifecycle state along with any non-empty reason string explaining a non-Running state.

type Manager

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

Manager owns the lifecycle of all configured source instances and routes tools/call invocations between clawtool's own MCP server and the right child. Created from a Config + Secrets pair; started once; stopped on clawtool shutdown.

func NewManager

func NewManager(cfg config.Config, sec *secrets.Store) *Manager

NewManager builds an empty manager from config + secrets. No processes are spawned until Start is called.

func (*Manager) AggregatedTools

func (m *Manager) AggregatedTools() []SourceTool

AggregatedTools returns one SourceTool per (running instance × tool) combination. Names are wire-form `<instance>__<tool>` per ADR-006. The handler closes over (instance, original tool name) and routes the call.

Tools from instances in non-Running state are silently omitted; the list is the source of truth for what clawtool advertises *now*.

func (*Manager) Health

func (m *Manager) Health() []HealthReport

Health returns sorted-by-name HealthReport snapshots for every managed instance. Safe to call from any goroutine; takes a read lock.

func (*Manager) Start

func (m *Manager) Start(ctx context.Context) error

Start spawns every configured source concurrently. A failure on one instance does NOT abort the whole manager — others keep going. The combined error (if any) is returned for caller logging; callers may proceed regardless because per-instance failures are also recorded for the `source list` surface.

Concurrency rationale: pre-2026-05 Start serialised every spawn, so a single slow source (cua's first uvx resolve pulling torch + transformers + gradio, hundreds of MB) blocked every other source's handshake for up to 60 s. Spawning in parallel goroutines means the daemon's tool surface goes live as each source becomes ready, instead of holding hostage on the slowest one. The 60 s initialize timeout still bounds the worst case per-instance; the parallel approach just stops one bad apple from spoiling the whole batch.

Synchronisation: each goroutine writes its instance into m.instances + records its error under m.mu. The outer Lock is held for the duration so callers can't observe a partial map state — Start returns only after every spawn (success or failure) has completed.

func (*Manager) Stop

func (m *Manager) Stop()

Stop reaps every instance. Idempotent.

type SourceTool

type SourceTool struct {
	Tool    mcp.Tool
	Handler server.ToolHandlerFunc
}

SourceTool pairs a wire-form tool with its routing handler so that the caller can register both with the parent MCP server in one shot.

type Spec

type Spec struct {
	Command []string          // argv, command[0] is the binary
	Env     map[string]string // resolved env (already merged with required_env)
}

Spec is the resolved spawn input for one source. The config + secrets layers produce this; the manager consumes it.

type Status

type Status string

Status is the lifecycle state of a single source instance.

const (
	StatusStarting        Status = "starting"
	StatusRunning         Status = "running"
	StatusDown            Status = "down"
	StatusUnauthenticated Status = "unauthenticated"
)

Jump to

Keyboard shortcuts

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