@@ -7,9 +7,11 @@ package main
77import (
88 "context"
99 "errors"
10+ "expvar"
1011 "flag"
1112 "fmt"
1213 "log/slog"
14+ "net"
1315 "net/http"
1416 "net/url"
1517 "os"
@@ -57,6 +59,15 @@ type MCPAPIConfig struct {
5759 Scopes []string `koanf:"scopes"`
5860}
5961
62+ // Build-time variables set via ldflags.
63+ var (
64+ // Version is the application version, set at build time via -ldflags.
65+ // On a tagged commit this is the tag (e.g. v0.4.1); between tags it includes
66+ // the offset and short hash (e.g. v0.4.1-3-gabcdef0); a -dirty suffix is
67+ // appended when there are uncommitted changes.
68+ Version = "dev"
69+ )
70+
6071const errKey = "error"
6172
6273// defaultTools is the list of tools enabled by default.
@@ -104,6 +115,10 @@ func main() {
104115
105116 // Define flags.
106117 f := flag .NewFlagSet ("lfx-mcp-server" , flag .ExitOnError )
118+ f .Usage = func () {
119+ fmt .Fprintf (f .Output (), "lfx-mcp-server %s\n \n Usage:\n " , Version )
120+ f .PrintDefaults ()
121+ }
107122 f .String ("mode" , "stdio" , "Transport mode: stdio or http" )
108123 f .String ("http.host" , "127.0.0.1" , "Host to bind to for HTTP transport" )
109124 f .Int ("http.port" , 8080 , "Port to listen on for HTTP transport" )
@@ -300,7 +315,7 @@ func mcpLoggingMiddleware(serverLogger *slog.Logger) mcp.Middleware {
300315func newServer (cfg Config ) * mcp.Server {
301316 server := mcp .NewServer (& mcp.Implementation {
302317 Name : "lfx-mcp-server" ,
303- Version : "0.1.0" ,
318+ Version : Version ,
304319 }, & mcp.ServerOptions {
305320 Logger : logger ,
306321 })
@@ -464,6 +479,10 @@ func runHTTPServer(cfg Config) {
464479 _ , _ = w .Write ([]byte ("ok" ))
465480 })
466481
482+ // Register expvar debug endpoint; restricted to loopback-only so it is
483+ // accessible via kubectl port-forward but blocked from ingress traffic.
484+ mux .Handle ("/debug/vars" , localhostOnly (expvar .Handler ()))
485+
467486 // Apply OAuth bearer token middleware if auth servers are configured.
468487 var mcpHandler http.Handler = handler
469488 if len (cfg .MCPAPI .AuthServers ) > 0 {
@@ -619,6 +638,26 @@ func runHTTPServer(cfg Config) {
619638 logger .Info ("HTTP server stopped" )
620639}
621640
641+ // localhostOnly wraps h and returns 403 Forbidden for any request whose remote
642+ // address is not the IPv4 or IPv6 loopback address. This allows the handler to
643+ // be reached via kubectl port-forward (which arrives as 127.0.0.1) while
644+ // blocking traffic that originates from the ingress or other cluster sources.
645+ func localhostOnly (h http.Handler ) http.Handler {
646+ return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
647+ host , _ , err := net .SplitHostPort (r .RemoteAddr )
648+ if err != nil {
649+ http .Error (w , "forbidden" , http .StatusForbidden )
650+ return
651+ }
652+ ip := net .ParseIP (host )
653+ if ip == nil || ! ip .IsLoopback () {
654+ http .Error (w , "forbidden" , http .StatusForbidden )
655+ return
656+ }
657+ h .ServeHTTP (w , r )
658+ })
659+ }
660+
622661// httpDebugLogging returns middleware that logs all incoming HTTP requests and their
623662// completion at DEBUG level, including paths not handled by any route (404s).
624663func httpDebugLogging (logger * slog.Logger ) func (http.Handler ) http.Handler {
0 commit comments