package mcpclient import ( "context" "os" "path/filepath" "strings" "testing" ) func TestFilesystemConfig(t *testing.T) { dir := t.TempDir() c := ServerConfig{Name: "Files", Transport: "filesystem", Enabled: true, Args: []string{dir}, TimeoutSeconds: 20, Command: "should-not-run", URL: "http://unused"} normalized, err := normalize(c) if err != nil || normalized.Command != "" || normalized.URL != "" { t.Fatalf("normalize: %+v %v", normalized, err) } for _, dirs := range [][]string{nil, {"relative"}} { c.Args = dirs if _, err := normalize(c); err == nil { t.Fatalf("accepted invalid roots %v", dirs) } } c.Args = []string{filepath.Join(dir, "missing")} if err := validateFilesystemDirs(c); err == nil { t.Fatal("accepted missing directory") } if err := validateSecrets(normalized, Secrets{Env: map[string]string{"NODE_OPTIONS": "--inspect"}}); err == nil { t.Fatal("accepted inherited config secrets") } s, _ := testService(t) view, err := s.SaveServer(ServerInput{Config: normalized}) if err != nil { t.Fatal(err) } restored := newService(s.path, memorySecrets{}) views, err := restored.ListServers() if err != nil || len(views) != 1 || views[0].Config.Args[0] != dir || views[0].Config.ID != view.Config.ID { t.Fatalf("restore: %+v %v", views, err) } } func TestBundledFilesystem(t *testing.T) { if os.Getenv("ITUOKE_TEST_FILESYSTEM") != "1" { t.Skip("set ITUOKE_TEST_FILESYSTEM=1 after staging official runtime") } t.Chdir(filepath.Join("..", "..")) t.Setenv("PATH", t.TempDir()) // No client-installed node/npm may be required. t.Setenv("NODE_OPTIONS", "--invalid-option-from-parent") s, _ := testService(t) view, err := s.AddFilesystem() if err != nil { t.Fatal(err) } second, err := s.AddFilesystem() if err != nil || second.Config.ID != view.Config.ID { t.Fatal("duplicate preset", err) } // Relocate the root to exercise spaces and Unicode paths. dir := filepath.Join(filepath.Dir(s.path), "产品资料 with spaces") if err := os.MkdirAll(dir, 0700); err != nil { t.Fatal(err) } view.Config.Args = []string{dir} if _, err := s.SaveServer(ServerInput{Config: view.Config}); err != nil { t.Fatal(err) } result := s.TestServer(context.Background(), ServerInput{Config: view.Config}) if !result.OK { t.Fatalf("discovery failed: %s", result.Message) } names := map[string]bool{} for _, tool := range result.Tools { names[tool.Name] = true } for _, tool := range []string{"read_text_file", "write_file", "search_files", "move_file", "list_allowed_directories"} { if !names[tool] { t.Fatalf("missing tool %s", tool) } } result = s.TestFilesystem(context.Background(), view.Config.ID) if !result.OK { t.Fatal(result.Message) } entries, err := os.ReadDir(dir) if err != nil || len(entries) != 0 { t.Fatalf("probe files remain: %v %v", entries, err) } raw, _ := os.ReadFile(s.path) if strings.Contains(string(raw), "node.exe") || strings.Contains(string(raw), "node_modules") { t.Fatal("machine-specific launch paths persisted") } t.Logf("official Filesystem MCP: %d tools; %s", len(result.Tools), result.Message) }