mcp-security modules are the only Java option that can be a full OAuth authorization server with dynamic client registration — via the mcp-authorization-server module, built on Spring Authorization Server. The official Java SDK deliberately delegates authorization to Spring, so this page is really about the Spring security modules. They’re authoritative; this page covers the choices and the one gotcha that matters most for MCP Manager.
Start with Building Your Own MCP
Server
for the requirements and the auth-mode
decision tree. This page is the Spring
AI layer on top.
Serve the STREAMABLE protocol
Use the WebMVC server starter (spring-ai-starter-mcp-server-webmvc) and set spring.ai.mcp.server.protocol=STREAMABLE (or STATELESS for a stateless deployment). That gives you the Streamable HTTP transport MCP Manager requires.
Choose a security module per MCP Manager mode
mcp-security has two distinct modules. Pick the one matching your chosen MCP Manager mode.
| You want | Use in Spring | Notes |
|---|---|---|
| Standard OAuth + DCR | mcp-authorization-server (McpAuthorizationServerConfigurer.mcpAuthorizationServer()) | Built on Spring Authorization Server; DCR is on by default. Also serves RFC 8414 + RFC 9728 metadata |
| Pre-registration / bearer token | mcp-server-security (McpServerOAuth2Configurer.mcpServerOAuth2()) | Resource server: validates inbound JWTs against an issuer, serves RFC 9728 at /.well-known/oauth-protected-resource/mcp |
| Token in a header | McpApiKeyConfigurer.mcpServerApiKey() | API-key auth, maps to MCP Manager’s header-token mode |
The gotcha: the default client repository is in-memory
If you runmcp-authorization-server, registered clients are stored in Spring Authorization Server’s RegisteredClientRepository, which defaults to InMemoryRegisteredClientRepository — dev/test only, and ephemeral. On a multi-instance deployment that’s the classic DCR failure: MCP Manager registers against one instance, the authorize hop lands on another, and the client isn’t found.
The fix is to wire a JdbcRegisteredClientRepository backed by a shared database (applying the oauth2-registered-client-schema.sql tables). This is an explicit configuration step — it does not happen automatically.
MCP Manager compatibility checklist
STREAMABLE protocol on WebMVC
Set
spring.ai.mcp.server.protocol=STREAMABLE
with the WebMVC starter;
mcp-security doesn’t cover WebFlux.Pick the right module
mcp-authorization-server for DCR;
mcp-server-security for
bearer-token resource-server;
McpApiKeyConfigurer for header
tokens.Use JdbcRegisteredClientRepository
Replace the default in-memory client
repository with the JDBC one so
registrations survive restarts and
are shared across instances.
Spring AI gotchas
In-memory RegisteredClientRepository
In-memory RegisteredClientRepository
The default loses clients on restart and isn’t shared across instances. Wire
JdbcRegisteredClientRepository for production. See Debug Self-Hosted OAuth.WebFlux is not supported
WebFlux is not supported
mcp-security targets WebMVC. If
you’re on WebFlux, the security
modules don’t apply — plan for WebMVC
or handle auth yourself.Resource-identifier breadth
Resource-identifier breadth
A documented limitation of the current modules is that every client supports all
resource identifiers. If you rely on per-resource audience separation, validate that behavior against your version.Further reading
Spring AI — MCP Security
The authoritative reference for the resource-server and authorization-server modules.
Securing MCP Servers (blog)
A walkthrough of the Spring AI MCP
server security model.
Debug Self-Hosted OAuth
The dynamic-client-registration
failure and why in-memory storage
causes it.
Building Your Own MCP Server
The cross-framework requirements, decision tree, and troubleshooting catalog.
.png?fit=max&auto=format&n=gKqTvJPtsRi2bLNx&q=85&s=8abbce3efb590630de2102c43d32aadf)
.png?fit=max&auto=format&n=Dy9YsIECUbR9JZiT&q=85&s=a1f404cd7f7aeb1727c89d81137ae1ac)