plugin

package
v0.1.7 Latest Latest
Warning

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

Go to latest
Published: May 5, 2026 License: GPL-3.0 Imports: 32 Imported by: 0

Documentation

Overview

Package plugin implements plugin process management, discovery, lifecycle, and the bidirectional JSON-lines transport.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ValidatePluginName added in v0.1.5

func ValidatePluginName(name string) error

ValidatePluginName checks whether name matches the plugin name pattern. Returns an error if the name is invalid.

Types

type AuthServiceConfig

type AuthServiceConfig struct {
	Type string `yaml:"type"`
	// Token holds a bearer token (type=bearer) or refresh/offline
	// token (type=refresh_token). Typically set via env var: "${MY_TOKEN}".
	Token           string                       `yaml:"token"`
	Header          string                       `yaml:"header"`
	Prefix          string                       `yaml:"prefix"`
	Username        string                       `yaml:"username"`
	Password        string                       `yaml:"password"`
	SPN             string                       `yaml:"spn"`
	SPNEGOProactive *bool                        `yaml:"spnego_proactive"`
	Scopes          []string                     `yaml:"scopes"`
	CredentialsFile string                       `yaml:"credentials_file"`
	TokenFile       string                       `yaml:"token_file"`
	TokenURL        string                       `yaml:"token_url"`
	ClientID        string                       `yaml:"client_id"`
	Select          string                       `yaml:"select"`
	Variants        map[string]AuthServiceConfig `yaml:"variants"`
	VariantOrder    []string                     `yaml:"-"` // populated from YAML key order
}

AuthServiceConfig declares auth requirements.

type CacheServiceConfig

type CacheServiceConfig struct {
	Enabled    *bool  `yaml:"enabled"`
	Namespace  string `yaml:"namespace"`
	DefaultTTL int    `yaml:"default_ttl"`
}

CacheServiceConfig declares cache settings.

type CallToolResult added in v0.1.5

type CallToolResult struct {
	Result  json.RawMessage
	Actions []protocol.Action
}

CallToolResult holds the result of a tool call along with any actions.

type CompiledSchema added in v0.1.7

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

CompiledSchema wraps a compiled JSON Schema for parameter validation.

func CompileParamsSchema added in v0.1.7

func CompileParamsSchema(toolName string, toolDef ToolDef) (*CompiledSchema, error)

CompileParamsSchema compiles a tool's parameter schema for validation. Returns nil schema (no validation) if the schema has no properties. Returns an error if the schema is malformed or oversized, causing the caller to disable the tool.

func (*CompiledSchema) Validate added in v0.1.7

func (cs *CompiledSchema) Validate(params json.RawMessage) error

Validate checks params against the compiled schema. Returns nil if valid.

type CredentialMeta

type CredentialMeta struct {
	Description  string `yaml:"description"`
	Example      string `yaml:"example"`
	HelpURL      string `yaml:"help_url"`
	Instructions string `yaml:"instructions"`
	Secret       bool   `yaml:"secret"`
}

CredentialMeta describes how to obtain a credential value.

type DisabledPlugin added in v0.1.4

type DisabledPlugin struct {
	Name     string
	Reason   string
	Manifest *Manifest
}

DisabledPlugin records a plugin that was discovered but could not be loaded due to a configuration issue (e.g., env.d file with bad permissions). Its tools are registered with [DISABLED] descriptions so the LLM can tell the user how to fix it.

type DiscoveryOptions added in v0.1.5

type DiscoveryOptions struct {
	ConfigPath          string // Optional config file path
	WorkdirOverride     string // Optional workdir override
	SkipConfigFiltering bool   // If true, ignore plugins.enabled and plugins.disabled during discovery
}

DiscoveryOptions configures plugin discovery behavior.

type DiscoveryResult added in v0.1.5

type DiscoveryResult struct {
	Workdir       string
	ConfigPath    string // Resolved config file path (for write-back)
	Config        *config.Config
	EnvDir        string // Resolved env.d directory path
	EnvGroups     map[string]map[string]string
	EnvErrors     map[string]string
	EnvDirError   string // env.d directory-level error, if any
	Manager       *Manager
	VaultResolver func(vaultID string) ([]byte, error)
}

DiscoveryResult contains the results of plugin discovery.

func Discover added in v0.1.5

func Discover(opts DiscoveryOptions) (*DiscoveryResult, error)

Discover performs plugin discovery without loading plugins. This is the common discovery logic used by CLI tools and the check command. For the main server runtime, use the full initialization in run().

type HTTPServiceConfig

