Modern identity systems require intelligent, context-aware, and secure communication between authentication components. Model Context Protocol (MCP) enables AI agents and identity servers like Keycloak to share dynamic session context and decision boundaries. In this guide, you’ll learn how to build an MCP server for Keycloak using Quarkus, a fast Java framework for microservices, and the Goose CLI, a lightweight tool for managing MCP configurations and state.

We’ll cover:

  • What MCP is and why it matters

  • The architecture of an MCP-enabled Keycloak server

  • Bootstrapping a Quarkus MCP service

  • Integrating with Keycloak

  • Using Goose CLI to manage and test contexts

Understanding the Model Context Protocol (MCP)

Model Context Protocol (MCP) is an emerging spec designed for sharing structured interaction context across systems involving models (AI or rule-based). In the case of Keycloak, MCP enables passing dynamic identity-related information (session status, role decisions, adaptive policy hints) to LLMs or other services that evaluate or enforce access control.

Benefits of MCP with Keycloak:

  • Enables dynamic authorization based on model feedback.

  • Supports context chaining between services.

  • Makes identity context auditable and versioned.

  • Bridges the gap between AI policy agents and IAM systems.

Architecture Overview: MCP with Keycloak

Here’s a high-level view of how the system will work:

sql
+-------------+ HTTP/MCP +-----------------+
| Goose CLI | <-------------------> | MCP Server API |
+-------------+ | (Quarkus App) |
+--------+--------+
|
Keycloak SPI Plugin
|
+------v------+
| Keycloak |
+-------------+
  1. The Quarkus MCP server exposes MCP endpoints (e.g., POST /context, GET /context/:id) and manages contextual model state.

  2. Keycloak communicates with this server using a Service Provider Interface (SPI) plugin.

  3. The Goose CLI interacts with the MCP server to inspect or simulate state changes.

Setting Up the Quarkus Project

Let’s create the Quarkus project that will serve MCP context data.

bash
mvn io.quarkus:quarkus-maven-plugin:create \
-DprojectGroupId=com.example \
-DprojectArtifactId=keycloak-mcp-server \
-DclassName="com.example.mcp.ContextResource" \
-Dpath="/context" \
-Dextensions="resteasy-reactive, jackson, h2, hibernate-orm-panache"

This sets up a Quarkus REST API project with JPA and H2 in-memory DB.

Define the MCP Context Entity

java
@Entity
public class ContextModel extends PanacheEntity {
public String sessionId;
public String userId;
public String role;
public String status;
public Instant timestamp;
}

This represents a piece of contextual identity data, versioned by timestamp.

Create REST Endpoints

java
@Path("/context")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ContextResource {
@POST
public Response create(ContextModel context) {
context.timestamp = Instant.now();
context.persist();
return Response.status(Response.Status.CREATED).entity(context).build();
}@GET
@Path(“/{id}”)
public Response get(@PathParam(“id”) Long id) {
var context = ContextModel.findById(id);
return context != null ? Response.ok(context).build() :
Response.status(Response.Status.NOT_FOUND).build();
}@GET
public List<ContextModel> list() {
return ContextModel.listAll(Sort.by(“timestamp”).descending());
}
}

This API enables Keycloak and external tools to read/write model context.

Configure the MCP Quarkus Server

application.properties

properties
quarkus.datasource.db-kind=h2
quarkus.datasource.jdbc.url=jdbc:h2:mem:mcp
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.http.port=8081

Run the app:

bash
./mvnw quarkus:dev

Test it with:

bash
curl -X POST http://localhost:8081/context \
-H "Content-Type: application/json" \
-d '{"sessionId":"abc123","userId":"jdoe","role":"admin","status":"active"}'

Connect Keycloak to MCP (Custom SPI)

Create a Keycloak SPI plugin to push and fetch context data from the Quarkus MCP service.

Example SPI Plugin (simplified):

java

public class MCPContextProvider implements EventListenerProvider {

private final String mcpServerUrl = “http://localhost:8081/context”;

@Override
public void onEvent(Event event) {
if (event.getType().equals(EventType.LOGIN)) {
sendContextToMCP(event);
}
}

private void sendContextToMCP(Event event) {
var context = Map.of(
“sessionId”, event.getSessionId(),
“userId”, event.getUserId(),
“role”, “user”, // resolve via token or claim
“status”, “authenticated”
);
HttpClient.postJson(mcpServerUrl, context);
}

@Override
public void close() {}
}

Package and deploy the plugin into your Keycloak providers directory, and register it via standalone.xml or keycloak.conf.

Managing Contexts with Goose CLI

Install Goose CLI (or simulate using a shell script for now):

bash
npm install -g goose-cli

Example Commands:

bash
# List recent context entries
goose context list --url http://localhost:8081/context
# Inject a manual test context
goose context inject –url http://localhost:8081/context \
–data ‘{“sessionId”:”test42″,”userId”:”admin”,”role”:”superadmin”,”status”:”elevated”}’

Sample Output:

yaml
Injected context with ID 9
userId: admin
status: elevated

You can also extend Goose CLI to simulate model feedback by updating a field like status="suspended" based on AI evaluation.

Optional: Enabling Model Feedback Loop

To support model input, add a PATCH method to your Quarkus app:

java
@PATCH
@Path("/{id}")
public Response update(@PathParam("id") Long id, Map<String, String> updates) {
ContextModel context = ContextModel.findById(id);
if (context == null) return Response.status(Response.Status.NOT_FOUND).build();
updates.forEach((key, value) -> {
switch (key) {
case “status” -> context.status = value;
case “role” -> context.role = value;
}
});
context.persist();
return Response.ok(context).build();
}

Now you can enable AI-based model agents to adjust the context dynamically, e.g., reduce privileges, flag anomalies, or escalate access.

Secure MCP Server with Keycloak Token

Use Quarkus OIDC to secure the MCP server, accepting tokens issued by your Keycloak realm.

Add extension:

bash
./mvnw quarkus:add-extension -Dextensions="oidc"

Add config:

properties
quarkus.oidc.auth-server-url=http://localhost:8080/realms/master
quarkus.oidc.client-id=mcp-server
quarkus.oidc.credentials.secret=your-client-secret
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated

This makes sure only trusted entities (like Keycloak SPI or Goose CLI with token) can write to the MCP store.

Conclusion

Bringing together identity management, real-time context sharing, and AI feedback mechanisms is a pivotal advancement for modern digital systems. With Model Context Protocol (MCP), Keycloak becomes more than an identity provider — it becomes a dynamic, intelligent participant in broader decision-making workflows.

Using Quarkus, we built a performant and extensible MCP server with minimal setup. Its REST endpoints, backed by a persistent model, provide structured access to contextual data. Then, with Goose CLI, we injected and managed contexts directly, enabling easy testing, debugging, and simulated AI interaction.

On the Keycloak side, a custom SPI plugin let us push session and identity events into the MCP server, forming a real-time loop between IAM and model logic. The setup also accommodates token-based security, ensuring that only trusted actors contribute or consume context data.

This architecture is particularly powerful for:

  • Adaptive access control (adjust roles based on model trust)

  • Auditing user interactions across services

  • Bridging AI agents with secure systems via a protocolized interface

As context-based computing and AI decision systems become ubiquitous, MCP will emerge as a standard glue between trust, behavior, and control. And by using tools like Quarkus and Goose CLI, you can stand at the forefront of this transformation — with Keycloak acting not just as a gatekeeper, but as a contextual partner in trust orchestration.