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 ¶
var ErrNoSuchInstance = errors.New("no such source instance")
Errors that callers care about by identity.
Functions ¶
func SplitWireName ¶
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.
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 ¶
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 ¶
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.
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.