provisioner

package
v0.1.0-alpha.8 Latest Latest
Warning

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

Go to latest
Published: Feb 16, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package provisioner detects installed LLM clients and manages their MCP gateway configuration, enabling zero-friction connection between gridctl and tools like Claude Desktop, Cursor, VS Code, and others.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrAlreadyLinked  = errors.New("already linked with identical config")
	ErrConflict       = errors.New("existing entry has unexpected config")
	ErrNotLinked      = errors.New("no gridctl entry found")
	ErrClientNotFound = errors.New("client not detected on this system")
	ErrNpxNotFound    = errors.New("npx not found in PATH")
)

Sentinel errors for link operations.

View Source
var NpxAvailable = func() bool {
	_, err := exec.LookPath("npx")
	return err == nil
}

NpxAvailable checks if npx is available in PATH. Exported as a variable to allow test overrides.

Functions

func DryRunDiff

func DryRunDiff(configPath string, prov ClientProvisioner, opts LinkOptions) (before, after string, err error)

DryRunDiff returns the before/after config for a dry run. Supports both JSON and YAML formats based on the provisioner type.

func GatewayHTTPURL

func GatewayHTTPURL(port int) string

GatewayHTTPURL constructs the streamable HTTP gateway URL from a port.

func GatewayURL

func GatewayURL(port int) string

GatewayURL constructs the SSE gateway URL from a port.

func HasComments

func HasComments(configPath string) bool

HasComments checks if a config file contains JSONC comments that would be lost on write. Returns false if the file doesn't exist.

func TransportDescription

func TransportDescription(needsBridge bool) string

TransportDescription returns a human-readable transport description.

func TransportDescriptionFor

func TransportDescriptionFor(prov ClientProvisioner) string

TransportDescriptionFor returns a transport description for a specific provisioner, distinguishing HTTP-native clients from SSE-native clients.

Types

type AnythingLLM

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

AnythingLLM provisions the AnythingLLM desktop MCP config. Transport: native SSE (no bridge needed). Config uses standard { "mcpServers": { "name": {...} } } structure.

func (*AnythingLLM) Detect

func (p *AnythingLLM) Detect() (string, bool)

func (*AnythingLLM) IsLinked

func (p *AnythingLLM) IsLinked(configPath string, serverName string) (bool, error)
func (p *AnythingLLM) Link(configPath string, opts LinkOptions) error

func (*AnythingLLM) Name

func (p *AnythingLLM) Name() string

func (*AnythingLLM) NeedsBridge

func (p *AnythingLLM) NeedsBridge() bool

func (*AnythingLLM) Slug

func (p *AnythingLLM) Slug() string
func (p *AnythingLLM) Unlink(configPath string, serverName string) error

type ClaudeCode

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

ClaudeCode provisions the Claude Code CLI MCP config. Transport: native HTTP (no bridge needed).

func (*ClaudeCode) Detect

func (c *ClaudeCode) Detect() (string, bool)

Detect overrides mcpServersProvisioner.Detect() because the config file ~/.claude.json has ~ as its parent, which always exists. Instead, check for the ~/.claude/ directory as the installation indicator.

func (*ClaudeCode) IsLinked

func (p *ClaudeCode) IsLinked(configPath string, serverName string) (bool, error)
func (p *ClaudeCode) Link(configPath string, opts LinkOptions) error

func (*ClaudeCode) Name

func (p *ClaudeCode) Name() string

func (*ClaudeCode) NeedsBridge

func (p *ClaudeCode) NeedsBridge() bool

func (*ClaudeCode) Slug

func (p *ClaudeCode) Slug() string
func (p *ClaudeCode) Unlink(configPath string, serverName string) error

type ClaudeDesktop

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

ClaudeDesktop provisions the Claude Desktop MCP config. Transport: stdio only (requires mcp-remote bridge).

func (*ClaudeDesktop) Detect

func (p *ClaudeDesktop) Detect() (string, bool)

func (*ClaudeDesktop) IsLinked

func (p *ClaudeDesktop) IsLinked(configPath string, serverName string) (bool, error)
func (p *ClaudeDesktop) Link(configPath string, opts LinkOptions) error

func (*ClaudeDesktop) Name

func (p *ClaudeDesktop) Name() string

func (*ClaudeDesktop) NeedsBridge

func (p *ClaudeDesktop) NeedsBridge() bool

func (*ClaudeDesktop) Slug

func (p *ClaudeDesktop) Slug() string
func (p *ClaudeDesktop) Unlink(configPath string, serverName string) error

type ClientInfo

type ClientInfo struct {
	Name       string
	Slug       string
	Detected   bool
	Linked     bool
	Transport  string
	ConfigPath string
}

