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 ¶
- Variables
- func DryRunDiff(configPath string, prov ClientProvisioner, opts LinkOptions) (before, after string, err error)
- func GatewayHTTPURL(port int) string
- func GatewayURL(port int) string
- func HasComments(configPath string) bool
- func TransportDescription(needsBridge bool) string
- func TransportDescriptionFor(prov ClientProvisioner) string
- type AnythingLLM
- func (p *AnythingLLM) Detect() (string, bool)
- func (p *AnythingLLM) IsLinked(configPath string, serverName string) (bool, error)
- func (p *AnythingLLM) Link(configPath string, opts LinkOptions) error
- func (p *AnythingLLM) Name() string
- func (p *AnythingLLM) NeedsBridge() bool
- func (p *AnythingLLM) Slug() string
- func (p *AnythingLLM) Unlink(configPath string, serverName string) error
- type ClaudeCode
- func (c *ClaudeCode) Detect() (string, bool)
- func (p *ClaudeCode) IsLinked(configPath string, serverName string) (bool, error)
- func (p *ClaudeCode) Link(configPath string, opts LinkOptions) error
- func (p *ClaudeCode) Name() string
- func (p *ClaudeCode) NeedsBridge() bool
- func (p *ClaudeCode) Slug() string
- func (p *ClaudeCode) Unlink(configPath string, serverName string) error
- type ClaudeDesktop
- func (p *ClaudeDesktop) Detect() (string, bool)
- func (p *ClaudeDesktop) IsLinked(configPath string, serverName string) (bool, error)
- func (p *ClaudeDesktop) Link(configPath string, opts LinkOptions) error
- func (p *ClaudeDesktop) Name() string
- func (p *ClaudeDesktop) NeedsBridge() bool
- func (p *ClaudeDesktop) Slug() string
- func (p *ClaudeDesktop) Unlink(configPath string, serverName string) error
- type ClientInfo
- type ClientProvisioner
- type Cline
- func (p *Cline) Detect() (string, bool)
- func (p *Cline) IsLinked(configPath string, serverName string) (bool, error)
- func (p *Cline) Link(configPath string, opts LinkOptions) error
- func (p *Cline) Name() string
- func (p *Cline) NeedsBridge() bool
- func (p *Cline) Slug() string
- func (p *Cline) Unlink(configPath string, serverName string) error
- type ContinueDev
- func (c *ContinueDev) Detect() (string, bool)
- func (c *ContinueDev) IsLinked(configPath string, serverName string) (bool, error)
- func (c *ContinueDev) Link(configPath string, opts LinkOptions) error
- func (c *ContinueDev) Name() string
- func (c *ContinueDev) NeedsBridge() bool
- func (c *ContinueDev) Slug() string
- func (c *ContinueDev) Unlink(configPath string, serverName string) error
- type Cursor
- func (p *Cursor) Detect() (string, bool)
- func (p *Cursor) IsLinked(configPath string, serverName string) (bool, error)
- func (p *Cursor) Link(configPath string, opts LinkOptions) error
- func (p *Cursor) Name() string
- func (p *Cursor) NeedsBridge() bool
- func (p *Cursor) Slug() string
- func (p *Cursor) Unlink(configPath string, serverName string) error
- type DetectedClient
- type GeminiCLI
- func (p *GeminiCLI) Detect() (string, bool)
- func (p *GeminiCLI) IsLinked(configPath string, serverName string) (bool, error)
- func (p *GeminiCLI) Link(configPath string, opts LinkOptions) error
- func (p *GeminiCLI) Name() string
- func (p *GeminiCLI) NeedsBridge() bool
- func (p *GeminiCLI) Slug() string
- func (p *GeminiCLI) Unlink(configPath string, serverName string) error
- type Goose
- func (g *Goose) Detect() (string, bool)
- func (g *Goose) IsLinked(configPath string, serverName string) (bool, error)
- func (g *Goose) Link(configPath string, opts LinkOptions) error
- func (g *Goose) Name() string
- func (g *Goose) NeedsBridge() bool
- func (g *Goose) Slug() string
- func (g *Goose) Unlink(configPath string, serverName string) error
- type LinkOptions
- type LinkResult
- type Registry
- type RooCode
- func (p *RooCode) Detect() (string, bool)
- func (p *RooCode) IsLinked(configPath string, serverName string) (bool, error)
- func (p *RooCode) Link(configPath string, opts LinkOptions) error
- func (p *RooCode) Name() string
- func (p *RooCode) NeedsBridge() bool
- func (p *RooCode) Slug() string
- func (p *RooCode) Unlink(configPath string, serverName string) error
- type VSCode
- func (v *VSCode) Detect() (string, bool)
- func (v *VSCode) IsLinked(configPath string, serverName string) (bool, error)
- func (v *VSCode) Link(configPath string, opts LinkOptions) error
- func (v *VSCode) Name() string
- func (v *VSCode) NeedsBridge() bool
- func (v *VSCode) Slug() string
- func (v *VSCode) Unlink(configPath string, serverName string) error
- type Windsurf
- func (p *Windsurf) Detect() (string, bool)
- func (p *Windsurf) IsLinked(configPath string, serverName string) (bool, error)
- func (p *Windsurf) Link(configPath string, opts LinkOptions) error
- func (p *Windsurf) Name() string
- func (p *Windsurf) NeedsBridge() bool
- func (p *Windsurf) Slug() string
- func (p *Windsurf) Unlink(configPath string, serverName string) error
- type Zed
- func (z *Zed) Detect() (string, bool)
- func (z *Zed) IsLinked(configPath string, serverName string) (bool, error)
- func (z *Zed) Link(configPath string, opts LinkOptions) error
- func (z *Zed) Name() string
- func (z *Zed) NeedsBridge() bool
- func (z *Zed) Slug() string
- func (z *Zed) Unlink(configPath string, serverName string) error
Constants ¶
This section is empty.
Variables ¶
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.
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 ¶
GatewayHTTPURL constructs the streamable HTTP gateway URL from a port.
func GatewayURL ¶
GatewayURL constructs the SSE gateway URL from a port.
func HasComments ¶
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 ¶
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) Link ¶
func (p *AnythingLLM) Link(configPath string, opts LinkOptions) error
func (*AnythingLLM) NeedsBridge ¶
func (p *AnythingLLM) NeedsBridge() bool
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) Link ¶
func (p *ClaudeCode) Link(configPath string, opts LinkOptions) error
func (*ClaudeCode) NeedsBridge ¶
func (p *ClaudeCode) NeedsBridge() bool
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) Link ¶
func (p *ClaudeDesktop) Link(configPath string, opts LinkOptions) error
func (*ClaudeDesktop) NeedsBridge ¶
func (p *ClaudeDesktop) NeedsBridge() bool
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) Link ¶
func (p *Cline) Link(configPath string, opts LinkOptions) error
func (*Cline) NeedsBridge ¶
func (p *Cline) NeedsBridge() bool
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 (*ContinueDev) Link ¶
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
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) Link ¶
func (p *Cursor) Link(configPath string, opts LinkOptions) error
func (*Cursor) NeedsBridge ¶
func (p *Cursor) NeedsBridge() bool
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) Link ¶
func (p *GeminiCLI) Link(configPath string, opts LinkOptions) error
func (*GeminiCLI) NeedsBridge ¶
func (p *GeminiCLI) NeedsBridge() bool
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) NeedsBridge ¶
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) 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 ¶
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) Link ¶
func (p *RooCode) Link(configPath string, opts LinkOptions) error
func (*RooCode) NeedsBridge ¶
func (p *RooCode) NeedsBridge() bool
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) NeedsBridge ¶
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) Link ¶
func (p *Windsurf) Link(configPath string, opts LinkOptions) error
func (*Windsurf) NeedsBridge ¶
func (p *Windsurf) NeedsBridge() bool
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").