Skip to content

Commit 56d1d18

Browse files
committed
Introduce new full-safe profile with a default resource deny list
1 parent 754da19 commit 56d1d18

File tree

5 files changed

+83
-2
lines changed

5 files changed

+83
-2
lines changed

pkg/kubernetes-mcp-server/cmd/root_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func TestProfile(t *testing.T) {
4747
rootCmd := NewMCPServer(ioStreams)
4848
rootCmd.SetArgs([]string{"--help"})
4949
o, err := captureOutput(rootCmd.Execute) // --help doesn't use logger/klog, cobra prints directly to stdout
50-
if !strings.Contains(o, "MCP profile to use (one of: full) ") {
50+
if !strings.Contains(o, "MCP profile to use (one of: full, full-safe) ") {
5151
t.Fatalf("Expected all available profiles, got %s %v", o, err)
5252
}
5353
})

pkg/mcp/configs/full-safe.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# A list of denied Kubernetes resources in Group/Version/Kind format.
2+
# If a resource is in this list, MCP server should deny all operations
3+
# on that resource type across all namespaces.
4+
[[denied_resources]]
5+
group = ""
6+
version = "v1"
7+
kind = "ServiceAccount"
8+
9+
[[denied_resources]]
10+
group = ""
11+
version = "v1"
12+
kind = "Secret"
13+
14+
[[denied_resources]]
15+
group = "rbac.authorization.k8s.io"
16+
version = "v1"

pkg/mcp/configs/full.toml

Whitespace-only changes.

pkg/mcp/mcp.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ package mcp
22

33
import (
44
"context"
5-
"github.com/manusa/kubernetes-mcp-server/pkg/config"
65
"net/http"
76

87
"github.com/mark3labs/mcp-go/mcp"
98
"github.com/mark3labs/mcp-go/server"
109
"k8s.io/utils/ptr"
1110

11+
"github.com/manusa/kubernetes-mcp-server/pkg/config"
1212
"github.com/manusa/kubernetes-mcp-server/pkg/kubernetes"
1313
"github.com/manusa/kubernetes-mcp-server/pkg/output"
1414
"github.com/manusa/kubernetes-mcp-server/pkg/version"
@@ -49,6 +49,14 @@ func NewServer(configuration Configuration) (*Server, error) {
4949
}
5050
s.k.WatchKubeConfig(s.reloadKubernetesClient)
5151

52+
if configuration.StaticConfig == nil {
53+
staticConfig, err := configuration.Profile.GetDefaultConfig()
54+
if err != nil {
55+
return nil, err
56+
}
57+
configuration.StaticConfig = staticConfig
58+
}
59+
5260
return s, nil
5361
}
5462

pkg/mcp/profiles.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
11
package mcp
22

33
import (
4+
"embed"
5+
"io/fs"
46
"slices"
57

8+
"github.com/BurntSushi/toml"
69
"github.com/mark3labs/mcp-go/server"
10+
11+
"github.com/manusa/kubernetes-mcp-server/pkg/config"
712
)
813

14+
//go:embed configs/full.toml
15+
var defaultFullConfigFile embed.FS
16+
17+
//go:embed configs/full-safe.toml
18+
var defaultFullSafeConfigFile embed.FS
19+
920
type Profile interface {
1021
GetName() string
1122
GetDescription() string
1223
GetTools(s *Server) []server.ServerTool
24+
GetDefaultConfig() (*config.StaticConfig, error)
1325
}
1426

1527
var Profiles = []Profile{
1628
&FullProfile{},
29+
&FullSafeProfile{},
1730
}
1831

1932
var ProfileNames []string
@@ -45,6 +58,50 @@ func (p *FullProfile) GetTools(s *Server) []server.ServerTool {
4558
s.initHelm(),
4659
)
4760
}
61+
func (p *FullProfile) GetDefaultConfig() (*config.StaticConfig, error) {
62+
data, err := fs.ReadFile(defaultFullConfigFile, "configs/full.toml")
63+
if err != nil {
64+
return nil, err
65+
}
66+
67+
var cfg *config.StaticConfig
68+
err = toml.Unmarshal(data, &cfg)
69+
if err != nil {
70+
return nil, err
71+
}
72+
return cfg, nil
73+
}
74+
75+
type FullSafeProfile struct{}
76+
77+
func (p *FullSafeProfile) GetName() string {
78+
return "full-safe"
79+
}
80+
func (p *FullSafeProfile) GetDescription() string {
81+
return "Complete profile with all tools and extended outputs"
82+
}
83+
func (p *FullSafeProfile) GetTools(s *Server) []server.ServerTool {
84+
return slices.Concat(
85+
s.initEvents(),
86+
s.initNamespaces(),
87+
s.initPods(),
88+
s.initResources(),
89+
s.initHelm(),
90+
)
91+
}
92+
func (p *FullSafeProfile) GetDefaultConfig() (*config.StaticConfig, error) {
93+
data, err := fs.ReadFile(defaultFullSafeConfigFile, "configs/full-safe.toml")
94+
if err != nil {
95+
return nil, err
96+
}
97+
98+
var cfg *config.StaticConfig
99+
err = toml.Unmarshal(data, &cfg)
100+
if err != nil {
101+
return nil, err
102+
}
103+
return cfg, nil
104+
}
48105

49106
func init() {
50107
ProfileNames = make([]string, 0)

0 commit comments

Comments
 (0)