ClientInfo holds detection and link status for one client provisioner.

type ClientProvisioner

type ClientProvisioner interface {
	// Name returns a human-readable client name (e.g., "Claude Desktop").
	Name() string

	// Slug returns the CLI identifier (e.g., "claude", "cursor").
	Slug() string

	// Detect checks if this client is installed on the current system.
	// Returns the config file path if found, empty string if not installed.
	Detect() (configPath string, found bool)

	// IsLinked checks if a gridctl entry already exists in the config.
	IsLinked(configPath string, serverName string) (bool, error)

	// Link injects or updates the gridctl entry in the client config.
	Link(configPath string, opts LinkOptions) error

	// Unlink removes the gridctl entry from the client config.
	Unlink(configPath string, serverName string) error

	// NeedsBridge returns true if this client requires mcp-remote for SSE.
	NeedsBridge() bool
}

ClientProvisioner handles config for a single LLM client.

type Cline

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

Cline provisions the Cline VS Code extension MCP config. Transport: stdio only (requires mcp-remote bridge). Adds Cline-specific fields: "disabled" and "alwaysAllow".

func (*Cline) Detect

func (p *Cline) Detect() (string, bool)

func (*Cline) IsLinked

func (p *Cline) IsLinked(configPath string, serverName string) (bool, error)
func (p *Cline) Link(configPath string, opts LinkOptions) error

func (*Cline) Name

func (p *Cline) Name() string

func (*Cline) NeedsBridge

func (p *Cline) NeedsBridge() bool

func (*Cline) Slug

func (p *Cline) Slug() string
func (p *Cline) Unlink(configPath string, serverName string) error

type ContinueDev

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

ContinueDev provisions the Continue.dev extension MCP config. Transport: native SSE (no bridge needed). Config structure is different: experimental.mcpServers is an array of objects.

func (*ContinueDev) Detect

func (c *ContinueDev) Detect() (string, bool)

func (*ContinueDev) IsLinked

func (c *ContinueDev) IsLinked(configPath string, serverName string) (bool, error)
func (c *ContinueDev) Link(configPath string, opts LinkOptions) error

func (*ContinueDev) Name

func (c *ContinueDev) Name() string

func (*ContinueDev) NeedsBridge

func (c *ContinueDev) NeedsBridge() bool

func (*ContinueDev) Slug

func (c *ContinueDev) Slug() string
func (c *ContinueDev) Unlink(configPath string, serverName string) error

type Cursor

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

Cursor provisions the Cursor editor MCP config. Transport: native SSE (no bridge needed).

func (*Cursor) Detect

func (p *Cursor) Detect() (string, bool)

func (*Cursor) IsLinked

func (p *Cursor) IsLinked(configPath string, serverName string) (bool, error)
func (p *Cursor) Link(configPath string, opts LinkOptions) error

func (*Cursor) Name

func (p *Cursor) Name() string

func (*Cursor) NeedsBridge

func (p *Cursor) NeedsBridge() bool

func (*Cursor) Slug

func (p *Cursor) Slug() string
func (p *Cursor) Unlink(configPath string, serverName string) error

type DetectedClient

type DetectedClient struct {
	Provisioner ClientProvisioner
	ConfigPath  string
}

DetectedClient pairs a provisioner with its found config path.

type GeminiCLI

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

GeminiCLI provisions the Gemini CLI MCP config. Transport: native streamable HTTP (no bridge needed).

func (*GeminiCLI) Detect

func (p *GeminiCLI) Detect() (string, bool)

func (*GeminiCLI) IsLinked

func (p *GeminiCLI) IsLinked(configPath string, serverName string) (bool, error)
func (p *GeminiCLI) Link(configPath string, opts LinkOptions) error

func (*GeminiCLI) Name

func (p *GeminiCLI) Name() string

func (*GeminiCLI) NeedsBridge

func (p *GeminiCLI) NeedsBridge() bool

func (*GeminiCLI) Slug

func (p *GeminiCLI) Slug() string
func (p *GeminiCLI) Unlink(configPath string, serverName string) error

type Goose

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

Goose provisions the Goose (Block) MCP config. Transport: SSE (no bridge needed). Uses YAML format with "extensions" dictionary.

func (*Goose) Detect

func (g *Goose) Detect() (string, bool)

func (*Goose) IsLinked

func (g *Goose) IsLinked(configPath string, serverName string) (bool, error)
func (g *Goose) Link(configPath string, opts LinkOptions) error

func (*Goose) Name

func (g *Goose) Name() string

func (*Goose) NeedsBridge

func (g *Goose) NeedsBridge() bool

