@@ -33,6 +33,7 @@ The project enables developers to:
3333
3434Provides OAuth 2.0 resource server capabilities
3535for [ Spring AI's MCP servers] ( https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html ) .
36+ It also provides basic support for API-key based servers.
3637This module is compatible with Spring WebMVC-based servers only.
3738
3839### Add to your project
@@ -48,8 +49,13 @@ This module is compatible with Spring WebMVC-based servers only.
4849 <artifactId >mcp-server-security</artifactId >
4950 <version >0.0.1</version >
5051 </dependency >
52+ <dependency >
53+ <groupId >org.springframework.boot</groupId >
54+ <artifactId >spring-boot-starter-security</artifactId >
55+ </dependency >
5156
52- <!-- Also ensure you import the appropriate OAuth2 resource server dependencies -->
57+ <!-- OPTIONAL -->
58+ <!-- If you would like to use OAuth2, ensure you import the Resource Server dependencies -->
5359 <dependency >
5460 <groupId >org.springframework.boot</groupId >
5561 <artifactId >spring-boot-starter-oauth2-resource-server</artifactId >
@@ -62,9 +68,14 @@ This module is compatible with Spring WebMVC-based servers only.
6268
6369``` groovy
6470implementation("org.springaicommunity:mcp-server-security:0.0.1")
71+ implementation("org.springframework.boot:spring-boot-starter-security")
72+
73+ // OPTIONAL
74+ // If you would like to use OAuth2, ensure you import the Resource Server dependencies
75+ implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
6576```
6677
67- ### Usage
78+ ### Usage: OAuth2
6879
6980Ensure that MCP server is enabled in your ` application.properties ` :
7081
@@ -113,7 +124,7 @@ class McpServerConfiguration {
113124}
114125```
115126
116- ### Special case: only secure tool calls
127+ ### Special case: only secure tool calls with OAuth2
117128
118129It is also possible to secure the tools only, and not the rest of the MCP Server. For example, both ` initialize ` and
119130` tools/list ` are made public, but ` tools/call ` is authenticated.
@@ -205,6 +216,84 @@ public String greet(
205216}
206217```
207218
219+ ### Usage: API keys
220+
221+ Ensure that MCP server is enabled in your ` application.properties ` :
222+
223+ ``` properties
224+ spring.ai.mcp.server.name =my-cool-mcp-server
225+ # Supported protocols: STREAMABLE, STATELESS
226+ spring.ai.mcp.server.protocol =STREAMABLE
227+ ```
228+
229+ For this, you'll need to provide your own implementation of ` ApiKeyEntityRepository ` , for storing ` ApiKeyEntity `
230+ objects.
231+ These represent the "entities" which have API keys.
232+ Each entry has an ID, a secret for storing API keys in a secure way (e.g. bcrypt, argon2, ...), as well as a name used
233+ for display purposes.
234+ A sample implementation is available with an ` InMemoryApiKeyEntityRepository ` along with a default ` ApiKeyEntityImpl ` .
235+ You can bring your own entity implementation with the in-memory repository.
236+
237+ > ⚠️ The ` InMemoryApiKeyEntityRepository ` uses on bcrypt for storing the API keys, and, as such, will be computationally
238+ > expensive. It is not suited for high-traffic production use. In that case, you must ship your own
239+ > ` ApiKeyEntityRepository ` implementation.
240+
241+ With that, you can configure the security for your project in the usual Spring-Security way:
242+
243+ ``` java
244+
245+ @Configuration
246+ @EnableWebSecurity
247+ class McpServerConfiguration {
248+
249+ @Bean
250+ SecurityFilterChain securityFilterChain (HttpSecurity http ) throws Exception {
251+ return http. authorizeHttpRequests(authz - > authz. anyRequest(). authenticated())
252+ .with(
253+ mcpServerApiKey(),
254+ (apiKey) - > {
255+ // REQUIRED: the repo for API keys
256+ apiKey. apiKeyRepository(buildApiKeyRepository());
257+
258+ // OPTIONAL: name of the header containing the API key.
259+ // Here for example, api keys will be sent with "CUSTOM-API-KEY: <value>"
260+ // Replaces .authenticationConverter(...) (see below)
261+ apiKey. headerName(" CUSTOM-API-KEY" );
262+
263+ // OPTIONAL: custom converter for transforming an http request
264+ // into an authentication object. Useful when the header is
265+ // "Authorization: Bearer <value>".
266+ // Replaces .headerName(...) (see above)
267+ apiKey. authenticationConverter(request - > {
268+ var key = extractKey(request);
269+ return ApiKeyAuthenticationToken . unauthenticated(key);
270+ });
271+ }
272+ )
273+ .build();
274+ }
275+
276+ /**
277+ * Provide a repository of {@link ApiKeyEntity}.
278+ */
279+ private ApiKeyEntityRepository<ApiKeyEntityImpl > apiKeyRepository () {
280+ // @formatter:off
281+ var apiKey = ApiKeyEntityImpl . builder()
282+ .name(" test api key" )
283+ .id(" api01" )
284+ // "mycustomapikey
285+ .secret(" mycustomapikey" )
286+ .build();
287+ // @formatter:on
288+
289+ return new InMemoryApiKeyEntityRepository<> (List . of(apiKey));
290+ }
291+
292+ }
293+ ```
294+
295+ Then you should be able to call your MCP server with ` X-API-key: api01.mycustomapikey ` .
296+
208297### Known limitations
209298
210299- The deprecated SSE transport is not supported.
0 commit comments