Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions pkg/mcp/tools_config_envs.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ type ConfigEnvsAddOutput struct {
}

func (s *Server) configEnvsAddHandler(ctx context.Context, r *mcp.CallToolRequest, input ConfigEnvsAddInput) (result *mcp.CallToolResult, output ConfigEnvsAddOutput, err error) {
if s.readonly.Load() {
err = fmt.Errorf("the server is currently in readonly mode. Please set FUNC_ENABLE_MCP_WRITE and restart the client")
return
}
if err = input.validate(); err != nil {
return
}
Expand Down Expand Up @@ -186,6 +190,10 @@ type ConfigEnvsRemoveOutput struct {
}

func (s *Server) configEnvsRemoveHandler(ctx context.Context, r *mcp.CallToolRequest, input ConfigEnvsRemoveInput) (result *mcp.CallToolResult, output ConfigEnvsRemoveOutput, err error) {
if s.readonly.Load() {
err = fmt.Errorf("the server is currently in readonly mode. Please set FUNC_ENABLE_MCP_WRITE and restart the client")
return
}
out, err := s.executor.Execute(ctx, "config", input.Args()...)
if err != nil {
err = fmt.Errorf("%w\n%s", err, string(out))
Expand Down
50 changes: 50 additions & 0 deletions pkg/mcp/tools_config_envs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -627,3 +627,53 @@ func TestTool_ConfigEnvsRemove_Error(t *testing.T) {
t.Fatal("expected error result, got success")
}
}

// TestTool_ConfigEnvsAdd_Readonly ensures the config_envs_add tool is blocked in readonly mode.
func TestTool_ConfigEnvsAdd_Readonly(t *testing.T) {
executor := mock.NewExecutor()

client, server, err := newTestPair(t, WithExecutor(executor))
if err != nil {
t.Fatal(err)
}
server.readonly.Store(true)

result, err := client.CallTool(t.Context(), &mcp.CallToolParams{
Name: "config_envs_add",
Arguments: map[string]any{"path": ".", "name": "KEY", "value": "VAL"},
})
if err != nil {
t.Fatal(err)
}
if !result.IsError {
t.Fatal("expected error result in readonly mode, got success")
}
if executor.ExecuteInvoked {
t.Fatal("executor should not be invoked in readonly mode")
}
}

// TestTool_ConfigEnvsRemove_Readonly ensures the config_envs_remove tool is blocked in readonly mode.
func TestTool_ConfigEnvsRemove_Readonly(t *testing.T) {
executor := mock.NewExecutor()

client, server, err := newTestPair(t, WithExecutor(executor))
if err != nil {
t.Fatal(err)
}
server.readonly.Store(true)

result, err := client.CallTool(t.Context(), &mcp.CallToolParams{
Name: "config_envs_remove",
Arguments: map[string]any{"path": ".", "name": "KEY"},
})
if err != nil {
t.Fatal(err)
}
if !result.IsError {
t.Fatal("expected error result in readonly mode, got success")
}
if executor.ExecuteInvoked {
t.Fatal("executor should not be invoked in readonly mode")
}
}
8 changes: 8 additions & 0 deletions pkg/mcp/tools_config_labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ type ConfigLabelsAddOutput struct {
}

func (s *Server) configLabelsAddHandler(ctx context.Context, r *mcp.CallToolRequest, input ConfigLabelsAddInput) (result *mcp.CallToolResult, output ConfigLabelsAddOutput, err error) {
if s.readonly.Load() {
err = fmt.Errorf("the server is currently in readonly mode. Please set FUNC_ENABLE_MCP_WRITE and restart the client")
return
}
out, err := s.executor.Execute(ctx, "config", input.Args()...)
if err != nil {
err = fmt.Errorf("%w\n%s", err, string(out))
Expand Down Expand Up @@ -120,6 +124,10 @@ type ConfigLabelsRemoveOutput struct {
}

func (s *Server) configLabelsRemoveHandler(ctx context.Context, r *mcp.CallToolRequest, input ConfigLabelsRemoveInput) (result *mcp.CallToolResult, output ConfigLabelsRemoveOutput, err error) {
if s.readonly.Load() {
err = fmt.Errorf("the server is currently in readonly mode. Please set FUNC_ENABLE_MCP_WRITE and restart the client")
return
}
out, err := s.executor.Execute(ctx, "config", input.Args()...)
if err != nil {
err = fmt.Errorf("%w\n%s", err, string(out))
Expand Down
50 changes: 50 additions & 0 deletions pkg/mcp/tools_config_labels_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,53 @@ func TestTool_ConfigLabelsRemove_Error(t *testing.T) {
t.Fatal("expected error result, got success")
}
}

// TestTool_ConfigLabelsAdd_Readonly ensures the config_labels_add tool is blocked in readonly mode.
func TestTool_ConfigLabelsAdd_Readonly(t *testing.T) {
executor := mock.NewExecutor()

client, server, err := newTestPair(t, WithExecutor(executor))
if err != nil {
t.Fatal(err)
}
server.readonly.Store(true)

result, err := client.CallTool(t.Context(), &mcp.CallToolParams{
Name: "config_labels_add",
Arguments: map[string]any{"path": ".", "name": "app", "value": "test"},
})
if err != nil {
t.Fatal(err)
}
if !result.IsError {
t.Fatal("expected error result in readonly mode, got success")
}
if executor.ExecuteInvoked {
t.Fatal("executor should not be invoked in readonly mode")
}
}

// TestTool_ConfigLabelsRemove_Readonly ensures the config_labels_remove tool is blocked in readonly mode.
func TestTool_ConfigLabelsRemove_Readonly(t *testing.T) {
executor := mock.NewExecutor()

client, server, err := newTestPair(t, WithExecutor(executor))
if err != nil {
t.Fatal(err)
}
server.readonly.Store(true)

result, err := client.CallTool(t.Context(), &mcp.CallToolParams{
Name: "config_labels_remove",
Arguments: map[string]any{"path": ".", "name": "app"},
})
if err != nil {
t.Fatal(err)
}
if !result.IsError {
t.Fatal("expected error result in readonly mode, got success")
}
if executor.ExecuteInvoked {
t.Fatal("executor should not be invoked in readonly mode")
}
}
8 changes: 8 additions & 0 deletions pkg/mcp/tools_config_volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ type ConfigVolumesAddOutput struct {
}

func (s *Server) configVolumesAddHandler(ctx context.Context, r *mcp.CallToolRequest, input ConfigVolumesAddInput) (result *mcp.CallToolResult, output ConfigVolumesAddOutput, err error) {
if s.readonly.Load() {
err = fmt.Errorf("the server is currently in readonly mode. Please set FUNC_ENABLE_MCP_WRITE and restart the client")
return
}
out, err := s.executor.Execute(ctx, "config", input.Args()...)
if err != nil {
err = fmt.Errorf("%w\n%s", err, string(out))
Expand Down Expand Up @@ -128,6 +132,10 @@ type ConfigVolumesRemoveOutput struct {
}

func (s *Server) configVolumesRemoveHandler(ctx context.Context, r *mcp.CallToolRequest, input ConfigVolumesRemoveInput) (result *mcp.CallToolResult, output ConfigVolumesRemoveOutput, err error) {
if s.readonly.Load() {
err = fmt.Errorf("the server is currently in readonly mode. Please set FUNC_ENABLE_MCP_WRITE and restart the client")
return
}
out, err := s.executor.Execute(ctx, "config", input.Args()...)
if err != nil {
err = fmt.Errorf("%w\n%s", err, string(out))
Expand Down
50 changes: 50 additions & 0 deletions pkg/mcp/tools_config_volumes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,53 @@ func TestTool_ConfigVolumesRemove_Error(t *testing.T) {
t.Fatal("expected error result, got success")
}
}

// TestTool_ConfigVolumesAdd_Readonly ensures the config_volumes_add tool is blocked in readonly mode.
func TestTool_ConfigVolumesAdd_Readonly(t *testing.T) {
executor := mock.NewExecutor()

client, server, err := newTestPair(t, WithExecutor(executor))
if err != nil {
t.Fatal(err)
}
server.readonly.Store(true)

result, err := client.CallTool(t.Context(), &mcp.CallToolParams{
Name: "config_volumes_add",
Arguments: map[string]any{"path": "."},
})
if err != nil {
t.Fatal(err)
}
if !result.IsError {
t.Fatal("expected error result in readonly mode, got success")
}
if executor.ExecuteInvoked {
t.Fatal("executor should not be invoked in readonly mode")
}
}

// TestTool_ConfigVolumesRemove_Readonly ensures the config_volumes_remove tool is blocked in readonly mode.
func TestTool_ConfigVolumesRemove_Readonly(t *testing.T) {
executor := mock.NewExecutor()

client, server, err := newTestPair(t, WithExecutor(executor))
if err != nil {
t.Fatal(err)
}
server.readonly.Store(true)

result, err := client.CallTool(t.Context(), &mcp.CallToolParams{
Name: "config_volumes_remove",
Arguments: map[string]any{"path": "."},
})
if err != nil {
t.Fatal(err)
}
if !result.IsError {
t.Fatal("expected error result in readonly mode, got success")
}
if executor.ExecuteInvoked {
t.Fatal("executor should not be invoked in readonly mode")
}
}
Loading