Files
kit/cmd/script_integration_test.go
T
Ed Zynda 7fc94018a9 rename: fork mcphost to kit (github.com/mark3labs/kit)
Rename the entire project from mcphost to kit, including:
- Go module path and all import paths
- SDK type MCPHost -> Kit, file renames mcphost.go -> kit.go
- CLI command name, usage strings, UI labels (KIT in literature)
- Config paths (.mcphost -> .kit), env prefix (MCPHOST_ -> KIT_)
- Data/credential/hooks directory paths
- Remove legacy .mcp config fallbacks
- Session metadata field (mcphost_version -> kit_version)
- MCP client identity name
- Build output, goreleaser binary name
- All documentation, examples, scripts, and test files
2026-02-26 16:59:59 +03:00

285 lines
8.0 KiB
Go

package cmd
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestScriptWithEnvAndArgsSubstitution(t *testing.T) {
// Create a temporary script file with both env vars and script args
tempDir := t.TempDir()
scriptPath := filepath.Join(tempDir, "test-script.sh")
scriptContent := `#!/usr/bin/env -S kit script
---
mcpServers:
github:
type: local
command: ["gh", "api"]
environment:
GITHUB_TOKEN: "${env://GITHUB_TOKEN}"
DEBUG: "${env://DEBUG:-false}"
filesystem:
type: builtin
name: fs
options:
allowed_directories: ["${env://WORK_DIR:-/tmp}"]
model: "${env://MODEL:-anthropic/claude-sonnet-4-5-20250929}"
debug: ${env://DEBUG:-false}
---
List ${repo_type:-public} repositories for user ${username}.
Use the GitHub API to fetch ${count:-10} repositories.
Working directory is ${env://WORK_DIR:-/tmp}.
`
err := os.WriteFile(scriptPath, []byte(scriptContent), 0644)
if err != nil {
t.Fatalf("Failed to write test script: %v", err)
}
// Set up environment variables
_ = os.Setenv("GITHUB_TOKEN", "ghp_test_token")
_ = os.Setenv("DEBUG", "true")
_ = os.Setenv("WORK_DIR", "/home/user/projects")
defer func() {
_ = os.Unsetenv("GITHUB_TOKEN")
_ = os.Unsetenv("DEBUG")
_ = os.Unsetenv("WORK_DIR")
}()
// Set up script arguments
variables := map[string]string{
"username": "alice",
"repo_type": "private",
}
// Parse the script
scriptConfig, err := parseScriptFile(scriptPath, variables)
if err != nil {
t.Fatalf("Failed to parse script: %v", err)
}
// Verify environment variable substitution in MCP servers
githubServer, exists := scriptConfig.MCPServers["github"]
if !exists {
t.Fatal("GitHub server not found in script config")
}
if githubServer.Environment["github_token"] != "ghp_test_token" {
t.Errorf("Expected github_token=ghp_test_token, got %s", githubServer.Environment["github_token"])
}
if githubServer.Environment["debug"] != "true" {
t.Errorf("Expected debug=true, got %s", githubServer.Environment["debug"])
}
// Verify environment variable substitution in builtin server options
fsServer, exists := scriptConfig.MCPServers["filesystem"]
if !exists {
t.Fatal("Filesystem server not found in script config")
}
allowedDirs, ok := fsServer.Options["allowed_directories"].([]any)
if !ok {
t.Fatal("allowed_directories should be an array")
}
if len(allowedDirs) != 1 || allowedDirs[0] != "/home/user/projects" {
t.Errorf("Expected allowed_directories=[/home/user/projects], got %v", allowedDirs)
}
// Verify global config values
if scriptConfig.Model != "anthropic/claude-sonnet-4-5-20250929" {
t.Errorf("Expected model=anthropic/claude-sonnet-4-5-20250929, got %s", scriptConfig.Model)
}
if !scriptConfig.Debug {
t.Error("Expected debug=true")
}
// Verify script args substitution in prompt
expectedPrompt := `List private repositories for user alice.
Use the GitHub API to fetch 10 repositories.
Working directory is /home/user/projects.`
if strings.TrimSpace(scriptConfig.Prompt) != strings.TrimSpace(expectedPrompt) {
t.Errorf("Expected prompt:\n%s\nGot:\n%s", expectedPrompt, scriptConfig.Prompt)
}
}
func TestScriptWithMissingRequiredEnvVar(t *testing.T) {
// Create a script with a required environment variable
tempDir := t.TempDir()
scriptPath := filepath.Join(tempDir, "test-script.sh")
scriptContent := `#!/usr/bin/env -S kit script
---
mcpServers:
github:
type: local
command: ["gh", "api"]
environment:
GITHUB_TOKEN: "${env://REQUIRED_TOKEN}"
---
Test script with required env var.
`
err := os.WriteFile(scriptPath, []byte(scriptContent), 0644)
if err != nil {
t.Fatalf("Failed to write test script: %v", err)
}
// Make sure the environment variable is not set
_ = os.Unsetenv("REQUIRED_TOKEN")
// Parse the script - should fail
variables := map[string]string{}
_, err = parseScriptFile(scriptPath, variables)
if err == nil {
t.Fatal("Expected error for missing required environment variable")
}
if !strings.Contains(err.Error(), "required environment variable REQUIRED_TOKEN not set") {
t.Errorf("Expected error about missing REQUIRED_TOKEN, got: %v", err)
}
}
func TestScriptWithMissingRequiredArg(t *testing.T) {
// Create a script with a required script argument
tempDir := t.TempDir()
scriptPath := filepath.Join(tempDir, "test-script.sh")
scriptContent := `#!/usr/bin/env -S kit script
---
mcpServers:
github:
type: local
command: ["gh", "api"]
environment:
GITHUB_TOKEN: "${env://GITHUB_TOKEN:-default_token}"
---
List repositories for user ${required_username}.
`
err := os.WriteFile(scriptPath, []byte(scriptContent), 0644)
if err != nil {
t.Fatalf("Failed to write test script: %v", err)
}
// Parse the script without providing the required argument
variables := map[string]string{}
_, err = parseScriptFile(scriptPath, variables)
if err == nil {
t.Fatal("Expected error for missing required script argument")
}
if !strings.Contains(err.Error(), "required_username") {
t.Errorf("Expected error about missing required_username, got: %v", err)
}
}
func TestScriptProcessingOrder(t *testing.T) {
// Test that env substitution happens before args substitution
tempDir := t.TempDir()
scriptPath := filepath.Join(tempDir, "test-script.sh")
// This script tests that env vars are processed first, then script args
scriptContent := `#!/usr/bin/env -S kit script
---
mcpServers:
test:
type: local
command: ["echo", "${env://BASE_PATH:-/tmp}/${path_suffix}"]
---
Base path is ${env://BASE_PATH:-/tmp} and suffix is ${path_suffix:-default}.
`
err := os.WriteFile(scriptPath, []byte(scriptContent), 0644)
if err != nil {
t.Fatalf("Failed to write test script: %v", err)
}
// Set environment variable
_ = os.Setenv("BASE_PATH", "/home/user")
defer func() { _ = os.Unsetenv("BASE_PATH") }()
// Set script argument
variables := map[string]string{
"path_suffix": "documents",
}
// Parse the script
scriptConfig, err := parseScriptFile(scriptPath, variables)
if err != nil {
t.Fatalf("Failed to parse script: %v", err)
}
// Verify that both substitutions worked correctly
testServer := scriptConfig.MCPServers["test"]
expectedCommand := []string{"echo", "/home/user/documents"}
if len(testServer.Command) != len(expectedCommand) {
t.Errorf("Expected command length %d, got %d", len(expectedCommand), len(testServer.Command))
}
for i, expected := range expectedCommand {
if i < len(testServer.Command) && testServer.Command[i] != expected {
t.Errorf("Expected command[%d] = %s, got %s", i, expected, testServer.Command[i])
}
}
// Verify prompt substitution
expectedPrompt := "Base path is /home/user and suffix is documents."
if strings.TrimSpace(scriptConfig.Prompt) != expectedPrompt {
t.Errorf("Expected prompt: %s\nGot: %s", expectedPrompt, strings.TrimSpace(scriptConfig.Prompt))
}
}
func TestScriptBackwardCompatibility(t *testing.T) {
// Test that existing scripts without env vars still work
tempDir := t.TempDir()
scriptPath := filepath.Join(tempDir, "test-script.sh")
scriptContent := `#!/usr/bin/env -S kit script
---
mcpServers:
filesystem:
type: builtin
name: fs
options:
allowed_directories: ["/tmp"]
model: "anthropic/claude-sonnet-4-5-20250929"
---
List files in ${directory:-/tmp} for user ${username}.
`
err := os.WriteFile(scriptPath, []byte(scriptContent), 0644)
if err != nil {
t.Fatalf("Failed to write test script: %v", err)
}
// Set script arguments
variables := map[string]string{
"username": "bob",
}
// Parse the script
scriptConfig, err := parseScriptFile(scriptPath, variables)
if err != nil {
t.Fatalf("Failed to parse script: %v", err)
}
// Verify that script args substitution still works
expectedPrompt := "List files in /tmp for user bob."
if strings.TrimSpace(scriptConfig.Prompt) != expectedPrompt {
t.Errorf("Expected prompt: %s\nGot: %s", expectedPrompt, strings.TrimSpace(scriptConfig.Prompt))
}
// Verify that config is unchanged
if scriptConfig.Model != "anthropic/claude-sonnet-4-5-20250929" {
t.Errorf("Expected model unchanged, got %s", scriptConfig.Model)
}
}