### Run Authorization Server with Maven Source: https://github.com/spring-ai-community/mcp-security/blob/main/samples/README.md Starts the authorization server using Maven. This server issues access tokens required by MCP servers. Ensure this is running before starting the MCP server. ```shell ./mvnw spring-boot:run -pl samples/sample-authorization-server ``` -------------------------------- ### Run Secured Tools Server Source: https://github.com/spring-ai-community/mcp-security/blob/main/samples/README.md Starts the MCP server with method-level security enabled for specific tools. Requires the authorization server to be running. ```shell ./mvnw spring-boot:run -pl samples/sample-mcp-server-secured-tools ``` -------------------------------- ### Run MCP Client (HttpClient) Source: https://github.com/spring-ai-community/mcp-security/blob/main/samples/README.md Starts the MCP client using the JDK's HttpClient for transport. This client demonstrates OAuth 2.0 authentication flow. ```shell ./mvnw spring-boot:run -pl samples/sample-mcp-client ``` -------------------------------- ### Run API Key MCP Server Source: https://github.com/spring-ai-community/mcp-security/blob/main/samples/README.md Starts an MCP server secured with API keys. This server does not require a separate authorization server. ```shell ./mvnw spring-boot:run -pl samples/sample-mcp-server-api-key ``` -------------------------------- ### Run MCP Client (WebClient) Source: https://github.com/spring-ai-community/mcp-security/blob/main/samples/README.md Starts the MCP client using Spring's reactive WebClient for transport. This client also demonstrates OAuth 2.0 authentication. ```shell ./mvnw spring-boot:run -pl samples/sample-mcp-client-webclient ``` -------------------------------- ### Run MCP Server with Maven Source: https://github.com/spring-ai-community/mcp-security/blob/main/samples/README.md Starts the MCP server using Maven. This server is protected by OAuth 2.0 and exposes MCP endpoints. It requires the authorization server to be running. ```shell ./mvnw spring-boot:run -pl samples/sample-mcp-server ``` -------------------------------- ### Gradle Dependency for Manual Security Setup Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Include this Gradle dependency if you prefer to manually wire beans for MCP client security using the lower-level mcp-client-security module. ```groovy implementation("org.springaicommunity:mcp-client-security:0.1.10") ``` -------------------------------- ### Maven Dependency for Manual Security Setup Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Include this Maven dependency if you prefer to manually wire beans for MCP client security using the lower-level mcp-client-security module. ```xml org.springaicommunity mcp-client-security 0.1.10 ``` -------------------------------- ### McpApiKeyConfigurer Source: https://context7.com/spring-ai-community/mcp-security/llms.txt Adds API key authentication to an MCP server. It installs an ApiKeyAuthenticationFilter and wires an ApiKeyAuthenticationProvider against a provided ApiKeyEntityRepository. The API key is expected in the X-API-key header by default. ```APIDOC ## McpApiKeyConfigurer ### Description Adds API key authentication to an MCP server. It installs an `ApiKeyAuthenticationFilter` before the `BasicAuthenticationFilter` and wires an `ApiKeyAuthenticationProvider` against a provided `ApiKeyEntityRepository`. The key is expected in the `X-API-key` header by default (format: `{id}.{secret}`). Use `McpApiKeyConfigurer.mcpServerApiKey()` as the factory method. ### Method Signature ```java // Maven: org.springaicommunity:mcp-server-security:0.1.10 @Configuration @EnableWebSecurity class McpServerApiKeyConfig { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(authz -> authz.anyRequest().authenticated()) .with( McpApiKeyConfigurer.mcpServerApiKey(), apiKey -> apiKey // REQUIRED: provide the API key repository .apiKeyRepository(buildApiKeyRepository()) // OPTIONAL: custom header name (default: "X-API-key") // .headerName("CUSTOM-API-KEY") // OPTIONAL: custom converter for Authorization: Bearer // .authenticationConverter(req -> { ... }) // OPTIONAL: bind MCP sessions to the API key owner .sessionBinding(Customizer.withDefaults()) ) .build(); } private ApiKeyEntityRepository buildApiKeyRepository() { // ApiKeyEntityImpl automatically bcrypt-encodes the secret at build time var key1 = ApiKeyEntityImpl.builder() .id("api01") .secret("mycustomapikey") // plaintext; stored as bcrypt hash .name("Production Client") .build(); var key2 = ApiKeyEntityImpl.builder() .id("api02") .secret("anothersecret") .name("Test Client") .passwordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder()) .build(); return new InMemoryApiKeyEntityRepository<>(List.of(key1, key2)); } } ``` ### Request Example ```bash curl -H "X-API-key: api01.mycustomapikey" http://localhost:8090/mcp ``` ### Response #### Success Response (200) Authenticated user based on the provided API key. #### Error Response - **401 Unauthorized**: If the `X-API-key` header is missing or invalid. ``` -------------------------------- ### Access Authentication in Tool Methods Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md This example shows how to access the current user's authentication details directly within a tool method using SecurityContextHolder. This allows for personalized responses based on the authenticated user. ```java @McpTool(name = "greeter", description = "A tool that greets the user by name, in the selected language") @PreAuthorize("isAuthenticated()") public String greet( @McpToolParam(description = "The language for the greeting (example: english, french, ...)") String language ) { if (!StringUtils.hasText(language)) { language = ""; } var authentication = SecurityContextHolder.getContext().getAuthentication(); var name = authentication.getName(); return switch (language.toLowerCase()) { case "english" -> "Hello, %s!".formatted(name); case "french" -> "Salut %s!".formatted(name); default -> ("I don't understand language \"%s\". " + "So I'm just going to say Hello %s!").formatted(language, name); }; } ``` -------------------------------- ### SecurityFilterChain with McpClientOAuth2Configurer Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Configure a SecurityFilterChain using McpClientOAuth2Configurer to integrate OAuth2 support. This setup allows all requests to be permitted and disables CSRF protection. ```java @Configuration @EnableWebSecurity class SecurityConfiguration { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()) .with(McpClientOAuth2Configurer.mcpClientOAuth2(), Customizer.withDefaults()) .csrf(CsrfConfigurer::disable) .build(); } } ``` -------------------------------- ### Add mcp-server-security-spring-boot Gradle Dependency Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Add this dependency for seamless OAuth2 security setup in your Spring AI MCP server via Boot auto-configuration. Check for compatibility with your Spring AI version. ```groovy implementation("org.springaicommunity:mcp-server-security-spring-boot:0.1.10") ``` -------------------------------- ### Activate Authorization Server Capabilities in Java Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Configure the security filter chain to activate authorization server capabilities when using manual setup. This Java code enables all requests to be authenticated, applies MCP authorization server customizations, and sets up form-based login. ```java @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) { return http // all requests must be authenticated .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) // enable authorization server customizations .with(McpAuthorizationServerConfigurer.mcpAuthorizationServer(), withDefaults()) // enable form-based login, for user "user"/"password" .formLogin(withDefaults()) .build(); } ``` -------------------------------- ### Configure OAuth2 Client with McpClientOAuth2Configurer Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Example of using McpClientOAuth2Configurer in Spring Security to set up OAuth2 client support for MCP. This snippet demonstrates pre-registering an OAuth2 client for a specific MCP server and optionally setting the base URL for redirect URIs. ```java @Configuration @EnableWebSecurity class SecurityConfiguration { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()) .with(McpClientOAuth2Configurer.mcpClientOAuth2(), mcpOAuth2 -> { // Pre-register an OAuth2 client for a specific MCP server mcpOAuth2.registerMcpOAuth2Client("my-mcp-server", "http://localhost:8090/mcp"); // Optionally set the base URL for redirect URIs // mcpOAuth2.baseUrl("http://localhost:8080"); }) .build(); } } ``` -------------------------------- ### Call Protected MCP Server Endpoint Source: https://github.com/spring-ai-community/mcp-security/blob/main/samples/README.md Makes a POST request to the MCP server endpoint using an obtained OAuth 2.0 access token. The token must be included in the Authorization header. This example demonstrates sending an initialization request. ```shell export OAUTH2_TOKEN= curl -XPOST "http://localhost:8090/mcp" \ -d '{"method":"initialize","params":{"protocolVersion":"2025-11-25","clientInfo":{"name":"curl-client","version":"0.19.0"}},"jsonrpc":"2.0","id":0}' \ --header "Accept: application/json" \ --header "Accept: text/event-stream" \ --header "Content-type: application/json" \ --header "Authorization: Bearer $OAUTH2_TOKEN" ``` -------------------------------- ### Configure McpAuthorizationServerConfigurer in Spring Security Source: https://context7.com/spring-ai-community/mcp-security/llms.txt Use McpAuthorizationServerConfigurer to enhance Spring Authorization Server with MCP features. This configuration requires Spring Security setup and can be customized further. ```java // Maven: org.springaicommunity:mcp-authorization-server:0.1.10 @Configuration @EnableWebSecurity class AuthorizationServerConfig { @Bean @Order(Ordered.HIGHEST_PRECEDENCE) SecurityFilterChain authorizationServerFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .with( McpAuthorizationServerConfigurer.mcpAuthorizationServer(), mcp -> mcp // OPTIONAL: disable DCR (default: enabled) // .dynamicClientRegistration(false) // OPTIONAL: further customize the underlying authorization server .authorizationServer(authzServer -> { // e.g., add custom token customizers, endpoint configurers, etc. }) ) .formLogin(Customizer.withDefaults()) .build(); } @Bean @Order(SecurityProperties.BASIC_AUTH_ORDER) SecurityFilterChain defaultFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .formLogin(Customizer.withDefaults()); return http.build(); } } ``` -------------------------------- ### Add mcp-server-security Gradle Dependency Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Include this dependency for manual configuration of MCP server security, useful for custom setups or non-Boot projects. Add Spring Security and optionally OAuth2 resource server dependencies. ```groovy implementation("org.springaicommunity:mcp-server-security:0.1.10") implementation("org.springframework.boot:spring-boot-starter-security") // OPTIONAL // If you would like to use OAuth2, ensure you import the Resource Server dependencies implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server") ``` -------------------------------- ### Gradle Dependency for MCP Authorization Server Spring Boot Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Add the mcp-authorization-server-spring-boot dependency to your Gradle project for easy setup of an MCP authorization server with default security configurations. ```groovy implementation("org.springaicommunity:mcp-authorization-server-spring-boot:0.1.10") ``` -------------------------------- ### Maven Dependency for MCP Authorization Server Spring Boot Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Add the mcp-authorization-server-spring-boot dependency to your Maven project for easy setup of an MCP authorization server with default security configurations. ```xml org.springaicommunity mcp-authorization-server-spring-boot 0.1.10 ``` -------------------------------- ### Minimal Security Configuration with Spring Boot Starter Source: https://context7.com/spring-ai-community/mcp-security/llms.txt When using the Spring Boot starter for MCP clients, only this minimal security configuration is typically needed. It enables basic request authorization and applies the McpClientOAuth2Configurer. ```java // Only this security configuration is needed alongside the Boot starter: @Configuration @EnableWebSecurity class SecurityConfiguration { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()) .with(McpClientOAuth2Configurer.mcpClientOAuth2(), Customizer.withDefaults()) .csrf(CsrfConfigurer::disable) .build(); } } ``` -------------------------------- ### Spring Boot Auto-Configuration for MCP Clients Source: https://context7.com/spring-ai-community/mcp-security/llms.txt The mcp-client-security-spring-boot starter provides auto-configuration for SYNC MCP clients. Configure client type, tool callback enablement, and server connections via application.properties. Dynamic client registration can also be enabled and configured. ```properties # Maven: org.springaicommunity:mcp-client-security-spring-boot:0.1.10 # application.properties spring.ai.mcp.client.type=SYNC spring.ai.mcp.client.initialized=false spring.ai.mcp.client.toolcallback.enabled=true # MCP server connection (Spring AI configures the transport) spring.ai.mcp.client.streamable-http.connections.current-weather.url=http://localhost:8090 # Enable Dynamic Client Registration (default: false) spring.ai.mcp.client.authorization.dynamic-client-registration.enabled=true # Allow localhost URLs for development spring.ai.mcp.client.authorization.dynamic-client-registration.allow-loopback-addresses=true ``` -------------------------------- ### Launch MCP Inspector Source: https://github.com/spring-ai-community/mcp-security/blob/main/samples/README.md Launches the MCP Inspector tool, which provides an interactive interface for exploring and testing MCP servers. This tool requires Node.js and npm. ```shell npx @modelcontextprotocol/inspector@latest ``` -------------------------------- ### API Key Authentication with McpApiKeyConfigurer Source: https://context7.com/spring-ai-community/mcp-security/llms.txt Configures API key authentication for MCP servers. Requires an ApiKeyEntityRepository and optionally allows custom header names or authentication converters. The API key is expected in the X-API-key header by default. ```java @Configuration @EnableWebSecurity class McpServerApiKeyConfig { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(authz -> authz.anyRequest().authenticated()) .with( McpApiKeyConfigurer.mcpServerApiKey(), apiKey -> apiKey // REQUIRED: provide the API key repository .apiKeyRepository(buildApiKeyRepository()) // OPTIONAL: custom header name (default: "X-API-key") // .headerName("CUSTOM-API-KEY") // OPTIONAL: custom converter for Authorization: Bearer // .authenticationConverter(req -> { ... }) // OPTIONAL: bind MCP sessions to the API key owner .sessionBinding(Customizer.withDefaults()) ) .build(); } private ApiKeyEntityRepository buildApiKeyRepository() { // ApiKeyEntityImpl automatically bcrypt-encodes the secret at build time var key1 = ApiKeyEntityImpl.builder() .id("api01") .secret("mycustomapikey") // plaintext; stored as bcrypt hash .name("Production Client") .build(); var key2 = ApiKeyEntityImpl.builder() .id("api02") .secret("anothersecret") .name("Test Client") .passwordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder()) .build(); return new InMemoryApiKeyEntityRepository<>(List.of(key1, key2)); } } // Calling the server with an API key: // curl -H "X-API-key: api01.mycustomapikey" http://localhost:8090/mcp // // Expected: 200 OK (authenticated as "api01") // Without header: 401 Unauthorized ``` -------------------------------- ### Enable MCP Server in application.properties Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Ensure this property is set in your application.properties to enable the MCP server functionality, which is a prerequisite for applying security configurations. ```properties spring.ai.mcp.server.name=my-cool-mcp-server ``` -------------------------------- ### MCP Client Connection Configuration Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Configure your MCP client connections in application.properties. This includes setting the client type, initialization status, server URLs, and enabling dynamic client registration with loopback address support for development. ```properties spring.ai.mcp.client.type=SYNC spring.ai.mcp.client.initialized=false # MCP server connections (Spring AI auto-configures these) spring.ai.mcp.client.streamable-http.connections.my-mcp-server.url=http://localhost:8090 # Enable Dynamic Client Registration (default: false) spring.ai.mcp.client.authorization.dynamic-client-registration.enabled=true # For development purposes, allow loopback addresses for MCP Servers and Auth Servers (default: false) spring.ai.mcp.client.authorization.dynamic-client-registration.allow-loopback-addresses=true ``` -------------------------------- ### Basic Spring Boot Application Security Source: https://context7.com/spring-ai-community/mcp-security/llms.txt This is the entire security configuration needed for a basic Spring Boot application when using the Boot starter. For advanced customization, a Customizer bean can be provided. ```java @SpringBootApplication public class MyMcpServerApplication { public static void main(String[] args) { SpringApplication.run(MyMcpServerApplication.class, args); } } ``` ```java @Bean Customizer mcpSecurityCustomizations() { return http -> { http.csrf(CsrfConfigurer::disable); // ... additional customizations (e.g., CORS for MCP Inspector) }; } ``` -------------------------------- ### Programmatically Configure WebClient MCP Client Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Configure an MCP client using WebClient when bypassing Spring AI's autoconfiguration. Requires WebClient.Builder, ObjectMapper, and McpClientCommonProperties. ```java // For WebClient based clients @Bean McpSyncClient client( WebClient.Builder mcpWebClientBuilder, ObjectMapper objectMapper, McpClientCommonProperties commonProperties ) { var builder = mcpWebClientBuilder.baseUrl(mcpServerUrl); var transport = WebClientStreamableHttpTransport.builder(builder) .jsonMapper(new JacksonMcpJsonMapper(objectMapper)) .build(); var clientInfo = new McpSchema.Implementation("clientName", commonProperties.getVersion()); return McpClient.sync(transport) .clientInfo(clientInfo) .requestTimeout(commonProperties.getRequestTimeout()) .transportContextProvider(new AuthenticationMcpTransportContextProvider()) .build(); } ``` -------------------------------- ### Add MCP Clients to Chat Client Tools Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Integrate configured MCP clients into a chat client by providing them to tool callbacks. This allows the chat client to utilize the MCP clients for specific tasks. ```java var chatResponse = chatClient.prompt("Prompt the LLM to _do the thing_") .toolCallbacks(new SyncMcpToolCallbackProvider(mcpClient1, mcpClient2, mcpClient3)) .call() .content(); ``` -------------------------------- ### Configure MCP Server Security with Spring Security Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md This configuration sets up Spring Security for the MCP Server, requiring authentication for all requests and integrating the MCP server's API key security. It demonstrates how to provide a custom ApiKeyEntityRepository and optionally configure the API key header name or a custom authentication converter. ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain; import static org.springframework.ai.mcp.server.security.McpServerSecurityConfigurer.mcpServerApiKey; @Configuration @EnableWebSecurity class McpServerConfiguration { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) { return http.authorizeHttpRequests(authz -> authz.anyRequest().authenticated()) .with( mcpServerApiKey(), (apiKey) -> { // REQUIRED: the repo for API keys apiKey.apiKeyRepository(apiKeyRepository()); // OPTIONAL: name of the header containing the API key. // Here for example, api keys will be sent with "CUSTOM-API-KEY: " // Replaces .authenticationConverter(...) (see below) // // apiKey.headerName("CUSTOM-API-KEY"); // OPTIONAL: custom converter for transforming an http request // into an authentication object. Useful when the header is // "Authorization: Bearer ". // Replaces .headerName(...) (see above) // // apiKey.authenticationConverter(request -> { // var key = extractKey(request); // return ApiKeyAuthenticationToken.unauthenticated(key); // }); // OPTIONAL: bind the MCP session to the user's identity // This ensures that a session created with a given API key // can only be used with that API key // // apiKey.sessionBinding(Customizer.withDefaults()); } ) .build(); } /** * Provide a repository of {@link ApiKeyEntity}. */ private ApiKeyEntityRepository apiKeyRepository() { //@formatter:off var apiKey = ApiKeyEntityImpl.builder() .name("test api key") .id("api01") .secret("mycustomapikey") .build(); //@formatter:on return new InMemoryApiKeyEntityRepository<>(List.of(apiKey)); } } ``` -------------------------------- ### Manual AuthenticationMcpTransportContextProvider and Request Customizer Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md When not using auto-configuration, add an AuthenticationMcpTransportContextProvider and configure a request customizer like OAuth2AuthorizationCodeSyncHttpRequestCustomizer. ```java @Configuration class McpConfiguration { @Bean McpSyncClientCustomizer syncClientCustomizer() { return (name, syncSpec) -> syncSpec.transportContextProvider( new AuthenticationMcpTransportContextProvider() ); } @Bean McpSyncHttpClientRequestCustomizer requestCustomizer( OAuth2AuthorizedClientManager clientManager, ClientRegistrationRepository clientRegistrationRepository ) { return new OAuth2AuthorizationCodeSyncHttpRequestCustomizer( clientManager, clientRegistrationRepository, "authserver" ); } } ``` -------------------------------- ### Secure Tool Calls with @PreAuthorize Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md This service demonstrates how to secure individual tool methods using the @PreAuthorize annotation with 'isAuthenticated()'. This ensures that only requests with a valid bearer token can invoke the tool. ```java @Service public class MyToolsService { // Note: you can also use Spring AI's @Tool @PreAuthorize("isAuthenticated()") @McpTool(name = "greeter", description = "A tool that greets you, in the selected language") public String greet( @McpToolParam(description = "The language for the greeting (example: english, french, ...)") String language ) { if (!StringUtils.hasText(language)) { language = ""; } return switch (language.toLowerCase()) { case "english" -> "Hello you!"; case "french" -> "Salut toi!"; default -> "I don't understand language \"%s\". So I'm just going to say Hello!".formatted(language); }; } } ``` -------------------------------- ### Configure MCP Server Security with OAuth2 Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Use this configuration to enforce authentication with a token on every request and configure OAuth2 for the MCP server. The issuer URI is required, and audience claim validation and session binding are optional. ```java @Configuration @EnableWebSecurity class McpServerConfiguration { @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") private String issuerUrl; @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) { return http // Enforce authentication with token on EVERY request .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) // Configure OAuth2 on the MCP server .with( McpServerOAuth2Configurer.mcpServerOAuth2(), (mcpAuthorization) -> { // REQUIRED: the issuerURI mcpAuthorization.authorizationServer(issuerUrl); // OPTIONAL: enforce the `aud` claim in the JWT token. // Not all authorization servers support resource indicators, // so it may be absent. Defaults to `false`. // See RFC 8707 Resource Indicators for OAuth 2.0 // https://www.rfc-editor.org/rfc/rfc8707.html // // mcpAuthorization.validateAudienceClaim(true); // OPTIONAL: bind the MCP session to the user's identity // This ensures that a session created by a user can only be accessed by that user // // mcpAuthorization.sessionBinding(Customizer.withDefaults()); } ) .build(); } } ``` -------------------------------- ### Programmatically Configure HttpClient MCP Client Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Configure an MCP client using HttpClient when bypassing Spring AI's autoconfiguration. Requires ObjectMapper, McpSyncHttpClientRequestCustomizer, and McpClientCommonProperties. ```java // For HttpClient-based clients @Bean McpSyncClient client( ObjectMapper objectMapper, McpSyncHttpClientRequestCustomizer requestCustomizer, McpClientCommonProperties commonProps ) { var transport = HttpClientStreamableHttpTransport.builder(mcpServerUrl) .clientBuilder(HttpClient.newBuilder()) .jsonMapper(new JacksonMcpJsonMapper(objectMapper)) .httpRequestCustomizer(requestCustomizer) .build(); var clientInfo = new McpSchema.Implementation("client-name", commonProps.getVersion()); return McpClient.sync(transport) .clientInfo(clientInfo) .requestTimeout(commonProps.getRequestTimeout()) .transportContextProvider(new AuthenticationMcpTransportContextProvider()) .build(); } ``` -------------------------------- ### Configure MCP Server as OAuth 2.0 Resource Server Source: https://context7.com/spring-ai-community/mcp-security/llms.txt Use McpServerOAuth2Configurer to set up an MCP server as an OAuth 2.0 resource server. Requires JWT decoder configuration and optionally enforces audience claims and session binding. Per-tool authorization can be achieved using method security annotations. ```java // Maven: org.springaicommunity:mcp-server-security:0.1.10 // application.properties: // spring.ai.mcp.server.name=my-mcp-server // spring.ai.mcp.server.protocol=STREAMABLE // spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9000 @Configuration @EnableWebSecurity @EnableMethodSecurity // required only for per-tool @PreAuthorize class McpServerConfig { @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") private String issuerUri; @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http // Require authentication on every request .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .with( McpServerOAuth2Configurer.mcpServerOAuth2(), mcp -> mcp // REQUIRED: issuer URI of the authorization server .authorizationServer(issuerUri) // OPTIONAL: override the MCP resource path (default: "/mcp") .resourcePath("/mcp") // OPTIONAL: enforce the JWT `aud` claim (RFC 8707) .validateAudienceClaim(true) // OPTIONAL: bind MCP sessions to the authenticated user (sub claim) .sessionBinding(Customizer.withDefaults()) ) .build(); } } // Per-tool authorization using method security: @Service public class WeatherService { @PreAuthorize("isAuthenticated()") @McpTool(name = "temperature-history", description = "Get historical temperature data for a location") public ToolResponse getHistoricalWeather( @ToolParam(description = "Latitude") double latitude, @ToolParam(description = "Longitude") double longitude) { // Access current principal from thread-local: var auth = SecurityContextHolder.getContext().getAuthentication(); String user = auth.getName(); // "alice" or the token's sub claim // ... implementation return new ToolResponse(List.of()); } } ``` ```java // Per-tool authorization using method security: @Service public class WeatherService { @PreAuthorize("isAuthenticated()") @McpTool(name = "temperature-history", description = "Get historical temperature data for a location") public ToolResponse getHistoricalWeather( @ToolParam(description = "Latitude") double latitude, @ToolParam(description = "Longitude") double longitude) { // Access current principal from thread-local: var auth = SecurityContextHolder.getContext().getAuthentication(); String user = auth.getName(); // "alice" or the token's sub claim // ... implementation return new ToolResponse(List.of()); } } ``` -------------------------------- ### Configure OAuth 2.0 Client Support for MCP Clients Source: https://context7.com/spring-ai-community/mcp-security/llms.txt Use McpClientOAuth2Configurer to set up OAuth 2.0 client support for applications hosting MCP clients. This configurer wires the resource parameter, registers necessary repositories and managers, and supports dynamic client registration. It's typically used within a Spring Security HttpSecurity configuration. ```java // Maven: org.springaicommunity:mcp-client-security:0.1.10 @Configuration @EnableWebSecurity class McpClientSecurityConfig { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()) .with( McpClientOAuth2Configurer.mcpClientOAuth2(), mcp -> mcp // OPTIONAL: pre-register an OAuth2 client for a specific MCP server // (triggers Dynamic Client Registration on first request) .registerMcpOAuth2Client("my-mcp-server", "http://localhost:8090/mcp") // OPTIONAL: base URL for redirect URIs (auto-detected if omitted) .baseUrl("https://my-app.example.com") // OPTIONAL: custom URL validator for SSRF protection .urlValidator(new DefaultUrlValidator()) // OPTIONAL: further customize the underlying OAuth2 client config .oauth2Client(Customizer.withDefaults()) ) .csrf(CsrfConfigurer::disable) .build(); } } ``` -------------------------------- ### Customize HTTP Client Requests Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Implement McpSyncHttpClientRequestCustomizer to add custom headers to HTTP client requests. This is useful for adding static or dynamic information to outgoing requests. ```java @Configuration class McpConfiguration { @Bean McpSyncHttpClientRequestCustomizer requestCustomizer() { return (builder, method, endpoint, body, context) -> builder .header("x-custom-header", "custom-value") .header("x-life-the-universe-everything", "42"); } } ``` -------------------------------- ### Test API Key Server with curl Source: https://github.com/spring-ai-community/mcp-security/blob/main/samples/README.md Sends a POST request to the API key secured MCP server using curl, including the API key in the header. ```shell curl -XPOST "http://localhost:8092/mcp" \ -d '{"method":"initialize","params":{"protocolVersion":"2025-11-25","clientInfo":{"name":"curl-client","version":"0.19.0"}},"jsonrpc":"2.0","id":0}' \ --header "Accept: application/json" \ --header "Accept: text/event-stream" \ --header "Content-type: application/json" \ --header "X-API-Key: api01.mycustomapikey" ``` -------------------------------- ### Java Method Security Configuration Source: https://github.com/spring-ai-community/mcp-security/blob/main/samples/README.md Illustrates enabling method-level security in a Spring Boot application using @EnableMethodSecurity and @PreAuthorize annotations on tool methods. ```java .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()) @PreAuthorize("isAuthenticated()") @McpTool(name = "temperature-history", ...) public ToolResponse getHistoricalWeatherData(...) { ...} ``` -------------------------------- ### Injecting Authentication into Reactor Context for Streaming Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md For streaming chat clients using Reactor, manually extract and inject authentication information into the Reactor context using AuthenticationMcpTransportContextProvider.writeToReactorContext(). ```java import com.mcp.security.oauth2.client.McpTransportContext; import reactor.core.publisher.Flux; class Example { void doTheThing() { chatClient .prompt("") .stream() .content() // ... any streaming operation ... .contextWrite(AuthenticationMcpTransportContextProvider.writeToReactorContext()); } } ``` -------------------------------- ### Integrate Thread-Local Context with HttpClient Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Use McpSyncClientCustomizer and McpSyncHttpClientRequestCustomizer to pass thread-local context to HTTP client requests. This allows request customizers to access thread-specific data. ```java @Configuration class McpConfiguration { @Bean McpSyncClientCustomizer syncClientCustomizer() { return (name, syncSpec) -> syncSpec.transportContextProvider(() -> { var myThing = MyThreadLocalThing.get(); return McpTransportContext.create(Map.of("custom-key", myThing)); }); } @Bean McpSyncHttpClientRequestCustomizer requestCustomizer() { return (builder, method, endpoint, body, context) -> builder.header("x-custom-header", context.get("custom-key")); } } ``` -------------------------------- ### Set Anthropic API Key Source: https://github.com/spring-ai-community/mcp-security/blob/main/samples/README.md Sets the Anthropic API key as an environment variable. This is required for the sample client to interact with the Anthropic AI model. ```shell export ANTHROPIC_API_KEY= ``` -------------------------------- ### Enable Loopback Address HTTP URLs for DCR Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Allows HTTP URLs for loopback addresses when running in development mode. Set this property to true to permit HTTP for localhost, 127.0.0.1, and [::1] during dynamic client registration. ```properties spring.ai.mcp.client.authorization.dynamic-client-registration.allow-loopback-addresses=true ``` -------------------------------- ### Configure WebClient with OAuth2 Client Credentials Filter Source: https://context7.com/spring-ai-community/mcp-security/llms.txt Use this configuration to set up a WebClient builder with a filter for OAuth2 client credentials grant type. This is suitable for machine-to-machine communication. ```java @Configuration class McpWebClientM2MConfig { @Bean WebClient.Builder mcpWebClientBuilder( OAuth2AuthorizedClientManager clientManager, ClientRegistrationRepository clientRegistrationRepository) { return WebClient.builder() .filter(new McpOAuth2ClientCredentialsExchangeFilterFunction( clientManager, clientRegistrationRepository, "my-m2m-registration" )); } } ``` -------------------------------- ### WebClient Builder with OAuth2 Filter Function Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Configure a WebClient.Builder with an MCP OAuth2 filter function for reactive transports. McpOAuth2AuthorizationCodeExchangeFilterFunction is preferred for authorization code flow. ```java @Configuration class McpConfiguration { @Bean McpSyncClientCustomizer syncClientCustomizer() { return (name, syncSpec) -> syncSpec.transportContextProvider( new AuthenticationMcpTransportContextProvider() ); } @Bean WebClient.Builder mcpWebClientBuilder(OAuth2AuthorizedClientManager clientManager) { return WebClient.builder().filter( new McpOAuth2AuthorizationCodeExchangeFilterFunction( clientManager, "authserver" ) ); } } ``` -------------------------------- ### Spring Boot Auto-configuration for MCP Authorization Server Source: https://context7.com/spring-ai-community/mcp-security/llms.txt Configure application properties to customize the behavior of the MCP Authorization Server, such as token expiration and client registration settings. Dynamic Client Registration is enabled by default. ```properties # Maven: org.springaicommunity:mcp-authorization-server-spring-boot:0.1.10 # application.yml spring: application: name: sample-authorization-server security: oauth2: authorizationserver: client: default-client: token: access-token-time-to-live: 1h registration: client-id: "default-client" client-secret: "{noop}default-secret" client-authentication-methods: - "client_secret_basic" - "none" authorization-grant-types: - "authorization_code" - "client_credentials" redirect-uris: - "http://localhost:8080/authorize/oauth2/code/authserver" # MCP Inspector callback - "http://localhost:6274/oauth/callback" # Claude Code callback - "https://claude.ai/api/mcp/auth_callback" user: name: user password: password server: servlet: session: cookie: name: MCP_AUTHORIZATION_SERVER_SESSIONID ``` ```properties # To disable Dynamic Client Registration: spring.ai.mcp.authorizationserver.dynamic-client-registration.enabled=false ``` -------------------------------- ### Configure MCP Server Security Properties Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Set these properties in application.properties to enable MCP server security and specify the authorization server's issuer URI. This configuration is essential for the auto-configuration to secure endpoints. ```properties spring.ai.mcp.server.name=my-cool-mcp-server spring.ai.mcp.server.protocol=STREAMABLE # The issuer URI of the authorization server spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9000 ``` -------------------------------- ### SessionBindingConfigurer Source: https://context7.com/spring-ai-community/mcp-security/llms.txt Enforces the MCP security best practice of binding a session ID to a specific authenticated principal, preventing session hijacking. Once a session is established, any subsequent request using that session ID must originate from the same principal; otherwise a 403 Forbidden is returned. ```APIDOC ## SessionBindingConfigurer ### Description Enforces the MCP security best practice of binding a session ID to a specific authenticated principal, preventing session hijacking. Once a session is established (identified by the `Mcp-Session-Id` response header), any subsequent request using that session ID must originate from the same principal; otherwise a `403 Forbidden` is returned. ### Method Signature ```java // Standalone use — called inside McpServerOAuth2Configurer.sessionBinding(): @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .with( McpServerOAuth2Configurer.mcpServerOAuth2(), mcp -> mcp .authorizationServer(issuerUri) .sessionBinding(sessionBinding -> { // OPTIONAL: custom repository (default: InMemoryMcpSessionBindingRepository) sessionBinding.sessionBindingRepository(new InMemoryMcpSessionBindingRepository()); // OPTIONAL: custom binding ID resolver (default: authentication.getName()) sessionBinding.sessionBindingIdResolver( req -> SecurityContextHolder.getContext().getAuthentication().getName() ); }) ) .build(); } // Same .sessionBinding(Customizer.withDefaults()) is available on McpApiKeyConfigurer. ``` ### Response #### Error Response - **403 Forbidden**: If a subsequent request uses a session ID that is not bound to the current principal. ``` -------------------------------- ### Integrate Thread-Local Context with WebClient Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Use McpSyncClientCustomizer and a WebClient filter to pass thread-local context to WebClient requests via Reactor context. This enables access to thread-specific data within the WebClient filter. ```java @Configuration class McpConfiguration { @Bean McpSyncClientCustomizer syncClientCustomizer() { return (name, syncSpec) -> syncSpec.transportContextProvider(() -> { var myThing = MyThreadLocalThing.get(); return McpTransportContext.create(Map.of("custom-key", myThing)); }); } @Bean WebClient.Builder mcpWebClientBuilder() { return WebClient.builder() .filter((request, next) -> Mono.deferContextual(reactorCtx -> { var transportCtx = reactorCtx.get(McpTransportContext.class); String customThing = transportCtx.get("custom-key").toString(); var newRequest = ClientRequest.from(request) .header("x-custom-header", customThing) .build(); return next.exchange(newRequest); }) ); } } ``` -------------------------------- ### Obtain OAuth 2.0 Access Token Source: https://github.com/spring-ai-community/mcp-security/blob/main/samples/README.md Obtains an OAuth 2.0 access token using the client credentials grant type. This token is then used to authenticate requests to the protected MCP server. Replace 'default-client' and 'default-secret' with actual client credentials. ```shell curl -XPOST "http://localhost:9000/oauth2/token" \ --data "grant_type=client_credentials" \ --user "default-client:default-secret" ``` -------------------------------- ### Add mcp-server-security-spring-boot Maven Dependency Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Include this dependency for easy OAuth2 security integration with Spring AI's MCP servers using Boot auto-configuration. Ensure your Spring AI version is compatible. ```xml org.springaicommunity mcp-server-security-spring-boot 0.1.10 ``` -------------------------------- ### MCP Server Security Boot Auto-configuration Source: https://context7.com/spring-ai-community/mcp-security/llms.txt The `mcp-server-security-spring-boot` module activates automatically when `spring.security.oauth2.resourceserver.jwt.issuer-uri` is set. It provides a default SecurityFilterChain requiring authentication on all requests, often eliminating the need for manual Java configuration. ```properties # Maven: org.springaicommunity:mcp-server-security-spring-boot:0.1.10 # application.properties spring.ai.mcp.server.name=my-mcp-server spring.ai.mcp.server.protocol=STREAMABLE server.port=8090 ``` -------------------------------- ### Add mcp-server-security Maven Dependency Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Use this lower-level dependency for manual bean wiring of MCP server security, suitable for advanced customization, API key support, or non-Boot applications. Include Spring Security and optionally OAuth2 resource server dependencies. ```xml org.springaicommunity mcp-server-security 0.1.10 org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-starter-oauth2-resource-server ``` -------------------------------- ### Configure Default Client in application.yml Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Use this YAML configuration to register a default client with specific token and registration properties for the authorization server. Ensure the server servlet session cookie name is overridden to prevent conflicts when running multiple Spring apps on localhost. ```yaml spring: application: name: sample-authorization-server security: oauth2: authorizationserver: client: default-client: token: access-token-time-to-live: 1h registration: client-id: "default-client" client-secret: "{noop}default-secret" client-authentication-methods: - "client_secret_basic" - "none" authorization-grant-types: - "authorization_code" - "client_credentials" redirect-uris: - "http://127.0.0.1:8080/authorize/oauth2/code/authserver" - "http://localhost:8080/authorize/oauth2/code/authserver" # mcp-inspector - "http://localhost:6274/oauth/callback" # claude code - "https://claude.ai/api/mcp/auth_callback" user: # A single user, named "user" name: user password: password server: servlet: session: cookie: # Override the default cookie name (JSESSIONID). # This allows running multiple Spring apps on localhost, and they'll each have their own cookie. # Otherwise, since the cookies do not take the port into account, they are confused. name: MCP_AUTHORIZATION_SERVER_SESSIONID ``` -------------------------------- ### Disable Dynamic Client Registration via Properties Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md To disable Dynamic Client Registration (DCR) when using Boot auto-configuration, set the following property in your application configuration. ```properties spring.ai.mcp.authorizationserver.dynamic-client-registration.enabled=false ``` -------------------------------- ### Gradle Dependency for Spring Boot Security Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Add this dependency to your Gradle project to enable Spring Boot auto-configuration for MCP client security. ```groovy implementation("org.springaicommunity:mcp-client-security-spring-boot:0.1.10") implementation("org.springframework.ai:spring-ai-starter-mcp-client") ``` -------------------------------- ### Propagate Authentication to MCP Requests Source: https://context7.com/spring-ai-community/mcp-security/llms.txt Configure `AuthenticationMcpTransportContextProvider` to propagate the current `Authentication` and `RequestAttributes` to MCP requests. This is useful for maintaining security context across asynchronous operations using Reactor. ```java // Manual configuration (without Boot starter): @Bean McpSyncClientCustomizer syncClientCustomizer() { return (name, syncSpec) -> syncSpec .transportContextProvider(new AuthenticationMcpTransportContextProvider()); } // For streaming ChatClient (to propagate thread-locals through Reactor): Flux stream = chatClient.prompt("Tell me the weather") .stream() .content() .contextWrite(AuthenticationMcpTransportContextProvider.writeToReactorContext()); // Programmatic client with context provider: McpSyncClient client = McpClient.sync(transport) .clientInfo(new McpSchema.Implementation("my-client", "1.0")) .requestTimeout(Duration.ofSeconds(30)) .transportContextProvider(new AuthenticationMcpTransportContextProvider()) .build(); ``` -------------------------------- ### Gradle Dependency for MCP Authorization Server Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md Add the mcp-authorization-server dependency to your Gradle project for manual bean wiring and advanced customization of the MCP authorization server. ```groovy implementation("org.springaicommunity:mcp-authorization-server:0.1.10") ``` -------------------------------- ### Configure MCP Server Security with OAuth2 Source: https://github.com/spring-ai-community/mcp-security/blob/main/README.md This configuration secures the MCP server by allowing public access to '/mcp' but requiring authentication for all other requests. It integrates OAuth2 for resource server authentication. ```java @Configuration @EnableWebSecurity @EnableMethodSecurity // ⬅️ enable annotation-driven security class McpServerConfiguration { @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") private String issuerUrl; @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) { return http // ⬇️ Open every request on the server .authorizeHttpRequests(auth -> { auth.requestMatchers("/mcp").permitAll(); auth.anyRequest().authenticated(); }) // Configure OAuth2 on the MCP server .with( McpServerOAuth2Configurer.mcpServerOAuth2(), (mcpAuthorization) -> { // REQUIRED: the issuerURI mcpAuthorization.authorizationServer(issuerUrl); } ) .build(); } } ```