func (*Goose) Slug

func (g *Goose) Slug() string
func (g *Goose) Unlink(configPath string, serverName string) error

type LinkOptions

type LinkOptions struct {
	GatewayURL string // e.g., "http://localhost:8180/sse"
	Port       int    // Gateway port for HTTP URL construction
	ServerName string // Key name in config (default: "gridctl")
	Force      bool   // Overwrite existing entry
	DryRun     bool   // Show what would change without modifying files
}

LinkOptions configures how a link is created.

type LinkResult

type LinkResult struct {
	Client     string // Human-readable client name
	ConfigPath string
	BackupPath string
	Action     string // "linked", "updated", "skipped", "already-linked"
	Transport  string // "native SSE" or "mcp-remote bridge"
	Error      error
}

LinkResult describes what happened during a link operation.

type Registry

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

Registry manages all known client provisioners.

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates a Registry with all known client provisioners.

func (*Registry) AllClientInfo

func (r *Registry) AllClientInfo(serverName string) []ClientInfo

AllClientInfo returns detection and link status for every registered client.

func (*Registry) AllSlugs

func (r *Registry) AllSlugs() []string

AllSlugs returns the slugs of all registered clients.

func (*Registry) DetectAll

func (r *Registry) DetectAll() []DetectedClient

DetectAll returns all clients found on this system.

func (*Registry) FindBySlug

func (r *Registry) FindBySlug(slug string) (ClientProvisioner, bool)

FindBySlug returns the provisioner matching the given slug.

func (*Registry) IsAnyLinked

func (r *Registry) IsAnyLinked(serverName string) bool

IsAnyLinked checks if any known client has a gridctl entry.

type RooCode

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

RooCode provisions the Roo Code VS Code extension MCP config. Transport: native SSE and Streamable HTTP (no bridge needed). Adds Roo-specific fields: "transportType", "disabled", "alwaysAllow".

func (*RooCode) Detect

func (p *RooCode) Detect() (string, bool)

func (*RooCode) IsLinked

func (p *RooCode) IsLinked(configPath string, serverName string) (bool, error)
func (p *RooCode) Link(configPath string, opts LinkOptions) error

func (*RooCode) Name

func (p *RooCode) Name() string

func (*RooCode) NeedsBridge

func (p *RooCode) NeedsBridge() bool

func (*RooCode) Slug

func (p *RooCode) Slug() string
func (p *RooCode) Unlink(configPath string, serverName string) error

type VSCode

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

VSCode provisions the VS Code / GitHub Copilot MCP config. Transport: native SSE (no bridge needed). Uses "servers" key (not "mcpServers") and requires a "type" field.

func (*VSCode) Detect

func (v *VSCode) Detect() (string, bool)

func (*VSCode) IsLinked

func (v *VSCode) IsLinked(configPath string, serverName string) (bool, error)
func (v *VSCode) Link(configPath string, opts LinkOptions) error

func (*VSCode) Name

func (v *VSCode) Name() string

func (*VSCode) NeedsBridge

func (v *VSCode) NeedsBridge() bool

func (*VSCode) Slug

func (v *VSCode) Slug() string
func (v *VSCode) Unlink(configPath string, serverName string) error

type Windsurf

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

Windsurf provisions the Windsurf (Codeium) editor MCP config. Transport: native SSE (no bridge needed).

func (*Windsurf) Detect

func (p *Windsurf) Detect() (string, bool)

func (*Windsurf) IsLinked

func (p *Windsurf) IsLinked(configPath string, serverName string) (bool, error)
func (p *Windsurf) Link(configPath string, opts LinkOptions) error

func (*Windsurf) Name

func (p *Windsurf) Name() string

func (*Windsurf) NeedsBridge

func (p *Windsurf) NeedsBridge() bool

func (*Windsurf) Slug

func (p *Windsurf) Slug() string
func (p *Windsurf) Unlink(configPath string, serverName string) error

type Zed

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

Zed provisions the Zed Editor MCP config. Transport: native SSE (no bridge needed). Uses "context_servers" key (not "mcpServers").

func (*Zed) Detect

func (z *Zed) Detect() (string, bool)

func (*Zed) IsLinked

func (z *Zed) IsLinked(configPath string, serverName string) (bool, error)
func (z *Zed) Link(configPath string, opts LinkOptions) error

func (*Zed) Name

func (z *Zed) Name() string

func (*Zed) NeedsBridge

func (z *Zed) NeedsBridge() bool

func (*Zed) Slug

func (z *Zed) Slug() string
func (z *Zed) Unlink(configPath string, serverName string) error

Jump to

Keyboard shortcuts

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