Skip to content

Control how commands execute

Every bound command runs as a subprocess of the binary the binding was given. These options shape that run. All are binding options, passed to cobra.Bind directly or through cli.WithBinding.

Decide which commands are published

mcpcobra.WithExposure(func(cmd *cobra.Command) bool { return cmd.Annotations["internal"] != "true" })

The policy runs after the mandatory filters (hidden, deprecated, help, completion, anything stamped cobra.Omit) and can only remove. Children are still visited under an unexposed parent, so a subtree exclusion with one child re-exposed works. A pure group with no work of its own is published by Cobra's definition of runnable; exclude it here if you do not want a tool that prints usage.

Withhold flags

mcpcobra.WithFlagFilter(func(_ *cobra.Command, flag *pflag.Flag) bool { return flag.Name != "config" })

A declined flag is neither published nor accepted. Use it for persistent flags that steer the process rather than the command: a config-file path a client should not be able to redirect, a --debug that means nothing to a client.

Name and group operations

mcpcobra.WithPrefix("tool")                              // default: the root command's name
mcpcobra.WithOperationName("foo bar", "tool_foo-bar")   // resolve a collision
mcpcobra.WithGroup(func(cmd *cobra.Command) string { return cmd.Annotations["feature"] })

Names are <prefix>_<path joined by _>; foo bar and foo_bar collide and fail the bind until one is renamed. The group is what search_tools narrows by (default: the parent command's name).

Bound execution

mcpcobra.WithLimits(mcpcobra.Limits{
    Concurrency:   2,                 // default 1
    Timeout:       2 * time.Minute,   // default 5 minutes, shortened by the caller's deadline
    CleanupBudget: 10 * time.Second,  // default 5 seconds
    OutputBytes:   4 << 20,           // default 1 MiB, stdout and stderr combined
})

At capacity a call fails at once with a retryable busy; nothing queues. Output beyond the budget is drained rather than blocking the child, and the result says "truncated": true. A run that exceeds the timeout, or is cancelled, is stopped along with every descendant it started; if that cannot be confirmed within the cleanup budget the slot stays taken and Binding.Status() reports it until the process is seen to be gone.

Fix the environment

mcpcobra.WithExecutable("/opt/tool/bin/tool")   // default: os.Executable(), made absolute at bind
mcpcobra.WithWorkingDirectory("/srv/tool")       // default: the host's cwd at bind
mcpcobra.WithEnvironment([]string{"PATH=/usr/bin", "HOME=/srv/tool"}) // default: a copy of the host's
mcpcobra.WithStdin(func() (io.Reader, error) { return strings.NewReader(""), nil }) // default: closed

None of these can be changed by a tool argument. With stdin closed, an interactive command sees EOF at once; exclude such commands or give them a deliberate input source.

Log

mcpcobra.WithLogger(logger)

One record per execution: operation name, exit code, how the run ended, whether output was truncated, and the duration. Arguments are never logged.

The Cobra binding reference has the defaults table and the cleanup boundary.