type HTTPServiceConfig struct {
	BaseURL         string    `yaml:"base_url"`
	AllowedDomains  []string  `yaml:"allowed_domains"`
	AllowPrivateIPs bool      `yaml:"allow_private_ips"`
	TLS             TLSConfig `yaml:"tls"`
}

HTTPServiceConfig declares HTTP proxy settings.

type Handle

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

Handle wraps a plugin process and serializes tool calls based on the plugin's concurrency setting.

func NewHandle

func NewHandle(manifest *Manifest, handler ServiceHandler, cfg ProcessConfig, toolTimeout time.Duration, groupVars map[string]string) *Handle

NewHandle creates a Handle for dispatching tool calls to a plugin.

func (*Handle) AuthBindings added in v0.1.7

func (h *Handle) AuthBindings() map[string]string

AuthBindings returns per-domain auth bindings registered during plugin init. Keys are domain names, values are env var names.

func (*Handle) CallTool

func (h *Handle) CallTool(ctx context.Context, toolName string, params json.RawMessage) (*CallToolResult, error)

CallTool dispatches a tool call to the plugin. For persistent plugins, sends via the transport. For oneshot plugins, spawns a fresh process per call.

func (*Handle) InitDomains added in v0.1.7

func (h *Handle) InitDomains() []string

InitDomains returns dynamic domains registered during plugin init.

func (*Handle) InitialResources added in v0.1.5

func (h *Handle) InitialResources() []protocol.ResourceDef

InitialResources returns the cached resource list (thread-safe).

func (*Handle) IsReady added in v0.1.6

func (h *Handle) IsReady() bool

IsReady returns true if the handle can accept tool calls. Non-persistent (oneshot) plugins are always ready; persistent plugins are ready once Start has been called and succeeded.

func (*Handle) ListResources added in v0.1.5

func (h *Handle) ListResources(ctx context.Context) ([]protocol.ResourceDef, error)

ListResources queries the handler for its current resource list. Uses transport directly (not h.mu) to avoid deadlock with tool calls.

func (*Handle) ReadResource added in v0.1.5

func (h *Handle) ReadResource(ctx context.Context, uri string) (string, string, error)

ReadResource requests the content of a specific resource URI. Uses transport directly (not h.mu) to avoid deadlock with tool calls.

func (*Handle) SetResources added in v0.1.5

func (h *Handle) SetResources(resources []protocol.ResourceDef)

SetResources updates the cached resource list (thread-safe).

func (*Handle) SetSandbox added in v0.1.7

func (h *Handle) SetSandbox(sb *sandbox.Manager)

SetSandbox configures the sandbox manager for this handle's processes.

func (*Handle) Start

func (h *Handle) Start(ctx context.Context) error

Start launches the plugin process.

func (*Handle) Stop

func (h *Handle) Stop(ctx context.Context) error

Stop gracefully shuts down the plugin process.

type ItemsDef

type ItemsDef struct {
	Type string `yaml:"type"`
}

ItemsDef describes array item types.

type Manager

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

Manager discovers, loads, and manages plugin lifecycles.

func NewManager

func NewManager(authReg *auth.Registry, p *proxy.Proxy, c cache.Store, cfg *config.Config, envGroups config.EnvGroups, envErrors map[string]string, envDirError, workdir, envDir string, envLoadOpts config.EnvLoadOptions, sessionDir string) *Manager

NewManager creates a plugin manager. envErrors maps credential group names to their load errors (from LoadEnvGroups). Plugins whose credential_group appears in envErrors will be disabled during LoadAll instead of loaded. envDirError, if non-empty, indicates the env.d directory itself has a problem (bad permissions, stat failure) — all credential-dependent plugins will be disabled. envDir is the resolved env.d directory path used to re-read env files on plugin reload.

func NewManagerForTest added in v0.1.4

func NewManagerForTest() *Manager

NewManagerForTest creates a Manager with no dependencies for use in tests that need to populate manifests and handles directly.

func (*Manager) CallTool

func (m *Manager) CallTool(_ context.Context, toolName string) (string, *Handle)

CallTool dispatches a tool call to the appropriate plugin.

func (*Manager) ConfigDisabledPlugins added in v0.1.5

func (m *Manager) ConfigDisabledPlugins() map[string]*Manifest

ConfigDisabledPlugins returns plugins that were skipped during discovery because they are listed in plugins.disabled config.

func (*Manager) DisabledPlugins added in v0.1.4

func (m *Manager) DisabledPlugins() map[string]DisabledPlugin

DisabledPlugins returns a snapshot of plugins that were discovered but could not be loaded (e.g., bad env.d permissions, TLS/cert errors, missing dependencies, process start failures). Thread-safe.

