Strona główna / Artykuły / Wskazówki praktyczne: Przepis Spring AI: Zabezpieczanie serwera MCP za pomocą OAuth

Wskazówki praktyczne: Przepis Spring AI: Zabezpieczanie serwera MCP za pomocą OAuth

Praktyczne wskazówki: Przepis Spring AI – zabezpieczanie serwera MCP za pomocą OAuth: umowy, sprawdzania oraz gotowe fragmenty kodu dla zespołów wdrażających ten wzorzec.

1607 słów

Poniższe notatki przedstawiają praktyczny plan działania dotyczący tematu „Spring AI Recipe: Zabezpieczanie serwera MCP za pomocą OAuth”. Nacisk kładziony jest na umowy, sprawdzania oraz miejsca na kod do wstawienia, a nie na motywacyjne aspekty. Podczas przechodzenia przez etap przeglądu najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Trzymaj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury.

Tworzenie serwera autoryzacji

Etap tworzenia serwera autoryzacji działa najlepiej, gdy traktuje się go jako mierzalną powierzchnię do analizy. Zapisz jeden idealny przypadek działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres.

implementation 'org.springaicommunity:mcp-authorization-server:0.1.14'
@Configuration
@EnableWebSecurity
public class SecurityConfig {

  @Bean
  SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .authorizeHttpRequests(auth ->
            auth.anyRequest().authenticated())
        .formLogin(withDefaults())
        .with(
            McpAuthorizationServerConfigurer.mcpAuthorizationServer(),
            withDefaults())
        .build();
  }

}
spring:
  application:
    name: recipes-authorization-server
  security:
    oauth2:
      authorizationserver:
        client:
          default-client:
            token:
              access-token-time-to-live: 1h
            registration:
              client-id: "myclient"
              client-secret: "{noop}mysecret"
              client-authentication-methods:
                - "client_secret_basic"
              authorization-grant-types:
                - "authorization_code"
              redirect-uris:
                - "http://localhost:6274/oauth/callback"
                - "http://127.0.0.1:6274/oauth/callback"
              scopes:
                - general-access
                - meteorology
                - administration
    user:
      name: craig
      password: letmein

server:
  port: 9999

Zabezpieczanie serwera MCP

Etap zabezpieczania serwera MCP działa najlepiej, gdy traktuje się go jako mierzalną powierzchnię do analizy. Zapisz jeden idealny przykład działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres pracy. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok zawiedzie, awaria powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Używaj narzędzi o wąskich schematach i wyraźnych oznaczeniach efektów ubocznych. Hostowie muszą wiedzieć, które wywołania zmieniają stan systemu, zanim automatycznie je zatwierdzą.

implementation 'org.springaicommunity:mcp-server-security:0.1.14'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9999
@Configuration
@EnableWebSecurity
class McpSecurityConfig {

  @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
  private String issuerUrl;

  @Bean
  SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .authorizeHttpRequests(auth ->
            auth.anyRequest().authenticated())
        .with(
            McpServerOAuth2Configurer.mcpServerOAuth2(),
            (mcpAuthorization) -> {
              mcpAuthorization.authorizationServer(issuerUrl);
            }
        )
        .build();
  }

}

Testowanie serwera MCP

Etap testowania serwera MCP funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia do analizy. Zapisz jeden idealny przepis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres testów. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań. Używaj narzędzi o wąskich schematach i wyraźnych oznaczeniach efektów ubocznych. Hostowie muszą wiedzieć, które wywołania zmieniają stan systemu, zanim automatycznie je zatwierdzą. Etap testowania serwera MCP funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia do analizy. Zapisz jeden idealny przepis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres testów. Przechowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, składysek z danymi poufnymi oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury.

Zabezpieczanie poszczególnych narzędzi

W fazie zabezpieczania poszczególnych narzędzi należy określić dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu.

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
class SecurityConfig {

  @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
  private String issuerUrl;

  @Bean
  SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .authorizeHttpRequests(auth -> {
          auth.requestMatchers("/mcp").permitAll();
          auth.anyRequest().authenticated();
        })
        .with(
            McpServerOAuth2Configurer.mcpServerOAuth2(),
            (mcpAuthorization) -> {
              mcpAuthorization.authorizationServer(issuerUrl);
            }
        )
        .build();
  }

}
@PreAuthorize("hasAuthority('SCOPE_meteorology')")
@McpTool(
    name = "get-weather-for-zipcode",
    description = "Gets the weather for a given zipcode",
    annotations = @McpTool.McpAnnotations(
        openWorldHint = false,
        destructiveHint = false,
        idempotentHint = true))
Weather getWeatherForZipcode(
    @McpToolParam(description = "The zipcode to get weather for")
    String zipcode) {
  var context = SecurityContextHolder.getContext();
  var username = context.getAuthentication().getName();
  return new Weather(
      zipcode,
      "Raining cats and dogs",
      78.0f,
      username);
}

Lista kontrolna operacyjna

W fazie listy kontrolnej operacyjnej należy określić dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu.

Zapisuj czas wykonywania operacji oraz koszt tokena lub zapytania obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk.

