Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var Command = &cli.Command{ Name: "client", Aliases: []string{"c"}, Usage: "Act as the proxy client", ArgsUsage: fmt.Sprintf("ws(s)://proxy-server-address:%d", protocol.DefaultPort), Description: "It will connect to the proxy server and forward stdin to it while forwarding back the server's response to stdout. To be launched by your application expecting a stdio MCP server.", Flags: []cli.Flag{ &cli.StringFlag{ Name: "cert", Usage: "Path to the client certificate file", Aliases: []string{"c"}, Category: "mTLS", OnlyOnce: true, }, &cli.StringFlag{ Name: "key", Usage: "Path to the client key file", Aliases: []string{"k"}, Category: "mTLS", OnlyOnce: true, }, &cli.StringFlag{ Name: "ca", Usage: "Path to the CA certificate file", Aliases: []string{"a"}, Category: "mTLS", OnlyOnce: true, }, }, Before: func(ctx context.Context, cmd *cli.Command) (actionCtx context.Context, err error) { defer func() { if err != nil { err = cli.Exit(err, 1) } }() if cmd.Args().Len() != 1 { err = errors.New("expected exactly one argument: the websocket URL") return } if target, err = url.Parse(cmd.Args().Get(0)); err != nil { err = fmt.Errorf("invalid URL: %w", err) return } certFile := cmd.String("cert") keyFile := cmd.String("key") caFile := cmd.String("ca") if certFile != "" || keyFile != "" || caFile != "" { if certFile == "" || keyFile == "" || caFile == "" { err = errors.New("--cert, --key and --ca must be specified together") return } if tlsConf, err = protocol.GetClientTLSConfig(caFile, certFile, keyFile); err != nil { err = fmt.Errorf("failed to generate client TLS configuration: %w", err) return } } switch target.Scheme { case "ws": if tlsConf != nil { err = errors.New("TLS configuration is not supported for ws:// URLs") return } case "wss": if tlsConf == nil { err = errors.New("TLS configuration is required for wss:// URLs") return } default: err = fmt.Errorf("invalid URL scheme, expecting 'ws' or 'wss': %s", target.Scheme) return } if isLoopbackHost(target.Host) { compressionMode = websocket.CompressionDisabled } else { compressionMode = protocol.CompressionMode } actionCtx = ctx return }, Action: func(ctx context.Context, cmd *cli.Command) (err error) { httpTransport := cleanhttp.DefaultTransport() httpTransport.TLSClientConfig = tlsConf conn, _, err := websocket.Dial(ctx, target.String(), &websocket.DialOptions{ HTTPClient: &http.Client{ Transport: httpTransport, }, CompressionMode: compressionMode, }) if err != nil { return cli.Exit(fmt.Errorf("failed to connect to server: %w", err), 2) } defer func() { if err := conn.CloseNow(); err != nil && !errors.Is(err, net.ErrClosed) { fmt.Fprintf(os.Stderr, "warning: failed to close websocket: %v\n", err) } }() if err = proxy(ctx, conn); err != nil { err = cli.Exit(err, 3) } return }, }
Functions ¶
This section is empty.
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.