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) ¶
Provide a factory function that produces a fresh *cobra.Command tree on each call. The factory is invoked once at registration time (read-only, for schema generation) and once per tool invocation at runtime. Using a factory ensures that every tool call gets its own Options structs, flag values, and closure-captured variables — eliminating all shared-state hazards and making concurrent tool calls fully independent.
package main
import (
"context"
"log"
"github.com/onexstack/cobrax"
)
func main() {
// Dependencies are injected at construction time and shared safely
// because they are read-only after initialisation.
biz := newBotSreBiz(apiClient, dbClient)
// Factory produces a fresh command tree per invocation.
// Each call allocates new Options structs and closure state.
factory := func() *cobra.Command {
return 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",
}, factory)
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" // AnnotationMCPTool controls whether a command is registered as an MCP tool. // Set to "false" in cmd.Annotations to exclude the command from MCP tool // registration entirely. The check happens before any safety filters or // selectors are evaluated. // // Boolean values are parsed with strconv.ParseBool (accepts "1", "t", "true", // "0", "f", "false", etc.). // // When absent or set to "true", the command proceeds through normal // selector processing. // // Example: // // cmd.Annotations = map[string]string{ // cobrax.AnnotationMCPTool: "false", // exclude this command from MCP // } AnnotationMCPTool = "cobrax.mcp.tool" )
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"`
// Subprocess controls whether tools are executed in a separate OS process.
// When true, each tool invocation re-invokes the current binary as a
// subprocess via execSubprocess. The subprocess survives MCP server
// termination, so long-running commands (e.g. project scaffolding) are
// not killed when the MCP client times out and closes the transport.
// Default is false (in-process execution via runInProcess).
Subprocess bool `json:"subprocess" mapstructure:"subprocess"`
}
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.
Each tool invocation calls cmdFactory to produce a fresh *cobra.Command tree, which means every call gets its own Options structs, flag values, ctx fields, and closure-captured variables. No shared mutable state exists between concurrent or sequential tool calls, so no mutex or reset logic is required.
Example:
biz := newBotSreBiz(client, clientset, ...)
factory := func() *cobra.Command {
root := &cobra.Command{Use: "myapp"}
root.AddCommand(sre.NewOpenCmd(biz, ioStreams))
return root
}
srv, err := cobrax.NewMCPServer(cobrax.MCPOptions{
Enabled: true,
Addr: ":8090",
Name: "myapp",
Version: "1.0.0",
}, factory)
if err != nil {
log.Fatal(err)
}
if err := srv.Start(ctx); err != nil {
log.Fatal(err)
}
func NewMCPServer ¶
func NewMCPServer(opts MCPOptions, cmdFactory func() *cobra.Command, serverOpts ...ServerOption) (*MCPServer, error)
NewMCPServer constructs an MCPServer that exposes Cobra commands as MCP tools.
cmdFactory is called once immediately to obtain a reference command tree for tool schema registration (a read-only traversal). It is then called once per tool invocation at runtime to produce a fresh *cobra.Command tree, ensuring that every call gets its own Options structs, flag values, ctx fields, and closure-captured variables with no shared mutable state between calls.
cmdFactory must not be nil and must return a non-nil *cobra.Command each time it is called; NewMCPServer returns an error if either condition is violated.
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) EinoTools ¶ added in v0.3.0
EinoTools returns the registered MCP tools as a slice of github.com/cloudwego/eino/components/tool.BaseTool.
Each tool's InputSchema is converted from the MCP ToolInputSchema representation into an eino-compatible *jsonschema.Schema via JSON round-trip. The returned tools implement BaseTool (Info method only) and can be passed directly to an eino ChatModel via WithTools / BindTools.
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 {
// FlatInput is the complete flat parameter map received from the MCP client.
// Both flag values and positional argument values live here, keyed by their
// property name (e.g. "output", "verbose", "resource").
FlatInput map[string]any
// FlagNames is the set of property names that correspond to cobra flags.
// Populated from the command's flag set at registration time.
FlagNames map[string]struct{}
// ArgNames is the ordered list of positional argument names, in the order
// they appear in cmd.Use. Ordering matters for positional args.
ArgNames []string
}
ToolInput represents the decoded input for a tool invocation.
After the schema format change, MCP clients send all parameters (both flags and positional arguments) as flat top-level properties in the JSON object. The FlatInput field holds the complete flat map as received from the MCP client. The FlagNames and ArgNames sets are populated during tool registration and are used at execution time to split the flat map back into flag arguments and positional arguments for the underlying cobra command.
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 |