Zaloguj się przy bramce i ponownie udziel uprawnień na poziomie warstwy danych. Sam token nie stanowi granicy między poszczególnymi użytkownikami.

Napisz krótki przewodnik: jak rotować klucze, jak opróżniać kolejki zadań, jak cofnąć ostatni proces importu.

Zachowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności przeglądania całej struktury.

Zaloguj się przy bramce i ponownie udziel uprawnień na poziomie warstwy danych. Sam token nie stanowi granicy między poszczególnymi użytkownikami.

Zanim wdrożysz cały zestaw narzędzi, zamroź wersje, utwórz dokładny zapis dla kluczowych etapów realizacji oraz potwierdź kroki odwracania zmian. Środowiska współdzielone wymagają ograniczeń szybkości działania, weryfikacji uprawnień użytkowników oraz wyraźnego właściciela odpowiedzialnego za rotację haseł. Wolimy nudną niezawodność od pomysłowych, jednorazowych demonstracji.

Uwaga dotycząca procesu 01496ca9e17e: unikaj przechowywania kluczy dostawcy w repozytorium, ustaw ograniczenie liczby tokenów na sesję oraz przechowuj zapisy obok plików testowych, aby późniejsze zmiany modeli pozostawały porównywalne.

Dla etapu 0 związkiego z wzmocnieniem bezpieczeństwa określ wcześniej dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu systemu. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań.

Szczegół wzmocnienia 0/819: zmierz czas wykonywania, klasę błędu oraz zużycie tokenów dla tej notatki, a następnie zdecyduj, czy zachować zmianę na podstawie ustalonego zestawu pytań, a nie jedynie anegdoty.

Podczas przechodzenia przez pierwszy etap notatki dotyczącej wzmocnienia, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Trzymaj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury.

Szczegół wzmocnienia 1/819: zmierz czas wykonywania, klasę błędu oraz zużycie tokenów dla tej notatki, a następnie zdecyduj, czy zachować zmianę na podstawie ustalonego zestawu pytań, a nie jedynie anegdoty.

Druga faza notatki dotyczącej wzmocnienia bezpieczeństwa działa najlepiej, gdy traktuje się ją jako mierzalną powierzchnię. Zapisz jeden idealny przypadek działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmiany, zanim rozszerzysz zakres prac. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakaś etap zawiedzie, awaria powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji.

Szczegół wzmocnienia bezpieczeństwa 2/819: zmierz czas wykonywania, klasę błędu oraz zużycie tokenów dla tej notatki, a następnie zdecyduj, czy zachować zmianę, opierając się na ustalonej serii pytań, a nie na anegdotach.

Dla trzeciego etapu ulepszeń związanych z wzmocnieniem bezpieczeństwa należy określić dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie wykonać ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu systemu. Należy rejestrować czas wykonywania operacji oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do współdzielonych środowisk.

Szczegóły ulepszenia nr 3/819: należy zmierzyć czas wykonywania operacji, klasę błędów oraz zużycie tokenów dla tego etapu, a następnie zdecydować o utrzymaniu zmiany na podstawie ustalonego zestawu kryteriów, a nie jedynie informacji anegdotycznych.

Gdy przechodzisz przez etap nr 4 notatki dotyczącej wzmocnienia bezpieczeństwa, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego awarii. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zdokumentuj zarówno prawidłowy przebieg działania, jak i ścieżkę odzyskiwania. Próby ponownych działań, kontrola przez ludzi oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później.

Szczegół nr 4/819 dotyczący wzmocnienia bezpieczeństwa: zmierz czas wykonywania operacji, klasę błędu oraz zużycie tokenów dla tej notatki, a następnie zdecyduj, czy zachować zmianę na podstawie ustalonego zestawu pytań, a nie jedynie informacji anegdotycznych.

Etap nr 5 notatki dotyczącej wzmocnienia bezpieczeństwa działa najlepiej, gdy traktuje się go jako mierzalną powierzchnię do analizy. Zapisz jeden idealny przepływ działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres prac. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzuć przypadki cichego, częściowego ukończenia zadania.

Szczegóły wzmocnienia bezpieczeństwa 5/819: zmierz czas wykonywania, klasę błędu oraz zużycie tokenów dla tej notatki, a następnie zdecyduj, czy zachować zmianę na podstawie ustalonego zestawu pytań, a nie jedynie anegdoty.

W etapie 6 notatki dotyczącej wzmocnienia bezpieczeństwa zdefiniuj dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie wykonać ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury.

Szczegóły wzmocnienia bezpieczeństwa 6/819: zmierz czas wykonywania, klasę błędu oraz zużycie tokenów dla tej notatki, a następnie zdecyduj, czy zachować zmianę na podstawie ustalonego zestawu pytań, a nie jedynie anegdoty.

Literatura pokrewna

  • Zbadalem 300 pakietów npm związanych z MCP. Mój skaner nie mógł przeglądać czasu ruchu — Szczegółowy przewodnik po procesie zbadania 300 pakietów npm związanych z MCP. Mój skaner nie mógł przeglądać czasu ruchu: umowy, sprawdzenia oraz miejsca na kod do wstawienia dla zespołów stosujących ten wzorzec.