toolcat

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package toolcat is the tool catalog + MCP broker. Two layers of "tool": the capabilities the agent SEES (typed, schema'd, role-scoped entries here) and the binaries that BACK them (in-image CLIs, sidecar services, external MCP servers). The catalog is the declarative source of truth for "what exists"; the broker (broker.go) is the single gated endpoint the agent talks to — list/describe for runtime discovery, route + output-cap + role-scope on invoke. Every entry is PINNED (content-addressed) so the provisioned set is reproducible and a replay re-provisions byte-identically (evidence log).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CatalogHash

func CatalogHash(tools []Tool) string

CatalogHash is a single digest over the pinned set — a compact replay key.

func Hashes

func Hashes(tools []Tool) []string

Hashes returns the sorted pinned references of the given tools — the set to record in provenance (artifact.Provenance.ToolHashes) so a replay re-provisions the identical tools.

Types

type AgentTool

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

func (AgentTool) Description

func (a AgentTool) Description() string

func (AgentTool) Invoke

func (a AgentTool) Invoke(ctx context.Context, args json.RawMessage) (string, error)

func (AgentTool) Name

func (a AgentTool) Name() string

func (AgentTool) Schema

func (a AgentTool) Schema() json.RawMessage

type Broker

type Broker struct {
	Tools          []Tool // already role-scoped
	Exec           Execer // for in-image CLIs
	MCP            MCPCaller
	DefaultTimeout time.Duration // default 60s
	DefaultCap     int           // default 64 KiB
	// contains filtered or unexported fields
}

Broker is the single gated endpoint the agent talks to. It surfaces the role-scoped catalog (list/describe), routes each call to its backend, and enforces per-tool timeouts + output caps. It is deliberately synchronous request/response to match the agent's tool-call loop; the async execution_id job model (for long tools like fuzzers) layers on top later.

func NewBroker

func NewBroker(tools []Tool, exec Execer, mcp MCPCaller) *Broker

NewBroker builds a broker over a role-scoped tool set.

func (*Broker) AgentTools

func (b *Broker) AgentTools() []AgentTool

AgentTools returns broker tools adapted to the agent Tool shape.

func (*Broker) Describe

func (b *Broker) Describe(id string) (Tool, bool)

Describe is `describe_tool`.

func (*Broker) Invoke

func (b *Broker) Invoke(ctx context.Context, id string, args json.RawMessage) (string, error)

Invoke routes a call to its backend with the tool's (or default) timeout and output cap. Unknown id → error surfaced to the agent (not a panic).

func (*Broker) List

func (b *Broker) List() []Tool

List is the runtime-discovery surface (`list_tools`).

type Catalog

type Catalog struct {
	Tools []Tool `yaml:"tools"`
}

Catalog is the loaded set of recipes.

func Load

func Load(path string) (Catalog, error)

Load reads + validates a catalog YAML.

func (Catalog) ForRole

func (c Catalog) ForRole(role string) []Tool

ForRole returns the tools scoped to a role (empty Roles ⇒ all roles). role == "" returns every tool (no filtering).

func (Catalog) Validate

func (c Catalog) Validate() error

Validate enforces the catalog invariants: unique ids, a known kind, a present backend, and — critically — that every tool is PINNED (an unpinned tool can drift and breaks replay, so it is refused, like the sandbox image).

type Execer

type Execer interface {
	Exec(ctx context.Context, cmd string, args []string, stdin string, timeout time.Duration) (stdout, stderr string, exit int, err error)
}

Execer runs an in-image CLI. The agent's Workspace satisfies it (adapted in the loop), so an in-image tool inherits the SAME execution boundary as the agent's exec — inside the container sandbox when one is configured (item 4).

type Kind

type Kind string

Kind is how a tool is backed.

const (
	InImage     Kind = "in-image"     // a CLI present in the (pinned) agent image
	Sidecar     Kind = "sidecar"      // a long-running service (Ghidra/angr) — reached via MCP
	ExternalMCP Kind = "external-mcp" // an external MCP server launched on demand
)

type MCPCaller

type MCPCaller interface {
	CallTool(ctx context.Context, command []string, tool string, args json.RawMessage, timeout time.Duration) (string, error)
}

MCPCaller invokes a named tool on an external MCP backend (stdio server argv + tool name + JSON args → text result). internal/mcp satisfies it. Optional: a nil caller means external-mcp/sidecar tools are advertised-but-unavailable.

type Tool

type Tool struct {
	ID          string   `yaml:"id"`
	Kind        Kind     `yaml:"kind"`
	Description string   `yaml:"description"`
	Schema      string   `yaml:"schema"`     // MCP input JSON-Schema (raw JSON string)
	Cmd         string   `yaml:"cmd"`        // in-image: program to run
	FixedArgs   []string `yaml:"fixed_args"` // in-image: args prepended before the agent's args
	Command     []string `yaml:"command"`    // external-mcp: server launch argv (stdio transport)
	MCPTool     string   `yaml:"mcp_tool"`   // external-mcp/sidecar: the server-side tool name (default = ID)
	Roles       []string `yaml:"roles"`      // role scope; empty ⇒ available to all roles
	Pin         string   `yaml:"pin"`        // REQUIRED content/digest pin (…@sha256:… / sha256:… / cas:…)
	TimeoutS    int      `yaml:"timeout_s"`  // per-call timeout (0 → broker default)
	OutputCap   int      `yaml:"output_cap"` // max bytes of captured output (0 → broker default)
}

Tool is one declarative catalog recipe.

Jump to

Keyboard shortcuts

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