func (*Manager) Discover

func (m *Manager) Discover(dirs []string, userDir string) error

Discover scans directories for plugin.yaml files and loads manifests. First directory wins for a given plugin name; duplicates in later directories are skipped with a warning. userDir, if non-empty, identifies the user plugins directory — plugins from it are restricted (e.g., cannot declare provides.auth).

func (*Manager) Handle added in v0.1.5

func (m *Manager) Handle(name string) *Handle

Handle returns the handle for a loaded plugin, or nil if not loaded.

func (*Manager) IsLoading added in v0.1.6

func (m *Manager) IsLoading() bool

IsLoading returns true if StartPending is still running.

func (*Manager) Load

func (m *Manager) Load(ctx context.Context, name string) error

Load starts a single plugin by name.

func (*Manager) LoadAll

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

LoadAll prepares all discovered plugins synchronously: resolves dependencies, loads auth providers, filters disabled plugins, and prepares handles (config, proxy, TLS). This is the fast phase.

After LoadAll returns, m.disabled is fully populated and all handles are prepared. Call StartPending to launch the plugin processes in the background (the slow phase).

func (*Manager) LoadedPlugins added in v0.1.4

func (m *Manager) LoadedPlugins() []string

LoadedPlugins returns the names of successfully loaded plugins.

func (*Manager) Manifests

func (m *Manager) Manifests() map[string]*Manifest

Manifests returns a snapshot of all discovered manifests.

func (*Manager) Reload

func (m *Manager) Reload(ctx context.Context, name string) error

Reload stops and restarts a plugin. Re-reads the env.d file to pick up any changes (e.g., new IPA_CA_CERT added by create_config). If the plugin was disabled due to an env.d error, enables it if the issue is resolved.

func (*Manager) SetDisabledPlugin added in v0.1.7

func (m *Manager) SetDisabledPlugin(name, reason string)

SetDisabledPlugin marks a plugin as disabled for testing.

func (*Manager) SetHandle added in v0.1.4

func (m *Manager) SetHandle(name string)

SetHandle marks a plugin as loaded by creating a placeholder handle.

func (*Manager) SetManifest added in v0.1.4

func (m *Manager) SetManifest(name string, manifest *Manifest)

SetManifest sets a manifest in the manager for testing.

func (*Manager) SetSandbox added in v0.1.7

func (m *Manager) SetSandbox(sb *sandbox.Manager)

SetSandbox configures the sandbox manager. When set, all plugin processes are launched in arapuca sandboxes. Must be called before LoadAll.

func (*Manager) ShutdownAll

func (m *Manager) ShutdownAll(ctx context.Context)

ShutdownAll stops all loaded plugins.

func (*Manager) StartPending added in v0.1.6

func (m *Manager) StartPending(ctx context.Context)

StartPending starts all prepared plugin processes by dependency level. This is the slow phase — each plugin spawns a subprocess and blocks on the init handshake (up to InitTimeout per plugin). Independent plugins within a level start in parallel.

Closes loadDone when complete. Safe to call from a goroutine.

func (*Manager) ToolOwner

func (m *Manager) ToolOwner(toolName string) string

ToolOwner returns the plugin name that owns a tool.

func (*Manager) Unload

func (m *Manager) Unload(ctx context.Context, name string) error

Unload stops a plugin. Removes the handle from the map before stopping the process so new tool calls are not dispatched to a stopping plugin.

func (*Manager) WaitLoaded added in v0.1.6

func (m *Manager) WaitLoaded()

WaitLoaded blocks until StartPending completes.

type Manifest

type Manifest struct {
	Name        string `yaml:"name"`
	Version     string `yaml:"version"`
	Description string `yaml:"description"`

	Execution   string `yaml:"execution"`   // "oneshot" or "persistent"
	Concurrency int    `yaml:"concurrency"` // default: 1
	Handler     string `yaml:"handler"`

	DependsOn       []string `yaml:"depends_on"`
	CredentialGroup string   `yaml:"credential_group"` // scopes env.d access
	EnvPassthrough  string   `yaml:"env_passthrough"`  // "all" to pass all group vars
	Env             []string `yaml:"env"`              // env vars to pass from credential group

	Services ServiceConfig     `yaml:"services"`
	Provides ProvidesConfig    `yaml:"provides"`
	Config   map[string]string `yaml:"config"`

	Tools        []ToolDef `yaml:"tools"`
	ContextFiles []string  `yaml:"context_files"`
	Priority     int       `yaml:"priority"`
	Enabled      *bool     `yaml:"enabled"`

	Output OutputConfig `yaml:"output"`
	Setup  SetupConfig  `yaml:"setup"`

	// Dir is the directory containing this manifest (set at load time).
	Dir string `yaml:"-"`
	// contains filtered or unexported fields
}

