@@ -3,6 +3,7 @@ package app
33import (
44 "context"
55 "fmt"
6+ "net"
67 "os"
78 "strings"
89
@@ -17,6 +18,7 @@ import (
1718 "github.com/stacklok/toolhive/pkg/permissions"
1819 "github.com/stacklok/toolhive/pkg/registry"
1920 "github.com/stacklok/toolhive/pkg/runner"
21+ "github.com/stacklok/toolhive/pkg/transport"
2022)
2123
2224var runCmd = & cobra.Command {
@@ -56,6 +58,7 @@ permission profile. Additional configuration can be provided via flags.`,
5658var (
5759 runTransport string
5860 runName string
61+ runHost string
5962 runPort int
6063 runTargetPort int
6164 runTargetHost string
7275func init () {
7376 runCmd .Flags ().StringVar (& runTransport , "transport" , "stdio" , "Transport mode (sse or stdio)" )
7477 runCmd .Flags ().StringVar (& runName , "name" , "" , "Name of the MCP server (auto-generated from image if not provided)" )
78+ runCmd .Flags ().StringVar (& runHost , "host" , transport .LocalhostName , "Host for the HTTP proxy to listen on (IP or hostname)" )
7579 runCmd .Flags ().IntVar (& runPort , "port" , 0 , "Port for the HTTP proxy to listen on (host port)" )
7680 runCmd .Flags ().IntVar (& runTargetPort , "target-port" , 0 , "Port for the container to expose (only applicable to SSE transport)" )
7781 runCmd .Flags ().StringVar (
@@ -131,6 +135,14 @@ func init() {
131135
132136func runCmdFunc (cmd * cobra.Command , args []string ) error {
133137 ctx := cmd .Context ()
138+
139+ // Validate the host flag and default resolving to IP in case hostname is provided
140+ validatedHost , err := ValidateAndNormaliseHostFlag (runHost )
141+ if err != nil {
142+ return fmt .Errorf ("invalid host: %s" , runHost )
143+ }
144+ runHost = validatedHost
145+
134146 // Get the server name or image
135147 serverOrImage := args [0 ]
136148
@@ -173,6 +185,7 @@ func runCmdFunc(cmd *cobra.Command, args []string) error {
173185 rt ,
174186 cmdArgs ,
175187 runName ,
188+ runHost ,
176189 debugMode ,
177190 runVolumes ,
178191 runSecrets ,
@@ -437,3 +450,31 @@ func parseCommandArguments(args []string) []string {
437450 }
438451 return cmdArgs
439452}
453+
454+ // ValidateAndNormaliseHostFlag validates and normalizes the host flag resolving it to an IP address if hostname is provided
455+ func ValidateAndNormaliseHostFlag (host string ) (string , error ) {
456+ // Check if the host is a valid IP address
457+ ip := net .ParseIP (host )
458+ if ip != nil {
459+ if ip .To4 () == nil {
460+ return "" , fmt .Errorf ("IPv6 addresses are not supported: %s" , host )
461+ }
462+ return host , nil
463+ }
464+
465+ // If not an IP address, resolve the hostname to an IP address
466+ addrs , err := net .LookupHost (host )
467+ if err != nil {
468+ return "" , fmt .Errorf ("invalid host: %s" , host )
469+ }
470+
471+ // Use the first IPv4 address found
472+ for _ , addr := range addrs {
473+ ip := net .ParseIP (addr )
474+ if ip != nil && ip .To4 () != nil {
475+ return ip .String (), nil
476+ }
477+ }
478+
479+ return "" , fmt .Errorf ("could not resolve host: %s" , host )
480+ }
0 commit comments