Documentation
¶
Overview ¶
Package tools is the ONE tool plane for Hanzo Cloud: a single registry where every callable capability — a connector action, a user function, a zap service route, a cloud /v1 control ("full-cloud-control"), an agent, a skill, or a tool on an org's own external MCP server — is a Tool with a Source, a JSON-Schema, a per-(org,project) activation state, and an optional price.
Decomplected on the Rich Hickey seam: a Source knows how to LIST its tools and DISPATCH one; the registry knows nothing about how any single source works. Each source REGISTERS a Provider into the registry from its own Mount — no source duplicates listing or dispatch logic, and the registry never grows a per-source branch. Adding a source is: implement Provider, call tools.Register.
Every dispatch flows through ONE per-principal plane: the caller's VALIDATED org (principal.Org) gates the call, the tool must be ACTIVATED for that (org,project) or the call is 403, a priced tool settles through the explicit x402 Charger seam, and the platform meters one unit. The same isolation boundary the connectors MCP endpoint (clients/automations) already ships — generalized across every source.
Index ¶
- Variables
- func Mount(app cloud.Router, deps cloud.Deps) error
- func Register(p Provider)
- func SetCharger(c Charger)
- func SetPricer(p Pricer)
- func Shutdown(_ context.Context) error
- type ActivationStore
- func (s *ActivationStore) Activate(ctx context.Context, org, project, tool string, source Source, byUser string) error
- func (s *ActivationStore) Close() error
- func (s *ActivationStore) Deactivate(ctx context.Context, org, project, tool string) error
- func (s *ActivationStore) IsActivated(ctx context.Context, org, project, tool string) bool
- func (s *ActivationStore) List(ctx context.Context, org, project string) ([]string, error)
- type Charge
- type Charger
- type MCPServer
- type MCPServerStore
- func (s *MCPServerStore) Close() error
- func (s *MCPServerStore) Create(ctx context.Context, srv MCPServer) (MCPServer, error)
- func (s *MCPServerStore) Delete(ctx context.Context, org, id string) (bool, error)
- func (s *MCPServerStore) Get(ctx context.Context, org, id string) (MCPServer, error)
- func (s *MCPServerStore) List(ctx context.Context, org string) ([]MCPServer, error)
- type Price
- type Pricer
- type Principal
- type Provider
- type Registry
- func (r *Registry) Activate(ctx context.Context, org, project, tool, byUser string) error
- func (r *Registry) Activated(ctx context.Context, org, project string) ([]string, error)
- func (r *Registry) Deactivate(ctx context.Context, org, project, tool string) error
- func (r *Registry) Dispatch(ctx context.Context, p Principal, name string, args map[string]any) (any, error)
- func (r *Registry) Exists(ctx context.Context, scope Scope, name string) bool
- func (r *Registry) List(ctx context.Context, scope Scope) []Tool
- func (r *Registry) Register(p Provider)
- func (r *Registry) SetActivation(a *ActivationStore)
- func (r *Registry) SetCharger(c Charger)
- func (r *Registry) SetPricer(p Pricer)
- type Scope
- type Source
- type Tool
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNotActivated — the tool exists for the scope but is not activated for this // (org,project). The activation API (task 5) toggles it on. ErrNotActivated = errors.New("tools: not activated for this org/project") // ErrUnknownTool — no source offers a tool by this name for the scope. ErrUnknownTool = errors.New("tools: unknown tool") // ErrNotDispatchable — the tool is discovery/activation-only (e.g. a skill). ErrNotDispatchable = errors.New("tools: not dispatchable") // ErrPaymentRequired — a priced tool could not be settled through the Charger. ErrPaymentRequired = errors.New("tools: payment required") // ErrChargerUnset — a priced tool was called but no x402 Charger is wired; the // call fails CLOSED (a paid tool is never served free). ErrChargerUnset = errors.New("tools: payment seam not configured") )
Sentinel dispatch outcomes. The HTTP layer maps these to status codes: a not-activated tool is 403 (the tool plane never serves an unactivated tool), an unknown tool is 404-in-JSON-RPC, payment-required is 402, not-dispatchable is 422.
Functions ¶
func Register ¶
func Register(p Provider)
Register adds a source Provider to the process-wide registry. Each source calls this ONCE from its Mount (only enabled subsystems mount, so a disabled source is simply absent). Order does not matter: List/Dispatch run at request time.
func SetCharger ¶
func SetCharger(c Charger)
SetCharger installs the x402 payment seam on the process-wide registry. The x402 wiring team calls this once; until it does, priced tools fail closed.
Types ¶
type ActivationStore ¶
type ActivationStore struct {
// contains filtered or unexported fields
}
ActivationStore is the per-(org,project,tool) activation plane: the durable toggle hanzo.chat / hanzo.app read to decide which skills/plugins/connectors an org has turned on. It is the tool-plane twin of the entitlements (org,product) enablement store — a row exists iff the tool is EXPLICITLY activated for that scope, and dispatch fails closed (403) on any tool without one.
Isolation is the (org, project, tool) composite key plus a mandatory `WHERE org=? AND project=?` on every statement. org/project are the VALIDATED principal values, never client input. One SQLite file (all orgs, org column), MaxOpenConns(1), WAL — the shared cloud store discipline.
func OpenActivationStore ¶
func OpenActivationStore(path string) (*ActivationStore, error)
OpenActivationStore opens (and migrates) the activation store at path.
func (*ActivationStore) Activate ¶
func (s *ActivationStore) Activate(ctx context.Context, org, project, tool string, source Source, byUser string) error
Activate turns a tool on for (org, project). Idempotent on the composite key. source + byUser are recorded for the audit/console view.
func (*ActivationStore) Close ¶
func (s *ActivationStore) Close() error
Close closes the underlying database.
func (*ActivationStore) Deactivate ¶
func (s *ActivationStore) Deactivate(ctx context.Context, org, project, tool string) error
Deactivate turns a tool off for (org, project). Idempotent (no row ⇒ no-op).
func (*ActivationStore) IsActivated ¶
func (s *ActivationStore) IsActivated(ctx context.Context, org, project, tool string) bool
IsActivated reports whether tool is activated for (org, project). It is nil-safe: a nil store (pre-Mount / split deploy) reports NOT activated, so dispatch fails closed rather than serving an unactivated tool.
type Charge ¶
type Charge struct {
Payer string // paying org's billing ledger (principal Owner/Org).
Project string
Tool string
Recipient string // seller payout wallet (Tool.Price.Recipient).
Currency string
Cents int64
RequestID string
}
Charge is one settlement request for a monetized tool call. It is the whole contract the registry hands the x402 seam: who pays, who is paid, how much.
type Charger ¶
Charger settles a monetized tool call over the x402 payment rail (LP-3028, clients/commerce/payment/x402). A SEPARATE team owns the concrete implementation backed by x402.Facilitator.Settle (Payee = the recipient wallet address); the registry codes to THIS narrow interface and keeps the seam explicit so it never pulls the processor/MPC/chain graph into the tool plane. A nil Charger makes every priced tool fail closed (ErrChargerUnset) — a paid tool is never free.
Charge returns nil on a settled payment, ErrPaymentRequired when the payer cannot pay, or another error (fail-closed) on an unavailable rail.
type MCPServer ¶
type MCPServer struct {
ID string `json:"id"`
Org string `json:"org"`
Name string `json:"name"`
URL string `json:"url"`
AuthHeader string `json:"authHeader,omitempty"` // header to inject the KMS secret into (e.g. "Authorization").
HasSecret bool `json:"hasSecret"`
CreatedAt int64 `json:"createdAt"`
}
MCPServer is one org-registered external MCP server. AuthHeader/HasSecret record how to authenticate; the secret itself is in KMS at authRef(org, id).
type MCPServerStore ¶
type MCPServerStore struct {
// contains filtered or unexported fields
}
MCPServerStore is the per-org registry of external MCP servers (one SQLite file, org column, the shared cloud store discipline). Isolation is a mandatory `WHERE org=?` on every statement; org is the validated principal value.
func OpenMCPServerStore ¶
func OpenMCPServerStore(path string) (*MCPServerStore, error)
OpenMCPServerStore opens (and migrates) the external-server store at path.
func (*MCPServerStore) Close ¶
func (s *MCPServerStore) Close() error
Close closes the underlying database.
func (*MCPServerStore) Create ¶
Create inserts a server row (id generated). It does NOT touch KMS — the handler stores the secret first, then records has_secret here.
func (*MCPServerStore) Delete ¶
Delete removes a server for (org, id). Returns whether a row was removed.
type Price ¶
type Price struct {
AmountCents int64 `json:"amountCents"`
Currency string `json:"currency"` // ISO 4217, e.g. "USD"; empty ⇒ "USD".
Recipient string `json:"recipient"` // payout wallet ref for the marketplace seller.
}
Price declares what a monetized tool call costs and who is paid. Enforcement is the x402 Charger seam (registry.go) — this is only the DECLARATION a marketplace listing carries. A nil Price means the tool is free (no x402 settlement).
type Pricer ¶
Pricer resolves the marketplace price of a tool at dispatch time. It is the seam the marketplace fills so a monetized listing's price + recipient wallet reach the per-call enforcement path WITHOUT the tool plane importing the marketplace. A tool whose provider already set an intrinsic Price does not consult the Pricer.
type Principal ¶
type Principal struct {
Org string
Project string
User string
Owner string
IsAdmin bool
// contains filtered or unexported fields
}
Principal is the VALIDATED caller a dispatch runs as — resolved once from the request and threaded to every source. Org/Project/User/Owner/IsAdmin are the IAM-native identity; credential is the caller's OWN credential headers, replayed by a builtin tool so a /v1 route runs under the SAME IAM check as a direct HTTP call (cloud's SanitizeIdentity strips minted headers on ingress and re-mints them ONLY from a re-validated credential, so replaying the credential — never the minted headers — is the one way an in-process call carries the caller's identity; this is exactly the zapface in-process-dispatch contract).
func PrincipalFrom ¶
PrincipalFrom resolves the validated caller from a request context. It returns ok=false (the caller must answer 403) unless a validated principal carries a non-empty org — the SAME gate principal.Org enforces. Because c.User() is set ONLY from a re-validated credential, a successful resolve guarantees a replayable credential is present; it is captured so a builtin tool can act as this exact caller and never escalate.
type Provider ¶
type Provider interface {
// Source is the provider's source tag (a provider serves exactly one source).
Source() Source
// List returns the tools this source offers for scope. It is scope-aware:
// a connector source lists an org's connected connectors; the external-MCP
// source lists tools from the org's registered servers; builtin lists routes.
List(ctx context.Context, scope Scope) ([]Tool, error)
// Dispatch invokes the named tool with JSON args, bound to the principal, and
// returns the JSON-encodable result. A source that only lists (skills) returns
// ErrNotDispatchable.
Dispatch(ctx context.Context, p Principal, name string, args map[string]any) (any, error)
}
Provider is one tool SOURCE. It lists the tools it offers to a (org,project) and dispatches a call to one of them bound to the principal. The registry composes providers; it never learns how any single source lists or runs its tools. A source implements this once and calls Register — that is the whole contract.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry is THE tool plane: the set of registered source Providers, the shared per-(org,project) activation store, and the x402 Charger seam. It composes providers and enforces the ONE dispatch policy (activation gate → price gate → dispatch); it knows nothing about how any source lists or runs a tool.
func Default ¶
func Default() *Registry
Default returns the process-wide registry (for marketplace + the HTTP surface).
func NewRegistry ¶
func NewRegistry() *Registry
NewRegistry builds an empty registry. The process-wide one is std (see Default); tests build their own with fake providers.
func (*Registry) Activate ¶
Activate turns a tool on for (org, project), recording its resolved source. This is the ONE activation write the marketplace "install" and the /v1/tools/activation API both drive, so activation is one store reached one way.
func (*Registry) Deactivate ¶
Deactivate turns a tool off for (org, project).
func (*Registry) Dispatch ¶
func (r *Registry) Dispatch(ctx context.Context, p Principal, name string, args map[string]any) (any, error)
Dispatch is the ONE per-principal dispatch path, enforcing the ONE policy:
- resolve the winning tool (precedence) — ErrUnknownTool if none.
- ACTIVATION gate — the tool MUST be activated for (org,project) or ErrNotActivated (403).
- PRICE gate — a priced tool settles through the x402 Charger seam or fails closed (ErrChargerUnset / ErrPaymentRequired). A paid tool is never free.
- dispatch to the winning source's provider, bound to the principal.
The scope is the principal's own (org, project) — a caller can only ever dispatch its own tools. Metering + audit are the HTTP layer's job (one unit per call).
func (*Registry) Exists ¶
Exists reports whether any source offers a tool by name to scope. Used by the marketplace to refuse a phantom listing/install.
func (*Registry) List ¶
List returns every tool offered to scope, deduped by name under source precedence (the lowest-rank source wins a collision), sorted by name. Each tool's Activated flag is filled from the activation store. A provider that errors is skipped (its tools are simply absent) — one failing source never blanks the whole plane.
func (*Registry) Register ¶
Register adds a provider. Duplicate sources are allowed (each lists its own tools); precedence resolves any name collision across sources.
func (*Registry) SetActivation ¶
func (r *Registry) SetActivation(a *ActivationStore)
SetActivation installs the activation store (called by tools.Mount once DataDir is known). A nil store fails every dispatch closed (nothing is activated).
func (*Registry) SetCharger ¶
SetCharger installs the payment seam.
type Scope ¶
Scope is the (org, project) a listing is resolved for. project == "" or the literal default project both denote the org's default scope.
type Source ¶
type Source string
Source names WHERE a tool comes from. It is the ONE dimension precedence and activation-default policy key on, so it is a closed set of values, not free text.
const ( // SourceBuiltin is a cloud /v1 route exposed as a tool ("full-cloud-control"): // a per-user token does over MCP exactly what that user may do over HTTP, gated // by the SAME IAM check because dispatch replays the request in-process. SourceBuiltin Source = "builtin" // SourceConnector is a connector action from clients/automations. SourceConnector Source = "connector" // SourceFunction is a user-defined function from clients/functions. SourceFunction Source = "function" // SourceZAPService is a zap-proto service route (tunneled over /zap). SourceZAPService Source = "zap-service" // SourceAgent is an org agent from clients/agents, callable as a tool. SourceAgent Source = "agent" // SourceSkill is an agent skill (clients/agentskills): discovery + activation // metadata, attached to agents rather than called directly. SourceSkill Source = "skill" // SourceMCP is a tool on an org's own registered EXTERNAL MCP server. SourceMCP Source = "mcp" )
type Tool ¶
type Tool struct {
Name string `json:"name"`
Source Source `json:"source"`
Description string `json:"description"`
Schema json.RawMessage `json:"inputSchema,omitempty"`
Price *Price `json:"price,omitempty"`
Dispatchable bool `json:"dispatchable"`
// Activated is filled by the registry from the activation store for the
// requesting (org,project); providers leave it zero.
Activated bool `json:"activated"`
}
Tool is the ONE description of a callable capability, uniform across sources. Schema is the JSON-Schema of the call arguments (MCP inputSchema); Dispatchable is false for a listing-only entry (a skill is activated + attached, not called).