Manifest holds plugin metadata loaded from plugin.yaml.

func LoadManifest

func LoadManifest(path string) (*Manifest, error)

LoadManifest reads and validates a plugin.yaml file.

func (*Manifest) CacheEnabled

func (m *Manifest) CacheEnabled() bool

CacheEnabled returns whether cache is enabled (defaults to true).

func (*Manifest) CacheNamespace

func (m *Manifest) CacheNamespace() string

CacheNamespace returns the cache namespace (defaults to plugin name).

func (*Manifest) HandlerPath

func (m *Manifest) HandlerPath() string

HandlerPath returns the absolute path to the handler executable.

func (*Manifest) IsEnabled

func (m *Manifest) IsEnabled() bool

IsEnabled returns whether the plugin is enabled (defaults to true).

func (*Manifest) ProvidesAuth

func (m *Manifest) ProvidesAuth() bool

ProvidesAuth returns true if this plugin provides an auth type.

func (*Manifest) ProvidesResources added in v0.1.5

func (m *Manifest) ProvidesResources() bool

ProvidesResources returns true if the plugin provides dynamic resources.

func (*Manifest) SetResolvedConfig

func (m *Manifest) SetResolvedConfig(cfg json.RawMessage)

SetResolvedConfig sets the resolved config JSON for the plugin.

func (*Manifest) Validate

func (m *Manifest) Validate() error

Validate checks the manifest for correctness.

type OutputConfig

type OutputConfig struct {
	Format string `yaml:"format"`
}

OutputConfig allows per-plugin output format override.

type ParamDef

type ParamDef struct {
	Type        string    `yaml:"type"`
	Description string    `yaml:"description"`
	Required    bool      `yaml:"required"`
	Default     any       `yaml:"default"`
	Items       *ItemsDef `yaml:"items"`
}

ParamDef describes a tool parameter.

type Process

type Process struct {
	Transport *Transport

	Resources    []protocol.ResourceDef // resources discovered at init
	Domains      []string               // dynamic domains from init_ok
	AuthBindings map[string]string      // per-domain auth bindings from init_ok
	// contains filtered or unexported fields
}

Process manages a plugin handler's OS process and transport.

func NewProcess

func NewProcess(manifest *Manifest, handler ServiceHandler, cfg ProcessConfig, groupVars map[string]string) *Process

NewProcess creates a Process for the given manifest. groupVars are the scoped env.d variables for this plugin's credential_group.

func (*Process) SetSandbox added in v0.1.7

func (p *Process) SetSandbox(sb *sandbox.Manager)

SetSandbox configures the sandbox manager for this process. When set and enabled, Start() launches via arapuca instead of exec.CommandContext.

func (*Process) Start

func (p *Process) Start(ctx context.Context) error

Start launches the plugin handler process and sends init for persistent plugins.

func (*Process) State

func (p *Process) State() State

State returns the current process state.

func (*Process) Stop

func (p *Process) Stop(ctx context.Context) error

Stop gracefully shuts down the plugin process.

type ProcessConfig

type ProcessConfig struct {
	InitTimeout       time.Duration
	ShutdownTimeout   time.Duration
	ShutdownKillAfter time.Duration
	MaxMessageSize    int
}

ProcessConfig holds process management settings.

type ProvidesAuthConfig

type ProvidesAuthConfig struct {
	Type        string `yaml:"type"`
	Description string `yaml:"description"`
}

ProvidesAuthConfig describes a plugin-provided auth type.

type ProvidesConfig

type ProvidesConfig struct {
	Auth      *ProvidesAuthConfig `yaml:"auth"`
	Resources bool                `yaml:"resources"`
}

ProvidesConfig declares what services a plugin provides.

type ServiceConfig

type ServiceConfig struct {
	Auth  AuthServiceConfig  `yaml:"auth"`
	HTTP  HTTPServiceConfig  `yaml:"http"`
	Cache CacheServiceConfig `yaml:"cache"`
}

ServiceConfig declares what services a plugin requires.

type ServiceHandler

type ServiceHandler interface {
	HandleHTTP(ctx context.Context, pluginName string, req protocol.Message) protocol.Message
	HandleCache(ctx context.Context, pluginName string, req protocol.Message) protocol.Message
}

ServiceHandler handles service requests from plugins. Implemented by the proxy and cache subsystems.

type SetupConfig

