Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var AIO = &cobra.Command{ Use: "aio [flags] -- command [args...]", Short: "Start an all-in-one minibridge frontend and backend", Args: cobra.MinimumNArgs(1), SilenceUsage: true, SilenceErrors: true, TraverseChildren: true, RunE: func(cmd *cobra.Command, args []string) (err error) { ctx, cancel := context.WithCancel(cmd.Context()) defer cancel() listen := viper.GetString("listen") mcpEndpoint := viper.GetString("endpoint-mcp") sseEndpoint := viper.GetString("endpoint-sse") messageEndpoint := viper.GetString("endpoint-messages") agentAuth, err := makeAgentAuth(true) if err != nil { return fmt.Errorf("unable to build auth: %w", err) } policer, penforce, err := makePolicer() if err != nil { return fmt.Errorf("unable to make policer: %w", err) } sbom, err := makeSBOM() if err != nil { return fmt.Errorf("unable to make hashes: %w", err) } tracer, err := makeTracer(ctx, "aio") if err != nil { return fmt.Errorf("unable to configure tracer: %w", err) } corsPolicy := makeCORSPolicy() mcpClient, err := makeMCPClient(args, true) if err != nil { return fmt.Errorf("unable to create MCP client: %w", err) } mm := startHealthServer(ctx) listener := memconn.NewListener() defer func() { _ = listener.Close() }() var eg errgroup.Group var mbackend backend.Backend eg.Go(func() error { defer cancel() slog.Info("Minibridge backend configured") mbackend = backend.NewWebSocket("self", nil, mcpClient, backend.OptListener(listener), backend.OptPolicer(policer), backend.OptPolicerEnforce(penforce), backend.OptDumpStderrOnError(viper.GetString("log-format") != "json"), backend.OptSBOM(sbom), backend.OptMetricsManager(mm), backend.OptTracer(tracer), ) return mbackend.Start(ctx) }) eg.Go(func() error { defer cancel() var mfrontend frontend.Frontend frontendServerTLSConfig, err := tlsConfigFromFlags(fTLSServer) if err != nil { return err } dialer := func(ctx context.Context, network, addr string) (net.Conn, error) { return listener.DialContext(cmd.Context(), "127.0.0.1:443") } if listen != "" { slog.Info("Minibridge frontend configured", "mcp", mcpEndpoint, "sse", sseEndpoint, "messages", messageEndpoint, "agent-token", agentAuth != nil, "mode", "http", "server-tls", frontendServerTLSConfig != nil, "server-mtls", mtlsMode(frontendServerTLSConfig), "listen", listen, ) mfrontend = frontend.NewHTTP(listen, "ws://self/ws", frontendServerTLSConfig, nil, frontend.OptHTTPBackendDialer(dialer), frontend.OptHTTPMCPEndpoint(mcpEndpoint), frontend.OptHTTPSSEEndpoint(sseEndpoint), frontend.OptHTTPMessageEndpoint(messageEndpoint), frontend.OptHTTPAgentTokenPassthrough(true), frontend.OptHTTPCORSPolicy(corsPolicy), frontend.OptHTTPMetricsManager(mm), frontend.OptHTTPTracer(tracer), ) } else { slog.Info("Minibridge frontend configured", "mode", "stdio", ) mfrontend = frontend.NewStdio("ws://self/ws", nil, frontend.OptStdioBackendDialer(dialer), frontend.OptStdioRetry(false), frontend.OptStdioTracer(tracer), ) } time.Sleep(300 * time.Millisecond) return startFrontendWithOAuth(ctx, mfrontend, agentAuth) }) return eg.Wait() }, }
View Source
var Backend = &cobra.Command{ Use: "backend [flags] -- command [args...]", Short: "Start a minibridge backend to expose an MCP server", SilenceUsage: true, SilenceErrors: true, TraverseChildren: true, Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { listen := viper.GetString("listen") if listen == "" { return fmt.Errorf("--listen must be set") } backendTLSConfig, err := tlsConfigFromFlags(fTLSServer) if err != nil { return err } policer, penforce, err := makePolicer() if err != nil { return fmt.Errorf("unable to make policer: %w", err) } sbom, err := makeSBOM() if err != nil { return fmt.Errorf("unable to make hashes: %w", err) } tracer, err := makeTracer(cmd.Context(), "backend") if err != nil { return fmt.Errorf("unable to configure tracer: %w", err) } corsPolicy := makeCORSPolicy() mcpClient, err := makeMCPClient(args, true) if err != nil { return fmt.Errorf("unable to create MCP client: %w", err) } mm := startHealthServer(cmd.Context()) slog.Info("Minibridge backend configured", "server-tls", backendTLSConfig != nil, "server-mtls", mtlsMode(backendTLSConfig), "listen", listen, ) proxy := backend.NewWebSocket(listen, backendTLSConfig, mcpClient, backend.OptPolicer(policer), backend.OptPolicerEnforce(penforce), backend.OptDumpStderrOnError(viper.GetString("log-format") != "json"), backend.OptCORSPolicy(corsPolicy), backend.OptSBOM(sbom), backend.OptMetricsManager(mm), backend.OptTracer(tracer), ) return proxy.Start(cmd.Context()) }, }
Backend is the cobra command to run the server.
View Source
var Completion = &cobra.Command{ Use: "completion [bash|zsh|fish|powershell]", Short: "Generate completion script", DisableFlagsInUseLine: true, ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), RunE: func(cmd *cobra.Command, args []string) error { switch args[0] { case "bash": return cmd.Root().GenBashCompletion(os.Stdout) case "zsh": return cmd.Root().GenZshCompletion(os.Stdout) case "fish": return cmd.Root().GenFishCompletion(os.Stdout, true) case "powershell": return cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout) } return nil }, }
View Source
var Frontend = &cobra.Command{ Use: "frontend", Short: "Start a minibridge frontend to connect to a minibridge backend", SilenceUsage: true, SilenceErrors: true, TraverseChildren: true, RunE: func(cmd *cobra.Command, args []string) error { listen := viper.GetString("listen") backendURL := viper.GetString("backend") mcpEndpoint := viper.GetString("endpoint-mcp") sseEndpoint := viper.GetString("endpoint-sse") messageEndpoint := viper.GetString("endpoint-messages") agentAuthPassthrough := viper.GetBool("agent-auth-passthrough") if backendURL == "" { return fmt.Errorf("--backend must be set") } if !strings.HasPrefix(backendURL, "wss://") && !strings.HasPrefix(backendURL, "ws://") { return fmt.Errorf("--backend must use wss:// or ws:// scheme") } if !strings.HasSuffix(backendURL, "/ws") { backendURL = backendURL + "/ws" } agentAuth, err := makeAgentAuth(true) if err != nil { return fmt.Errorf("unable to build auth: %w", err) } clientTLSConfig, err := tlsConfigFromFlags(fTLSClient) if err != nil { return err } tracer, err := makeTracer(cmd.Context(), "backend") if err != nil { return fmt.Errorf("unable to configure tracer: %w", err) } corsPolicy := makeCORSPolicy() mm := startHealthServer(cmd.Context()) var mfrontend frontend.Frontend if listen != "" { serverTLSConfig, err := tlsConfigFromFlags(fTLSServer) if err != nil { return err } slog.Info("Minibridge frontend configured", "backend", backendURL, "mcp", mcpEndpoint, "sse", sseEndpoint, "messages", messageEndpoint, "mode", "http", "server-tls", serverTLSConfig != nil, "server-mtls", mtlsMode(serverTLSConfig), "client-tls", clientTLSConfig != nil, "listen", listen, ) mfrontend = frontend.NewHTTP(listen, backendURL, serverTLSConfig, clientTLSConfig, frontend.OptHTTPMCPEndpoint(mcpEndpoint), frontend.OptHTTPSSEEndpoint(sseEndpoint), frontend.OptHTTPMessageEndpoint(messageEndpoint), frontend.OptHTTPAgentTokenPassthrough(agentAuthPassthrough), frontend.OptHTTPCORSPolicy(corsPolicy), frontend.OptHTTPMetricsManager(mm), frontend.OptHTTPTracer(tracer), ) } else { slog.Info("Minibridge frontend configured", "backend", backendURL, "mode", "stdio", ) mfrontend = frontend.NewStdio(backendURL, clientTLSConfig, frontend.OptStdioTracer(tracer), frontend.OptStdioRetry(false), ) } return startFrontendWithOAuth(cmd.Context(), mfrontend, agentAuth) }, }
Frontend is the cobra command to run the client.
View Source
var Root = &cobra.Command{ Use: "minibridge", Short: "Secure your MCP Servers", SilenceUsage: true, SilenceErrors: true, TraverseChildren: true, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { return err } if err := viper.BindPFlags(cmd.Flags()); err != nil { return err } bootstrap.ConfigureLogger("minibridge", conf.LoggingConf{ LogLevel: viper.GetString("log-level"), LogFormat: viper.GetString("log-format"), }) return nil }, RunE: func(cmd *cobra.Command, args []string) error { if viper.GetBool("version") { fmt.Println(version.Short()) os.Exit(0) } return cmd.Usage() }, }
View Source
var Scan = &cobra.Command{ Use: "scan [dump|sbom|check file.sbom] -- command [args...]", Short: "Scan an MCP server for resources, prompts, etc and generate sbom", SilenceUsage: true, SilenceErrors: true, TraverseChildren: true, Args: cobra.MinimumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { timeout := viper.GetDuration("timeout") exclusions := &scan.Exclusions{ Prompts: viper.GetBool("exclude-prompts"), Resources: viper.GetBool("exclude-resources"), Tools: viper.GetBool("exclude-tools"), } var ctx context.Context var cancel context.CancelFunc if timeout > 0 { ctx, cancel = context.WithTimeout(cmd.Context(), timeout) } else { ctx, cancel = context.WithCancel(cmd.Context()) } defer cancel() var err error var mcpCommand string var mcpArgs []string if args[0] == "check" { mcpCommand = args[2] mcpArgs = args[3:] } else { mcpCommand = args[1] mcpArgs = args[2:] } mcpClient, err := makeMCPClient(append([]string{mcpCommand}, mcpArgs...), false) if err != nil { return err } agentAuth, err := makeAgentAuth(false) if err != nil { return fmt.Errorf("unable to build auth: %w", err) } stream, err := mcpClient.Start(ctx, client.OptionAuth(agentAuth)) if err != nil { return fmt.Errorf("unable to start MCP server: %w", err) } dump, err := scan.DumpAll(ctx, stream, exclusions) if err != nil { return fmt.Errorf("unable to dump tools: %w", err) } cancel() var toolHashes scan.Hashes if !exclusions.Tools { toolHashes, err = scan.HashTools(dump.Tools) if err != nil { return fmt.Errorf("unable to hash tools: %w", err) } } var promptHashes scan.Hashes if !exclusions.Prompts { promptHashes, err = scan.HashPrompts(dump.Prompts) if err != nil { return fmt.Errorf("unable to hash prompts: %w", err) } } sbom := scan.SBOM{ Tools: toolHashes, Prompts: promptHashes, } switch args[0] { case "check": refSBOM, err := scan.LoadSBOM(args[1]) if err != nil { return fmt.Errorf("unable to load sbom: %w", err) } if err := refSBOM.Tools.Matches(sbom.Tools); err != nil { return fmt.Errorf("tools sbom does not match: %w", err) } if err := refSBOM.Prompts.Matches(sbom.Prompts); err != nil { return fmt.Errorf("prompts sbom does not match: %w", err) } case "sbom": enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") if err := enc.Encode(sbom); err != nil { return fmt.Errorf("unable to encode sbom: %w", err) } case "dump": enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") if err := enc.Encode(dump); err != nil { return fmt.Errorf("unable to encode dump: %w", err) } default: return fmt.Errorf("first command must be either dump, sbom or check") } return nil }, }
Scan is the cobra command to run the server.
Functions ¶
This section is empty.
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.