@@ -19,6 +19,8 @@ import (
1919 "github.com/containers/kubernetes-mcp-server/pkg/version"
2020)
2121
22+ const TokenScopesContextKey = "TokenScopesContextKey"
23+
2224type Configuration struct {
2325 Profile Profile
2426 ListOutput output.Output
@@ -45,20 +47,29 @@ func (c *Configuration) isToolApplicable(tool server.ServerTool) bool {
4547type Server struct {
4648 configuration * Configuration
4749 server * server.MCPServer
50+ enabledTools []string
4851 k * internalk8s.Manager
4952}
5053
5154func NewServer (configuration Configuration ) (* Server , error ) {
55+ var serverOptions []server.ServerOption
56+ serverOptions = append (serverOptions ,
57+ server .WithResourceCapabilities (true , true ),
58+ server .WithPromptCapabilities (true ),
59+ server .WithToolCapabilities (true ),
60+ server .WithLogging (),
61+ server .WithToolHandlerMiddleware (toolCallLoggingMiddleware ),
62+ )
63+ if configuration .StaticConfig .RequireOAuth {
64+ serverOptions = append (serverOptions , server .WithToolHandlerMiddleware (toolScopedAuthorizationMiddleware ))
65+ }
66+
5267 s := & Server {
5368 configuration : & configuration ,
5469 server : server .NewMCPServer (
5570 version .BinaryName ,
5671 version .Version ,
57- server .WithResourceCapabilities (true , true ),
58- server .WithPromptCapabilities (true ),
59- server .WithToolCapabilities (true ),
60- server .WithLogging (),
61- server .WithToolHandlerMiddleware (toolCallLoggingMiddleware ),
72+ serverOptions ... ,
6273 ),
6374 }
6475 if err := s .reloadKubernetesClient (); err != nil {
@@ -81,6 +92,7 @@ func (s *Server) reloadKubernetesClient() error {
8192 continue
8293 }
8394 applicableTools = append (applicableTools , tool )
95+ s .enabledTools = append (s .enabledTools , tool .Tool .Name )
8496 }
8597 s .server .SetTools (applicableTools ... )
8698 return nil
@@ -125,6 +137,10 @@ func (s *Server) GetKubernetesAPIServerHost() string {
125137 return s .k .GetAPIServerHost ()
126138}
127139
140+ func (s * Server ) GetEnabledTools () []string {
141+ return s .enabledTools
142+ }
143+
128144func (s * Server ) Close () {
129145 if s .k != nil {
130146 s .k .Close ()
@@ -181,3 +197,16 @@ func toolCallLoggingMiddleware(next server.ToolHandlerFunc) server.ToolHandlerFu
181197 return next (ctx , ctr )
182198 }
183199}
200+
201+ func toolScopedAuthorizationMiddleware (next server.ToolHandlerFunc ) server.ToolHandlerFunc {
202+ return func (ctx context.Context , ctr mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
203+ scopes , ok := ctx .Value (TokenScopesContextKey ).([]string )
204+ if ! ok {
205+ 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
206+ }
207+ if ! slices .Contains (scopes , "mcp:" + ctr .Params .Name ) && ! slices .Contains (scopes , ctr .Params .Name ) {
208+ 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
209+ }
210+ return next (ctx , ctr )
211+ }
212+ }
0 commit comments