Skip to main content
Glama

Portainer MCP

Official
by portainer
zlib License
67
  • Linux
  • Apple
stack_test.go6.41 kB
package integration import ( "encoding/json" "fmt" "testing" mcpmodels "github.com/mark3labs/mcp-go/mcp" "github.com/portainer/portainer-mcp/internal/mcp" "github.com/portainer/portainer-mcp/pkg/portainer/models" "github.com/portainer/portainer-mcp/tests/integration/helpers" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) const ( testStackName = "test-mcp-stack" testStackFile = "version: '3'\nservices:\n web:\n image: nginx:latest" testStackFileUpdated = "version: '3'\nservices:\n web:\n image: nginx:alpine" testEdgeGroupName = "test-stack-group" ) // prepareStackManagementTestEnvironment creates a test environment group needed for stack tests func prepareStackManagementTestEnvironment(t *testing.T, env *helpers.TestEnv) int { // First, enable Edge features in Portainer host, port := env.Portainer.GetHostAndPort() serverAddr := fmt.Sprintf("%s:%s", host, port) tunnelAddr := fmt.Sprintf("%s:8000", host) err := env.RawClient.UpdateSettings(true, serverAddr, tunnelAddr) require.NoError(t, err, "Failed to update settings to enable Edge features") // Create a test environment group for the stack to be associated with testGroupID, err := env.RawClient.CreateEdgeGroup(testEdgeGroupName, []int64{}) require.NoError(t, err, "Failed to create test environment group via raw client") return int(testGroupID) } // TestStackManagement is an integration test suite that verifies the complete // lifecycle of stack management in Portainer MCP. It tests stack creation, // retrieval, file content retrieval, and updates. func TestStackManagement(t *testing.T) { env := helpers.NewTestEnv(t) defer env.Cleanup(t) // Prepare the test environment testGroupID := prepareStackManagementTestEnvironment(t, env) var testStackID int // Subtest: Stack Creation // Verifies that: // - A new stack can be created via the MCP handler // - The handler response indicates success with an ID // - The created stack exists in Portainer when checked directly via Raw Client t.Run("Stack Creation", func(t *testing.T) { handler := env.MCPServer.HandleCreateStack() request := mcp.CreateMCPRequest(map[string]any{ "name": testStackName, "file": testStackFile, "environmentGroupIds": []any{float64(testGroupID)}, }) result, err := handler(env.Ctx, request) require.NoError(t, err, "Failed to create stack via MCP handler") textContent, ok := result.Content[0].(mcpmodels.TextContent) require.True(t, ok, "Expected text content in MCP response") // Check for success message and extract ID for later tests assert.Contains(t, textContent.Text, "Stack created successfully with ID:", "Success message prefix mismatch") // Verify by fetching stacks directly via client and finding the created stack by name stack, err := env.RawClient.GetEdgeStackByName(testStackName) require.NoError(t, err, "Failed to get stack directly via client after creation") assert.Equal(t, testStackName, stack.Name, "Stack name mismatch") // Extract stack ID for subsequent tests testStackID = int(stack.ID) }) // Subtest: Stack Listing // Verifies that: // - The stack list can be retrieved via the MCP handler // - The list contains the expected stack // - The stack data matches the expected properties t.Run("Stack Listing", func(t *testing.T) { handler := env.MCPServer.HandleGetStacks() result, err := handler(env.Ctx, mcp.CreateMCPRequest(nil)) require.NoError(t, err, "Failed to get stacks via MCP handler") assert.Len(t, result.Content, 1, "Expected exactly one content block in the result") textContent, ok := result.Content[0].(mcpmodels.TextContent) assert.True(t, ok, "Expected text content in MCP response") var retrievedStacks []models.Stack err = json.Unmarshal([]byte(textContent.Text), &retrievedStacks) require.NoError(t, err, "Failed to unmarshal retrieved stacks") require.Len(t, retrievedStacks, 1, "Expected exactly one stack after unmarshalling") stack := retrievedStacks[0] assert.Equal(t, testStackName, stack.Name, "Stack name mismatch") // Fetch the same stack directly via the client rawStack, err := env.RawClient.GetEdgeStack(int64(testStackID)) require.NoError(t, err, "Failed to get stack directly via client") // Convert the raw stack to the expected Stack model expectedStack := models.ConvertEdgeStackToStack(rawStack) assert.Equal(t, expectedStack, stack, "Stack mismatch between MCP handler and direct client call") }) // Subtest: Get Stack File // Verifies that: // - The stack file can be retrieved via the MCP handler // - The file content matches the content used during creation t.Run("Get Stack File", func(t *testing.T) { handler := env.MCPServer.HandleGetStackFile() request := mcp.CreateMCPRequest(map[string]any{ "id": float64(testStackID), }) result, err := handler(env.Ctx, request) require.NoError(t, err, "Failed to get stack file via MCP handler") textContent, ok := result.Content[0].(mcpmodels.TextContent) require.True(t, ok, "Expected text content in MCP response") // Compare with the original content assert.Equal(t, testStackFile, textContent.Text, "Stack file content mismatch") }) // Subtest: Stack Update // Verifies that: // - A stack can be updated via the MCP handler // - The handler response indicates success // - The stack file is updated when checked directly via Raw Client t.Run("Stack Update", func(t *testing.T) { handler := env.MCPServer.HandleUpdateStack() request := mcp.CreateMCPRequest(map[string]any{ "id": float64(testStackID), "file": testStackFileUpdated, "environmentGroupIds": []any{float64(testGroupID)}, }) result, err := handler(env.Ctx, request) require.NoError(t, err, "Failed to update stack via MCP handler") textContent, ok := result.Content[0].(mcpmodels.TextContent) require.True(t, ok, "Expected text content in MCP response") assert.Contains(t, textContent.Text, "Stack updated successfully", "Success message mismatch") // Verify by fetching stack file directly via raw client updatedFile, err := env.RawClient.GetEdgeStackFile(int64(testStackID)) require.NoError(t, err, "Failed to get stack file via raw client after update") assert.Equal(t, testStackFileUpdated, updatedFile, "Stack file was not updated correctly") }) }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/portainer/portainer-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server