Filesystem MCP, czyli asystent czytający i piszący pliki
To najczęściej podłączany serwer w całym ekosystemie protokołu i zarazem ten o najwyższej stawce. Asystent mający dostęp do plików czyta kod, poprawia go, tworzy nowe pliki i przenosi rzeczy między katalogami.
Wygoda jest oczywista, a ryzyko wyższe niż przy dostępie do bazy danych czy do dokumentów. Pliki to jednocześnie kod źródłowy, klucze prywatne, pliki konfiguracyjne i wszystko inne, co leży na dysku.
Dobra wiadomość jest taka, że oficjalny serwer został zaprojektowany z myślą o tym ryzyku i ma sensowne zabezpieczenia. Zła jest taka, że najpoważniejsze zagrożenie leży poza nim i wynika z tego, jak działa cały układ. Do tego wrócę w osobnej sekcji.
Katalogi dozwolone
Podstawowym zabezpieczeniem jest lista katalogów, poza które serwer nie wyjdzie. Podajesz ją przy uruchomieniu.
{
"mcpServers": {
"pliki": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/anna/projekty/sklep"
]
}
}
}Ten jeden katalog jest całym światem, jaki asystent widzi. Próba odczytu czegokolwiek poza nim kończy się odmową, niezależnie od tego, jak zostanie sformułowana.
Drugą drogą jest przekazanie listy katalogów przez klienta, w mechanizmie przewidzianym w protokole. Wtedy klient wskazuje, nad czym akurat pracujesz, a serwer dostosowuje zakres. Warto wiedzieć, że lista przekazana przez klienta zastępuje tę podaną przy uruchomieniu, a nie dokłada się do niej.
Serwer uruchomiony bez żadnej z tych dwóch rzeczy nie wystartuje. To dobra decyzja projektowa, bo domyślny dostęp do całego dysku byłby najgorszym możliwym ustawieniem początkowym.
Praktyczna zasada: wskazuj konkretny projekt, a nie katalog domowy. Różnica polega na tym, że w katalogu domowym leżą klucze, pliki konfiguracyjne z hasłami i historia poleceń, a w katalogu projektu leży projekt.
Ochrona przed wyjściem poza zakres
Sama lista katalogów nie wystarczy, bo ścieżkę da się zapisać na wiele sposobów. Serwer obsługuje to na kilku poziomach.
Ścieżki są sprowadzane do postaci kanonicznej przed sprawdzeniem, więc odwołania cofające o katalog w górę nie prowadzą poza dozwolony obszar. To najprostszy sposób obejścia i zarazem najlepiej pokryty.
Dowiązania symboliczne są sprawdzane pod kątem tego, gdzie faktycznie prowadzą. Dowiązanie leżące w dozwolonym katalogu, ale wskazujące na katalog domowy, zostanie odrzucone. Odrzucane są też dowiązania prowadzące donikąd.
To rozwiązuje kategorię problemów, która przy własnej implementacji jest najczęstszym źródłem błędów, bo sprawdzenie ścieżki przed rozwiązaniem dowiązania wygląda na poprawne i takie nie jest.
Warto natomiast rozumieć granicę tej ochrony. Zabezpieczenia dotyczą tego, gdzie asystent sięga, a nie tego, co robi w obrębie dozwolonego katalogu. Wewnątrz wskazanego projektu może nadpisać dowolny plik, i to jest zachowanie zamierzone.
Prawdziwe ryzyko
Ta sekcja jest najważniejsza w całym tekście, bo dotyczy zagrożenia, którego opisane wyżej zabezpieczenia nie obejmują.
Model wywołuje narzędzia na podstawie tego, co przeczytał. Jeśli w kontekście znajdzie się tekst sformułowany jak polecenie, model może go wykonać, nie odróżniając instrukcji od danych.
W układzie z jednym narzędziem to ograniczone ryzyko. Problem zaczyna się przy kilku narzędziach naraz, a taki układ jest typowy. Asystent mający dostęp do plików oraz do pobierania stron internetowych może przeczytać stronę zawierającą ukrytą instrukcję i wykonać ją na Twoich plikach.
Scenariusz nie jest hipotetyczny i został opisany przez badaczy bezpieczeństwa. Wystarczy, że model pobierze zewnętrzną treść, w której ktoś umieścił polecenie odczytania określonego pliku i wysłania go gdzieś. Odczyt mieści się w dozwolonym katalogu, więc żadne zabezpieczenie serwera się nie uruchamia.
To samo dotyczy treści pochodzącej z bliższych źródeł: zgłoszenia od użytkownika, komentarza w kodzie, pliku z zależnościami pobranego z zewnątrz. Wszystko, co model przeczyta, może wpłynąć na to, co zrobi dalej.
Trzy rzeczy ograniczają to ryzyko realnie. Pierwsza to wąski katalog, bo ogranicza szkodę niezależnie od tego, co model zostanie nakłoniony zrobić. Druga to zatwierdzanie operacji zapisu, zamiast pozwalania na nie samodzielnie. Trzecia to nieumieszczanie w dozwolonym katalogu rzeczy, których nie chcesz stracić ani ujawnić: kluczy, plików konfiguracyjnych z hasłami i kopii bazy danych.
Czwarta, najskuteczniejsza przy poważnej pracy: rozdzielenie narzędzi. Asystent czytający treści z zewnątrz i asystent mający dostęp do plików to bezpieczniejszy układ jako dwie osobne sesje niż jako jedna z obydwoma narzędziami.
Co potrafi
Zestaw narzędzi jest przewidywalny i warto go znać, bo od niego zależy, czego wymagać przy zatwierdzaniu.
Odczyt obejmuje pojedynczy plik oraz wiele plików w jednym wywołaniu, co przy przeglądaniu projektu jest wyraźnie szybsze. Dostępne jest też listowanie katalogów i przechodzenie drzewa katalogów.
Zapis obejmuje tworzenie plików, nadpisywanie oraz edycję opartą na zamianie fragmentów, z podglądem zmian przed wykonaniem. Ta ostatnia jest najbezpieczniejszą formą, bo zmienia wskazany fragment zamiast nadpisywać całość, więc pomyłka nie kasuje reszty pliku.
Dostępne jest również przenoszenie, tworzenie katalogów i wyszukiwanie plików po nazwie, wzorcem dopasowywanym do całej ścieżki. Wyszukiwania po zawartości plików serwer nie ma, więc odnalezienie wszystkich miejsc z daną nazwą wymaga otwarcia plików albo osobnego narzędzia.
Warto zwrócić uwagę na jedną rzecz przy edycji. Zamiana fragmentu nie sprawdza, czy fragment występuje w pliku tylko raz. Podmieniane jest pierwsze wystąpienie, bez ostrzeżenia, a operacja kończy się błędem dopiero wtedy, gdy nie ma żadnego dopasowania. Dlatego fragment do zamiany warto podawać na tyle długi, żeby był jednoznaczny, i korzystać z podglądu zmian przed zapisem, bo to jedyne zabezpieczenie przed zmianą w niewłaściwym miejscu.
Duże pliki i kontekst
Problem praktyczny, mniej groźny od poprzedniego i spotykany codziennie: pliki, które nie mieszczą się w kontekście modelu.
Plik na trzy tysiące linii to kilkadziesiąt tysięcy tokenów. Wczytanie trzech takich plików wypełnia znaczną część dostępnego miejsca, a model musi jeszcze pomieścić polecenie, historię rozmowy i odpowiedź.
Objawy bywają mylące. Model odpowiada na podstawie fragmentu, nie sygnalizując, że reszty nie widział, albo poprawnie opisuje początek pliku i pomija funkcję zdefiniowaną na końcu. Przy edycji jest gorzej: propozycja zmiany oparta na niepełnym obrazie potrafi zepsuć rzecz, której model nie widział.
Trzy nawyki ograniczają ten problem. Pierwszy to wskazywanie konkretnych plików zamiast pozwalania asystentowi na przeglądanie całego drzewa. Drugi to odczyt fragmentu zamiast całości tam, gdzie interesuje Cię jedna funkcja. Trzeci to praca na mniejszych plikach, co i tak jest dobrą praktyką z innych powodów.
Przy większych projektach warto też pamiętać, że odnalezienie właściwych plików po nazwie jest tańsze niż wczytywanie ich po kolei. Skoro serwer nie zagląda do środka, szukanie miejsc, w których występuje dana nazwa, wykonaj narzędziem spoza niego, a asystentowi podaj do odczytu dopiero znalezione pliki.
Praca z repozytorium
Kilka rzeczy, które przy pracy nad kodem zmieniają układ z ryzykownego na kontrolowany.
Zacznij od czystego stanu w systemie kontroli wersji. Wszystkie Twoje zmiany zatwierdzone, katalog roboczy bez modyfikacji. Wtedy każda zmiana, która pojawi się później, pochodzi od asystenta i jest widoczna w różnicy.
Przeglądaj różnicę, a nie opis zmian. Asystent podsumowuje, co zrobił, i to podsumowanie bywa poprawne oraz niepełne. Różnica pokazuje wszystko, łącznie z rzeczami, o których nie wspomniał.
Zatwierdzaj małymi porcjami. Jedno polecenie, jeden przegląd, jedno zatwierdzenie. Trzy polecenia pod rząd bez przeglądu dają zmianę obejmującą dwadzieścia plików, w której trudno odróżnić to, co chciałeś, od tego, co przy okazji.
Zwróć uwagę na pliki, których asystent nie powinien ruszać. Pliki blokujące wersje zależności, konfiguracja narzędzi budowania i pliki wygenerowane automatycznie bywają modyfikowane przy okazji, a zmiana w nich potrafi zepsuć budowanie w sposób trudny do wytropienia.
Znaj też granicę zakresu tego serwera. Widzi pliki na dysku, a nie repozytorium: historii zmian, zgłoszeń ani propozycji zmian stąd nie odczytasz, bo te leżą po stronie API. Do nich służy serwer GitHuba, który dzieli narzędzia na zestawy i ma osobny tryb tylko do odczytu. Przy pracy nad kodem oba bywają podłączone naraz i wtedy warto pamiętać, że różnicę w kodzie przeglądasz lokalnie, a nie przez API.
Ostatnia rzecz: nie trzymaj w katalogu projektu pliku ze zmiennymi środowiskowymi zawierającego prawdziwe klucze. Nawet jeśli jest wyłączony z kontroli wersji, dla asystenta jest zwykłym plikiem w dozwolonym katalogu.
Serwer plikowy kontra alternatywy
| Rozwiązanie | Mocna strona | Słabość | Kiedy wybrać |
|---|---|---|---|
| Serwer oficjalny | Sprawdzone zabezpieczenia ścieżek, aktywnie utrzymywany | Zapis bez potwierdzenia, jeśli klient go nie wymaga | Praca z plikami projektu |
| Asystent w edytorze | Kontekst projektu, przegląd zmian przed zapisem | Działa wyłącznie w tym edytorze | Codzienna praca nad kodem |
| Serwery społecznościowe | Więcej operacji, obsługa dużych plików | Cudzy kod z dostępem do dysku | Nietypowe wymagania |
| Kontener z zamontowanym katalogiem | Izolacja od reszty systemu | Więcej konfiguracji | Praca z kodem z nieznanego źródła |
Drugi wiersz bywa pomijany, a przy pracy nad kodem jest zwykle lepszym wyborem. Narzędzia takie jak Cursor mają dostęp do plików wbudowany, pokazują zmiany przed zapisem i działają w kontekście projektu, więc dokładanie osobnego serwera niewiele wnosi.
Ostatni wiersz warto rozważyć przy pracy z kodem, którego nie znasz. Uruchomienie asystenta w kontenerze z zamontowanym jednym katalogiem sprawia, że nawet wykonanie złośliwej instrukcji ogranicza się do tego katalogu, bez dostępu do reszty systemu.
Bezpieczna konfiguracja
Podsumowanie w formie listy, bo to jest część, do której warto wracać.
Wskaż konkretny katalog projektu, nigdy katalog domowy ani katalog główny. Sprawdź, czy w tym katalogu nie leży plik z danymi dostępowymi, bo to najczęstsze przeoczenie.
Włącz zatwierdzanie operacji zapisu w kliencie, jeśli je oferuje. Odczyt może działać samodzielnie, zapis raczej nie.
Nie łącz w jednej sesji dostępu do plików z narzędziami pobierającymi treść z zewnątrz. To najprostszy sposób ograniczenia najpoważniejszego ryzyka i nic nie kosztuje.
Trzymaj projekt w systemie kontroli wersji z zatwierdzonymi zmianami przed rozpoczęciem pracy. Wtedy każda zmiana wprowadzona przez asystenta jest widoczna w różnicy i odwracalna jednym poleceniem.
Przejrzyj zmiany przed zatwierdzeniem, nawet jeśli asystent twierdzi, że zrobił dokładnie to, o co prosiłeś. To ta sama zasada co przy przeglądzie cudzego kodu i z tego samego powodu.
Typowe błędy
Pierwszy to wskazanie katalogu domowego jako dozwolonego. Leżą tam klucze, pliki konfiguracyjne z hasłami i historia poleceń, czyli dokładnie to, czego asystent nie powinien widzieć.
Drugi to łączenie dostępu do plików z pobieraniem treści z zewnątrz w jednej sesji. To najczęściej opisywana droga do wykonania cudzej instrukcji na Twoich plikach.
Trzeci to pozwalanie na zapis bez potwierdzenia. Odczyt jest odwracalny, nadpisanie pliku niekoniecznie.
Czwarty to praca bez systemu kontroli wersji. Bez niego zmiana wprowadzona przez asystenta jest nie do odróżnienia od Twojej i nie do cofnięcia.
Piąty to zakładanie, że zabezpieczenia serwera obejmują wszystko. Dotyczą tego, gdzie asystent sięga, a nie tego, co robi wewnątrz dozwolonego katalogu.
Szósty to uruchamianie serwera społecznościowego z dostępem do dysku bez przeglądu kodu. Zasady z tekstu o katalogu serwerów obowiązują tu w podwójnym stopniu, bo stawka jest najwyższa w całym ekosystemie.
Siódmy to trzymanie w katalogu projektu pliku z prawdziwymi kluczami. Wyłączenie go z kontroli wersji nie zmienia nic, bo dla asystenta jest zwykłym plikiem w dozwolonym obszarze.
FAQ
Czy asystent może wyjść poza wskazany katalog?
Nie przez ścieżkę. Serwer sprowadza ścieżki do postaci kanonicznej, blokuje odwołania cofające w górę i sprawdza, dokąd prowadzą dowiązania symboliczne. Może natomiast zrobić dowolną rzecz wewnątrz dozwolonego katalogu, i to jest zachowanie zamierzone.
Na czym polega największe ryzyko?
Na tym, że model wykonuje instrukcje znalezione w treści, którą przeczytał. Przy jednoczesnym dostępie do plików i do pobierania stron zewnętrznych ktoś może umieścić w treści polecenie odczytania pliku i wysłania go dalej, a serwer nie ma powodu tego zablokować.
Jak się przed tym zabezpieczyć?
Wąski katalog, zatwierdzanie operacji zapisu i nieumieszczanie w dozwolonym obszarze rzeczy wrażliwych. Najskuteczniejsze jest jednak rozdzielenie: nie łącz w jednej sesji dostępu do plików z narzędziami czytającymi treść z zewnątrz.
Czy to lepsze niż asystent wbudowany w edytor?
Przy pracy nad kodem zwykle nie. Narzędzia takie jak Cursor mają dostęp do plików wbudowany, pokazują zmiany przed zapisem i rozumieją kontekst projektu. Osobny serwer plikowy przydaje się tam, gdzie pracujesz poza edytorem.
Czy warto uruchamiać to w kontenerze?
Przy pracy z kodem z nieznanego źródła zdecydowanie tak. Kontener z zamontowanym jednym katalogiem sprawia, że nawet wykonanie złośliwej instrukcji ogranicza się do tego katalogu, bez dostępu do reszty systemu.
Kod i dokumentacja stoją w repozytorium serwerów protokołu, a pakiet znajdziesz w rejestrze npm.