Documentation
¶
Overview ¶
Package cobrax transforms Cobra CLI applications into MCP (Model Context Protocol) servers, enabling AI assistants to interact with command-line tools.
Ophis automatically converts existing Cobra commands into MCP tools, handling protocol complexity, command execution, and tool registration.
Two Execution Models ¶
Ophis supports two execution models:
Subprocess model (Command / Config): The MCP server re-invokes the same binary as a subprocess for each tool call. This works well when all necessary state can be reconstructed from CLI flags alone.
In-process model (NewMCPServer / MCPServer): The MCP server calls the cobra.Command's Run/RunE function directly in-process. Because the command closures already hold references to runtime dependencies (API clients, database handles, business-logic objects, etc.), those objects are available without any additional wiring. This is the preferred model when commands depend on non-serialisable state.
In-Process Usage (NewMCPServer) ¶
Construct the cobra command tree with its dependencies already injected, then pass the root command to NewMCPServer:
package main
import (
"context"
"log"
"github.com/onexstack/cobrax"
)
func main() {
// Dependencies are injected at construction time.
biz := newBotSreBiz(apiClient, dbClient)
root := buildRootCommand(biz) // adds all subcommands with biz in closures
srv, err := cobrax.NewMCPServer(cobrax.MCPOptions{
Enabled: true,
Addr: ":8090",
Name: "myapp",
Version: "1.0.0",
}, root)
if err != nil {
log.Fatal(err)
}
if err := srv.Start(context.Background()); err != nil {
log.Fatal(err)
}
}
Subprocess Usage (Command) ¶
Add MCP server management subcommands to an existing Cobra application:
package main
import (
"os"
"github.com/onexstack/cobrax"
)
func main() {
rootCmd := createMyRootCommand()
// Adds: mcp start, mcp tools, mcp claude enable/disable/list, etc.
rootCmd.AddCommand(cobrax.Command(nil))
if err := rootCmd.Execute(); err != nil {
os.Exit(1)
}
}
Configuration (Subprocess model) ¶
The Config struct provides fine-grained control over which commands and flags are exposed as MCP tools through a selector system.
Basic filters are always applied automatically:
- Hidden and deprecated commands/flags are excluded
- Commands without executable functions are excluded
- Built-in commands (mcp, help, completion) are excluded
Example with selectors:
config := &cobrax.Config{
Selectors: []cobrax.Selector{
{
CmdSelector: cobrax.AllowCmdsContaining("get", "list"),
LocalFlagSelector: cobrax.AllowFlags("namespace", "output"),
InheritedFlagSelector: cobrax.NoFlags,
},
{
CmdSelector: cobrax.AllowCmds("mycli delete"),
LocalFlagSelector: cobrax.ExcludeFlags("all", "force"),
InheritedFlagSelector: cobrax.NoFlags,
},
},
SloggerOptions: &slog.HandlerOptions{Level: slog.LevelDebug},
}
Index ¶
Constants ¶
const ( // AnnotationTitle sets the human-readable title for the tool. AnnotationTitle = "title" // AnnotationReadOnly hints that the tool does not modify its environment. AnnotationReadOnly = "readOnlyHint" // AnnotationDestructive hints that the tool may perform destructive updates. // Only meaningful when ReadOnlyHint is false. AnnotationDestructive = "destructiveHint" // AnnotationIdempotent hints that calling the tool repeatedly with the same // arguments has no additional effect. Only meaningful when ReadOnlyHint is false. AnnotationIdempotent = "idempotentHint" // AnnotationOpenWorld hints that the tool may interact with external entities // outside its closed domain. AnnotationOpenWorld = "openWorldHint" )
Cobra command annotation keys for MCP tool annotations. Set these in cmd.Annotations to populate mcp.ToolAnnotation on the generated tool.
Boolean values are parsed with strconv.ParseBool (accepts "1", "t", "true", "0", "f", "false", etc.).
Example:
cmd.Annotations = map[string]string{
cobrax.AnnotationReadOnly: "true",
cobrax.AnnotationTitle: "List files",
}
const AnnotationArgPrefix = "cobrax.arg."
Cobra command annotation keys for positional argument metadata. Set these in cmd.Annotations to provide semantic descriptions for each positional argument, which are then surfaced in the MCP Tool JSON Schema so that LLMs know exactly what to supply for each argument position.
Convention:
AnnotationArgPrefix + "0" = description for the first positional arg AnnotationArgPrefix + "1" = description for the second positional arg ... and so on
Example:
cmd.Annotations = map[string]string{
cobrax.AnnotationArgPrefix + "0": "The on-call module name (e.g. 'bke', 'kafka')",
cobrax.AnnotationArgPrefix + "1": "Brief title describing the incident",
}
Variables ¶
This section is empty.
Functions ¶
Types ¶
type ArgSpec ¶
type ArgSpec struct {
// Name is the canonical field name used in the JSON Schema (e.g. "module", "title").
// Derived from the bracket-stripped token in cmd.Use (e.g. "<module>" → "module").
Name string
// Description is a human-readable explanation of what this argument means.
// Populated from the AnnotationArgPrefix+index annotation when available,
// or synthesised from the usage pattern token otherwise.
Description string
// Required indicates whether this argument must be present.
// true → angle-bracket syntax e.g. <name>
// false → square-bracket syntax e.g. [name]
Required bool
// Variadic indicates this argument accepts one or more values.
// true when the token ends with "..." (e.g. [targets...] or <files...>).
Variadic bool
// Index is the zero-based position of this argument in the CLI invocation.
Index int
}
ArgSpec describes a single positional argument parsed from cmd.Use.
type CmdSelector ¶
CmdSelector determines if a command should become an MCP tool. Return true to include the command as a tool. Note: Basic safety filters (hidden, deprecated, non-runnable) are always applied first. Commands are tested against selectors in order; the first matching selector wins.
func AllowCmds ¶
func AllowCmds(cmds ...string) CmdSelector
AllowCmds creates a selector that only accepts commands whose path is listed. Example: AllowCmds("kubectl get", "helm list") includes only those exact commands.
func AllowCmdsContaining ¶
func AllowCmdsContaining(substrings ...string) CmdSelector
AllowCmdsContaining creates a selector that only accepts commands whose path contains a listed phrase. Example: AllowCmdsContaining("get", "helm list") includes "kubectl get pods" and "helm list".
func ExcludeCmds ¶
func ExcludeCmds(cmds ...string) CmdSelector
ExcludeCmds creates a selector that rejects commands whose path is listed. Example: ExcludeCmds("kubectl delete", "helm uninstall") excludes those exact commands.
func ExcludeCmdsContaining ¶
func ExcludeCmdsContaining(substrings ...string) CmdSelector
ExcludeCmdsContaining creates a selector that rejects commands whose path contains any listed phrase. Example: ExcludeCmdsContaining("kubectl delete", "admin") excludes "kubectl delete" and "cli admin user".
type Config ¶
type Config struct {
// CommandName is the Use name for the top-level command returned by Command().
// It is also used by GetCmdPath to locate the cobrax command in the Cobra tree
// and by cmdFilter to exclude cobrax subcommands from tool exposure.
// Default: "mcp".
CommandName string
// Selectors defines rules for converting commands to MCP tools.
// Each selector specifies which commands to match and which flags to include.
//
// Basic safety filters are always applied first:
// - Hidden/deprecated commands and flags are excluded
// - Non-runnable commands are excluded
// - Built-in commands (the cobrax command, help, completion) are excluded
//
// Then selectors are evaluated in order for each command:
// 1. The first selector whose CmdSelector returns true is used
// 2. That selector's FlagSelector determines which flags are included
// 3. If no selectors match, the command is not exposed as a tool
//
// If nil or empty, defaults to exposing all commands with all flags.
Selectors []Selector
// DefaultEnv specifies environment variables that are automatically
// included when `enable` writes a server config for any editor.
// These are merged with user-provided --env values; user values
// take precedence on conflict.
//
// A common use is to capture PATH so the MCP server subprocess can
// find executables that live outside the system PATH:
//
// &cobrax.Config{
// DefaultEnv: map[string]string{
// "PATH": os.Getenv("PATH"),
// },
// }
//
// If nil, no default environment variables are added (current behavior).
DefaultEnv map[string]string
// ToolNamePrefix replaces the root command name in tool names.
// This is useful for shortening tool names to comply with API limits (e.g., Claude's 64 char limit).
// For example, if root command is "omnistrate-ctl" and ToolNamePrefix is "omctl",
// a command "omnistrate-ctl cost by-cell list" becomes "omctl_cost_by-cell_list" instead of
// "omnistrate-ctl_cost_by-cell_list".
// If empty, the root command name is used as-is.
ToolNamePrefix string
// SloggerOptions configures logging to stderr.
// Default: Info level logging.
SloggerOptions *slog.HandlerOptions
// BaseURL is the base URL for the SSE server (e.g. "http://localhost:8080").
// Required when using serveHTTP (the stream command).
// If empty, defaults to "http://localhost:8080".
BaseURL string
// contains filtered or unexported fields
}
Config customizes MCP server behavior and command-to-tool conversion.
type ExecuteFunc ¶
type ExecuteFunc func(context.Context, mcp.CallToolRequest, ToolInput) (*mcp.CallToolResult, ToolOutput, error)
ExecuteFunc defines the function signature for executing a tool.
type FlagSelector ¶
FlagSelector determines if a flag should be included in an MCP tool. Return true to include the flag. Note: Hidden and deprecated flags are always excluded regardless of this selector. This selector is only applied to commands that match the associated CmdSelector.
func AllowFlags ¶
func AllowFlags(names ...string) FlagSelector
AllowFlags creates a selector that only accepts flags whose name is listed. Example: AllowFlags("namespace", "output") includes only flags named "namespace" and "output".
func ExcludeFlags ¶
func ExcludeFlags(names ...string) FlagSelector
ExcludeFlags creates a selector that rejects flags whose name is listed. Example: ExcludeFlags("color", "kubeconfig") excludes flags named "color" and "kubeconfig".
type MCPOptions ¶
type MCPOptions struct {
// Enabled controls whether the MCP server is started.
// When false, Start returns immediately without binding any port.
Enabled bool `json:"enabled" mapstructure:"enabled"`
// Addr is the listen address for the MCP server (e.g. ":8090").
// Required when Enabled is true.
Addr string `json:"addr" mapstructure:"addr"`
// Name is the MCP server name advertised to clients.
Name string `json:"name" mapstructure:"name"`
// Version is the MCP server version advertised to clients.
Version string `json:"version" mapstructure:"version"`
// BaseURL is the publicly reachable base URL for the SSE server
// (e.g. "http://localhost:8090"). Used to construct the SSE endpoint
// advertised to clients. If empty, it is derived from Addr.
BaseURL string `json:"baseURL" mapstructure:"baseURL"`
}
MCPOptions holds configuration for the MCP (Model Context Protocol) server. It is used with NewMCPServer to control how the server advertises itself and which network address it listens on.
type MCPServer ¶
type MCPServer struct {
// contains filtered or unexported fields
}
MCPServer is an MCP server that exposes Cobra commands as MCP tools.
Unlike the subprocess-based execution model used by Config, MCPServer runs every tool handler in-process by directly invoking the matched cobra.Command. This means all dependencies captured in command closures (database clients, API clients, business-logic objects, etc.) are available at call time without any extra wiring — the caller simply constructs the cobra.Command tree with its dependencies already injected before passing it to NewMCPServer.
Example:
biz := newBotSreBiz(client, clientset, ...)
root := cobra.Command{Use: "myapp"}
root.AddCommand(sre.NewOpenCmd(biz, ioStreams))
srv, err := cobrax.NewMCPServer(cobrax.MCPOptions{
Enabled: true,
Addr: ":8090",
Name: "myapp",
Version: "1.0.0",
}, &root)
if err != nil {
log.Fatal(err)
}
if err := srv.Start(ctx); err != nil {
log.Fatal(err)
}
func NewMCPServer ¶
func NewMCPServer(opts MCPOptions, rootCommand *cobra.Command, serverOpts ...ServerOption) (*MCPServer, error)
NewMCPServer constructs an MCPServer by converting every runnable command in rootCommand's tree into an MCP tool.
The rootCommand and all its subcommands are walked recursively. For each command that passes the built-in safety filters (not hidden, not deprecated, has a Run/RunE function, is not the built-in help/completion group) a corresponding MCP tool is registered on the returned server.
Each tool's handler runs the matched cobra.Command in-process, which means any non-cobra dependencies already captured in the command's closure are available at invocation time. stdout and stderr from the command are captured and returned in the ToolOutput.
opts.Enabled must be true for Start to actually bind a port; if false, Start is a no-op, which lets callers gate the MCP server behind a feature flag.
func (*MCPServer) RawMCPServer ¶
RawMCPServer returns the underlying mcpserver.MCPServer instance.
type MiddlewareFunc ¶
type MiddlewareFunc func(context.Context, mcp.CallToolRequest, ToolInput, ExecuteFunc) (*mcp.CallToolResult, ToolOutput, error)
MiddlewareFunc is middleware hook that runs after each tool call Common uses: error handling, response filtering, metrics collection.
type Selector ¶
type Selector struct {
// CmdSelector determines if this selector applies to a command.
// If nil, accepts all commands that pass basic safety filters.
// Cannot be used to bypass safety filters (hidden, deprecated, non-runnable).
CmdSelector CmdSelector
// LocalFlagSelector determines which flags to include for commands matched by CmdSelector.
// If nil, includes all flags that pass basic safety filters.
// Cannot be used to bypass safety filters (hidden, deprecated flags).
LocalFlagSelector FlagSelector
// InheritedFlagSelector determines which persistent flags to include for commands matched by CmdSelector.
// If nil, includes all flags that pass basic safety filters.
// Cannot be used to bypass safety filters (hidden, deprecated flags).
InheritedFlagSelector FlagSelector
// Middleware is an optional middleware hook that wraps around tool execution.
// Common uses: error handling, response filtering, metrics collection.
// If nil, no middleware is applied.
Middleware MiddlewareFunc
}
Selector contains selectors for filtering commands and flags. When multiple selectors are configured, they are evaluated in order. The first selector whose CmdSelector matches a command is used, and its FlagSelector determines which flags are included for that command.
Basic safety filters are always applied automatically:
- Hidden/deprecated commands and flags are excluded
- Non-runnable commands are excluded
- Built-in commands (mcp, help, completion) are excluded
This allows fine-grained control within safe boundaries, such as:
- Exposing different flags for different command groups
- Applying stricter flag filtering to dangerous commands
- Having a default catch-all selector with common flag exclusions
type ServerOption ¶
type ServerOption func(*MCPServer)
ServerOption is a functional option for configuring the MCPServer.
func WithSelectors ¶
func WithSelectors(selectors ...Selector) ServerOption
WithSelectors sets the selector rules used during tool registration. If provided, it overrides the default catch-all Selector{}.
type ToolInput ¶
type ToolInput struct {
Flags map[string]any `json:"flags" jsonschema:"Command line flags"`
PositionalArgs map[string]any `` /* 144-byte string literal not displayed */
Args []string `json:"args,omitempty" jsonschema:"Positional command line arguments (legacy flat list; use positional_args when available)"`
}
ToolInput represents the input structure for command tools. Do not `omitempty` the Flags field, there may be required flags inside.
Positional arguments are encoded in two complementary ways:
PositionalArgs (map[string]any): the preferred representation when the command has named positional arguments parsed from cmd.Use. Each key is the canonical argument name (e.g. "module", "title") and the value is the string (or []string for variadic) supplied by the caller. The MCP JSON Schema exposes these as individually-described named properties so that an LLM knows exactly what to supply for each position.
Args ([]string): the legacy flat-array representation. Used as a fallback when a command has no named argument tokens in cmd.Use, or when the caller prefers to supply raw positional values directly.
Only one of the two fields needs to be populated for any given call; the execution layer checks PositionalArgs first, then falls back to Args.
type ToolOutput ¶
type ToolOutput struct {
StdOut string `json:"stdout,omitempty" jsonschema:"Standard output"`
StdErr string `json:"stderr,omitempty" jsonschema:"Standard error"`
ExitCode int `json:"exitCode" jsonschema:"Exit code"`
}
ToolOutput represents the output structure for command tools.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
bridge/flags
Package flags provides JSON schema generation from Cobra command flags.
|
Package flags provides JSON schema generation from Cobra command flags. |
|
cfgmgr/cmd/claude
Package claude provides CLI commands for managing Claude Desktop MCP servers.
|
Package claude provides CLI commands for managing Claude Desktop MCP servers. |
|
cfgmgr/cmd/cursor
Package cursor provides CLI commands for managing Cursor MCP servers.
|
Package cursor provides CLI commands for managing Cursor MCP servers. |
|
cfgmgr/cmd/vscode
Package vscode provides CLI commands for managing VSCode MCP servers.
|
Package vscode provides CLI commands for managing VSCode MCP servers. |
|
cfgmgr/manager
Package manager provides configuration management for MCP servers across platforms.
|
Package manager provides configuration management for MCP servers across platforms. |
|
cfgmgr/manager/claude
Package claude provides configuration management for Claude Desktop MCP servers.
|
Package claude provides configuration management for Claude Desktop MCP servers. |
|
cfgmgr/manager/cursor
Package cursor provides configuration management for Cursor MCP servers.
|
Package cursor provides configuration management for Cursor MCP servers. |
|
cfgmgr/manager/vscode
Package vscode provides configuration management for VSCode MCP servers.
|
Package vscode provides configuration management for VSCode MCP servers. |
|
schema
Package schema provides JSON schema caching utilities.
|
Package schema provides JSON schema caching utilities. |
|
Package test provides integration testing helper functions for cobrax It assumes cobrax.Command is a root level subcommand
|
Package test provides integration testing helper functions for cobrax It assumes cobrax.Command is a root level subcommand |
