@@ -4,10 +4,11 @@ import (
44 "bytes"
55 "context"
66 "fmt"
7- "k8s.io/klog/v2"
87 "net/http"
98 "slices"
109
10+ "k8s.io/klog/v2"
11+
1112 "github.com/mark3labs/mcp-go/mcp"
1213 "github.com/mark3labs/mcp-go/server"
1314 authenticationapiv1 "k8s.io/api/authentication/v1"
@@ -19,6 +20,8 @@ import (
1920 "github.com/containers/kubernetes-mcp-server/pkg/version"
2021)
2122
23+ const TokenScopesContextKey = "TokenScopesContextKey"
24+
2225type Configuration struct {
2326 Profile Profile
2427 ListOutput output.Output
@@ -45,20 +48,29 @@ func (c *Configuration) isToolApplicable(tool server.ServerTool) bool {
4548type Server struct {
4649 configuration * Configuration
4750 server * server.MCPServer
51+ enabledTools []string
4852 k * internalk8s.Manager
4953}
5054
5155func NewServer (configuration Configuration ) (* Server , error ) {
56+ var serverOptions []server.ServerOption
57+ serverOptions = append (serverOptions ,
58+ server .WithResourceCapabilities (true , true ),
59+ server .WithPromptCapabilities (true ),
60+ server .WithToolCapabilities (true ),
61+ server .WithLogging (),
62+ server .WithToolHandlerMiddleware (toolCallLoggingMiddleware ),
63+ )
64+ if configuration .StaticConfig .RequireOAuth {
65+ serverOptions = append (serverOptions , server .WithToolHandlerMiddleware (toolScopedAuthorizationMiddleware ))
66+ }
67+
5268 s := & Server {
5369 configuration : & configuration ,
5470 server : server .NewMCPServer (
5571 version .BinaryName ,
5672 version .Version ,
57- server .WithResourceCapabilities (true , true ),
58- server .WithPromptCapabilities (true ),
59- server .WithToolCapabilities (true ),
60- server .WithLogging (),
61- server .WithToolHandlerMiddleware (toolCallLoggingMiddleware ),
73+ serverOptions ... ,
6274 ),
6375 }
6476 if err := s .reloadKubernetesClient (); err != nil {
@@ -81,6 +93,7 @@ func (s *Server) reloadKubernetesClient() error {
8193 continue
8294 }
8395 applicableTools = append (applicableTools , tool )
96+ s .enabledTools = append (s .enabledTools , tool .Tool .Name )
8497 }
8598 s .server .SetTools (applicableTools ... )
8699 return nil
@@ -125,6 +138,10 @@ func (s *Server) GetKubernetesAPIServerHost() string {
125138 return s .k .GetAPIServerHost ()
126139}
127140
141+ func (s * Server ) GetEnabledTools () []string {
142+ return s .enabledTools
143+ }
144+
128145func (s * Server ) Close () {
129146 if s .k != nil {
130147 s .k .Close ()
@@ -154,12 +171,6 @@ func NewTextResult(content string, err error) *mcp.CallToolResult {
154171}
155172
156173func contextFunc (ctx context.Context , r * http.Request ) context.Context {
157- // Get the standard Authorization header (OAuth compliant)
158- authHeader := r .Header .Get (string (internalk8s .OAuthAuthorizationHeader ))
159- if authHeader != "" {
160- return context .WithValue (ctx , internalk8s .OAuthAuthorizationHeader , authHeader )
161- }
162-
163174 // Fallback to custom header for backward compatibility
164175 customAuthHeader := r .Header .Get (string (internalk8s .CustomAuthorizationHeader ))
165176 if customAuthHeader != "" {
@@ -181,3 +192,16 @@ func toolCallLoggingMiddleware(next server.ToolHandlerFunc) server.ToolHandlerFu
181192 return next (ctx , ctr )
182193 }
183194}
195+
196+ func toolScopedAuthorizationMiddleware (next server.ToolHandlerFunc ) server.ToolHandlerFunc {
197+ return func (ctx context.Context , ctr mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
198+ scopes , ok := ctx .Value (TokenScopesContextKey ).([]string )
199+ if ! ok {
200+ return NewTextResult ("" , fmt .Errorf ("Authorization failed: Access denied: Tool '%s' requires scope 'mcp:%s' but no scope is available" , ctr .Params .Name , ctr .Params .Name )), nil
201+ }
202+ if ! slices .Contains (scopes , "mcp:" + ctr .Params .Name ) && ! slices .Contains (scopes , ctr .Params .Name ) {
203+ return NewTextResult ("" , fmt .Errorf ("Authorization failed: Access denied: Tool '%s' requires scope 'mcp:%s' but only scopes %s are available" , ctr .Params .Name , ctr .Params .Name , scopes )), nil
204+ }
205+ return next (ctx , ctr )
206+ }
207+ }
0 commit comments