type SetupConfig struct {
	Credentials      map[string]CredentialMeta `yaml:"credentials"`
	Variants         map[string]SetupVariant   `yaml:"variants"`
	ValidationTool   string                    `yaml:"validation_tool"`
	PostSetupMessage string                    `yaml:"post_setup_message"`
}

SetupConfig holds human-facing metadata for configuration wizards. The core parses it but does not act on it — consumed by CLI tools.

type SetupVariant

type SetupVariant struct {
	Label       string   `yaml:"label"`
	Description string   `yaml:"description"`
	Required    []string `yaml:"required"`
}

SetupVariant adds human-facing labels to auth variants.

type State

type State int

State represents the plugin process lifecycle state.

const (
	StateUnloaded State = iota
	StateStarting
	StateRunning
	StateFailed
	StateStopping
)

Plugin process lifecycle states.

type TLSConfig added in v0.1.4

type TLSConfig struct {
	CACert             string `yaml:"ca_cert"`
	ClientCert         string `yaml:"client_cert"`
	ClientKey          string `yaml:"client_key"`
	SkipHostnameVerify bool   `yaml:"skip_hostname_verify"`

	// CACertPEM holds the pre-loaded CA cert bytes (set at load time,
	// not from YAML). Prevents TOCTOU between validation and use.
	CACertPEM []byte `yaml:"-"`
}

TLSConfig declares per-plugin TLS settings for custom CAs and mTLS.

type ToolDef

type ToolDef struct {
	Name        string              `yaml:"name"`
	Description string              `yaml:"description"`
	Access      string              `yaml:"access"`     // "read" or "write" (default: "write")
	Visibility  string              `yaml:"visibility"` // "primary" or "deferred" (default: "deferred")
	Params      map[string]ParamDef `yaml:"params"`
}

ToolDef declares an MCP tool with its parameter schema. ToolDef describes a single tool exposed by a plugin.

func (ToolDef) IsPrimary added in v0.1.4

func (t ToolDef) IsPrimary() bool

IsPrimary returns true if the tool should be registered without the defer_loading flag. Tools default to deferred.

func (ToolDef) IsReadOnly added in v0.1.2

func (t ToolDef) IsReadOnly() bool

IsReadOnly returns true if the tool is declared as read-only (no side effects).

func (*ToolDef) ParamsSchema

func (t *ToolDef) ParamsSchema() map[string]any

ParamsSchema converts the tool's parameter definitions to JSON Schema as required by the MCP spec.

type Transport

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

Transport manages bidirectional JSON-lines communication with a plugin process over stdin/stdout.

func NewTransport

func NewTransport(stdin io.Writer, stdout, stderr io.Reader, maxSize int) *Transport

NewTransport creates a Transport for communicating with a plugin process.

func (*Transport) ForwardStderr

func (t *Transport) ForwardStderr(pluginName string)

ForwardStderr reads the plugin's stderr and logs it with a prefix.

func (*Transport) GenerateID

func (t *Transport) GenerateID(prefix string) string

GenerateID returns a unique message ID for service requests.

func (*Transport) ReadLoop

func (t *Transport) ReadLoop(pluginName string, concurrency int, serviceHandler ServiceHandler)

ReadLoop reads messages from the plugin's stdout and routes them.

For concurrency <= 1, service requests (http_request, cache_*) are handled synchronously — no goroutines, no race conditions. This guarantees that sequential plugins can use simple blocking read/write loops.

For concurrency > 1, service requests are handled in goroutines.

The handler functions are provided by the caller (proxy and cache).

func (*Transport) Send

func (t *Transport) Send(msg protocol.Message) error

Send writes a JSON message to the plugin's stdin. Thread-safe: serializes writes via mutex to guarantee atomic lines.

func (*Transport) SendAndWait

func (t *Transport) SendAndWait(ctx context.Context, id string, msg protocol.Message) (protocol.Message, error)

SendAndWait sends a message and waits for a response with the same ID. The response is routed by ReadLoop. The context controls the maximum wait time — if the context is cancelled or its deadline expires, SendAndWait returns immediately with the context error.

func (*Transport) SetToolContext added in v0.1.5

func (t *Transport) SetToolContext(ctx *context.Context)

SetToolContext sets the current tool call's context so ReadLoop can use it for service requests (HTTP, cache). Cleared by the caller when the tool call completes or times out. The deferred cancel() from the tool call's context.WithTimeout propagates cancellation to any in-flight HTTP request, unblocking ReadLoop.

func (*Transport) ToolContext added in v0.1.5

func (t *Transport) ToolContext() context.Context

ToolContext returns the current tool call context, or context.Background() if none is set (e.g., during plugin init).

Jump to

Keyboard shortcuts

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