Springing into AI - Part 17: MCP Server - Security Playground
About
In MCP Server, Security plays an extremly crucial part in securing access to different capabilities offered by it for only authenticated and authorized users. Currently, there are two ways in which this can be accomplished. OAuth2 is the industry de facto recommended approcah, and the other being a token or API key exchange. For this playground, we will be focussing on OAuth2 authorization.
Project
In Hobbits Inc, we will be having our custom hobbit Authorization Server that will comprise of hobbit credentials stored in memory. Our Hobbit MCP Server will be providing the relevant Resource capability information in form of profile and mugshot only for the logged in hobbit as we do not want Sauron the dark lord accessing that information else Middle Earth and Hobbits Inc would be in deep jeopardy with lawsuits from Elrond. Please note that this can be extended to other MCP capabilities like tools, prompts etc as well. Architecture overview is shown below:
Setup
Our project setup encompasses the following:- Authorization Server:
- Java: 17
- Spring AI: 1.1.2
- Spring Boot: 4.0.3
- Source Code: can be viewed here
- Miscellaneous:
- Server Port 9000
- MCP Server:
- Testing tool: MCP Inspector
- Authorization Server:
- Java: 17
- Spring AI: 1.1.2
- Spring Boot: 4.0.3
- Source Code: can be viewed here
- Miscellaneous:
- Server Port 9000
- MCP Server:
- Testing tool: MCP Inspector
Demo Screenshots
In the MCP Inspector, we have two modes in which we can emulate OAuth authentication. The "Quick OAuth Flow" is a one stop button click which will run through the process automatically of obtaining an OAuth token. "Guided OAuth Flow" is the process of manually running through each and every step one at a time.
Either of the process will result in the same result where a successfull authentication provides an authentication token. The image below shows a basic form login as part of OAuth for this demo where we requesting user to validate themselves.
When we run through the process, the net result upon successfull user authentication is shown below:
It is to be noted at this stage, we still need to login to the application. This is done by copying the access token and then using it as a bearer token to login.
The access token is prefixed with "Bearer " in the header. The other configuration that is shown was used initially with which the OAuth Server was configured. Notice the redirect URL mentioned as this is the callback URL the Authentication Server invokes after a successfull validation of user credentials.
Since at this stage we are logged in, the Spring security holds the authenticated object in its context. This in the code can be used to obtain the logged in user. In our Middle Earths Hobbit Inc, we use the username of the hobbit to then retrieve their profile and mugshot. For the purpose of demo, we are only using Resources capability, but it can be extended to any other capability from the MCP Server.
If you do use the mugshot resources, you would need to decode the encoded Base64 content into an image using an online tool to see the hobbit mugshot. Here, since we logged in with frodo above during the OAuth process we see frodo's profile and mugshot. Similar representation would take shape depending on which hobbit we logged in with.
Code Walkthrough
Either of the process will result in the same result where a successfull authentication provides an authentication token. The image below shows a basic form login as part of OAuth for this demo where we requesting user to validate themselves.
It is to be noted at this stage, we still need to login to the application. This is done by copying the access token and then using it as a bearer token to login.
The access token is prefixed with "Bearer " in the header. The other configuration that is shown was used initially with which the OAuth Server was configured. Notice the redirect URL mentioned as this is the callback URL the Authentication Server invokes after a successfull validation of user credentials.
If you do use the mugshot resources, you would need to decode the encoded Base64 content into an image using an online tool to see the hobbit mugshot. Here, since we logged in with frodo above during the OAuth process we see frodo's profile and mugshot. Similar representation would take shape depending on which hobbit we logged in with.
Authorization Server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | server: port: 9000 app: credentials: sam: "password" frodo: "password" merry: "password" pippin: "password" spring: security: oauth2: authorizationserver: client: default-client: token: access-token-time-to-live: 1h registration: client-id: "default-client-id" client-secret: "{noop}default-client-secret" client-authentication-methods: - "client_secret_basic" - "client_secret_post" - "none" authorization-grant-types: - "authorization_code" - "client_credentials" redirect-uris: - "http://localhost:6274/oauth/callback" # mcp-inspector - "http://localhost:6274/oauth/callback/debug" # mcp-inspector scopes: - "openid" |
In the configuration above:
- Lines 1 - 2: Declares the port we running the Authorization Server on
- Lines 4 - 9: Declares the in memory configuration of our hobbit users in form of their credentials with keys representing username, and the value the password. NOTE: In production you would have an actual database storing the credentials or an active directory or external vendor where such credentials are stored.
- Line 20: Declares the client-id that will be used to identify the client. This is also the same as we configured in the MCP Inspector seen in images above.
- Line 21: Declares a client-secret in its normal representation, hence the "noop". In production system this would be an encoded value for security purposes.
- Lines 23 - 25: Provides the usual authentication methods supported by the Authorization server.
- Lines 27 - 28: Provides the grant type used in this form of OAuth representation.
- Lines 30 - 31: These are the whitelisted redirect URI's that our Authorization Server supports.
- Line 33: Is the supported scope.
The code for the Authorization Server, is basically ensuring that our OAuth2 flow works and the requests to the resources are authenticated. In case it requires end user to validate themselves, it is configured with basic form login as can be seen in image above.
MCP Secured Server (Resources Capability)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | spring: ai: mcp: server: enabled: true type: SYNC protocol: STREAMABLE streamable-http: mcp-endpoint: /mcp security: oauth2: resourceserver: jwt: issuer-uri: http://localhost:9000 authorizationserver: client: oidc-client: registration: client-id: "default-client-id" client-secret: "{noop}default-client-secret" client-authentication-methods: - "client_secret_basic" - "client_secret_post" - "none" authorization-grant-types: - "authorization_code" - "client_credentials" |
- Lines 4 - 9: This is merely just setting the configuration settings for our MCP Server in form of the protocol used, the mode of communication whether synchronous or asynchronous, and the MCP endpoint that our MCP server would be available on
- Line 15: This is the issuer URI, or in simple terms the URI where the Authorization Server is running. Since we running it on port 9000, we have it configured as such
- Lines 19 - 29: This is the OIDC client configuration which adheres to the same configuration that we have our Authorization Server configured with. If dynamic client registration is required, then the setup is a bit more advanced which goes beyond the scope of our current playground.
- Lines 39 - 40: Obtains the authenticated hobbit from the Spring security context. For this playground, this would be the username of the hobbit.
- Lines 42 - 54: From our pre-compiled profile for each hobbit, the logic here is merely taking the name of the logged in hobbit and loading the profile for it, that we can then return in form of response as Mcp Schema Resource Content.


Comments
Post a Comment