keycloak-mcp-server

Parametric Collapse Strategy Implementation

Overview

This project implements the “Parametric Collapse” strategy to consolidate multiple tool classes into a single, generic KeycloakTool class. This design pattern significantly reduces tool proliferation and improves API maintainability.

The Problem

Before the implementation, the project had 7+ separate tool classes:

This resulted in 37+ individual tool methods exposed through the MCP protocol, creating a cluttered API surface.

The Solution

The new KeycloakTool class consolidates all operations into:

Architecture


 KeycloakTool
 (Single Unified Tool Class)

 + executeKeycloakOperation()
 - operation: KeycloakOperation
 - params: JSON


 Routes to appropriate service





 UserService RealmService ...etc

Benefits

  1. Reduced Tool Count: From 37+ tools to 1 tool
  2. Better Maintainability: All routing logic in one place
  3. Consistent Error Handling: Centralized exception management
  4. Type Safety: Enum-based operation selection
  5. Flexible Parameters: JSON allows optional and complex parameters
  6. Easy Extension: Add new operations by adding enum values and cases

Usage Examples

User Operations

Get all users in a realm

{
 "operation": "GET_USERS",
 "params": {
 "realm": "quarkus"
 }
}

Create a new user

{
 "operation": "CREATE_USER",
 "params": {
 "realm": "quarkus",
 "username": "jdoe",
 "firstName": "John",
 "lastName": "Doe",
 "email": "john.doe@example.com",
 "password": "SecurePass123!"
 }
}

Add role to user

{
 "operation": "ADD_ROLE_TO_USER",
 "params": {
 "realm": "quarkus",
 "userId": "1eed6a8e-a853-4597-b4c6-c4c2533546a0",
 "roleName": "admin"
 }
}

Reset user password

{
 "operation": "RESET_PASSWORD",
 "params": {
 "realm": "quarkus",
 "userId": "1eed6a8e-a853-4597-b4c6-c4c2533546a0",
 "newPassword": "NewSecurePass456!",
 "temporary": false
 }
}

Realm Operations

Get all realms

{
 "operation": "GET_REALMS",
 "params": {}
}

Create a realm

{
 "operation": "CREATE_REALM",
 "params": {
 "realmName": "my-new-realm",
 "displayName": "My New Realm",
 "enabled": true
 }
}

Client Operations

Get all clients

{
 "operation": "GET_CLIENTS",
 "params": {
 "realm": "quarkus"
 }
}

Create a client

{
 "operation": "CREATE_CLIENT",
 "params": {
 "realm": "quarkus",
 "clientId": "my-app",
 "redirectUris": "http://localhost:8080/*"
 }
}

Generate new client secret

{
 "operation": "GENERATE_CLIENT_SECRET",
 "params": {
 "realm": "quarkus",
 "clientId": "my-app"
 }
}

Group Operations

Get all groups

{
 "operation": "GET_GROUPS",
 "params": {
 "realm": "quarkus"
 }
}

Create a group

{
 "operation": "CREATE_GROUP",
 "params": {
 "realm": "quarkus",
 "groupName": "Developers"
 }
}

Create a subgroup

{
 "operation": "CREATE_SUBGROUP",
 "params": {
 "realm": "quarkus",
 "parentGroupId": "abc123",
 "subGroupName": "Backend Developers"
 }
}

Authentication Operations

Get authentication flows

{
 "operation": "GET_AUTHENTICATION_FLOWS",
 "params": {
 "realm": "quarkus"
 }
}

Get flow executions

{
 "operation": "GET_FLOW_EXECUTIONS",
 "params": {
 "realm": "quarkus",
 "flowAlias": "browser"
 }
}

Complete Operation List

User Operations (15)

Realm Operations (3)

Client Operations (8)

Role Operations (2)

Group Operations (6)

Identity Provider Operations (3)

Authentication Operations (6)

Implementation Details

Service Layer

The KeycloakTool directly injects and uses all service classes:

Error Handling

All operations are wrapped in try-catch blocks with:

JSON Processing

Uses Jackson ObjectMapper for:

Migration from Old Tools

If you were using the old individual tool classes, here is how to migrate:

Before (UserTool.getUsers)

@Tool(description = "Get all users from a keycloak realm")
String getUsers(String realm)

After (KeycloakTool)

executeKeycloakOperation(
 KeycloakOperation.GET_USERS,
 "{\"realm\": \"quarkus\"}"
)

Extending the Tool

To add a new operation:

  1. Add enum value to KeycloakOperation:
    public enum KeycloakOperation {
     // ... existing operations
     MY_NEW_OPERATION
    }
    
  2. Add case to switch statement in executeKeycloakOperation():
    case MY_NEW_OPERATION:
     return myService.myNewMethod(
     paramsNode.get("param1").asText(),
     paramsNode.get("param2").asInt()
     );
    
  3. Update tool description with the new operation name

Design Pattern Benefits

Before: Tool Explosion

UserTool {
 getUsers()
 createUser()
 deleteUser()
 ...
}

ClientTool {
 getClients()
 createClient()
 deleteClient()
 ...
}

// 7+ more tool classes...

After: Parametric Collapse

KeycloakTool {
 executeKeycloakOperation(
 operation: KeycloakOperation,
 params: JSON
 )
}

The AI model sees 1 tool definition instead of 37+ tool definitions, making it:

Performance Considerations

Testing

To test the implementation:

# Compile the project
mvn clean compile

# Run tests
mvn test

# Build the native executable
mvn package -Pnative

Conclusion

The Parametric Collapse strategy successfully reduced the Keycloak MCP Server from 37+ individual tools to 1 unified tool, while maintaining all functionality and improving maintainability. This pattern can be applied to any domain where you have multiple similar operations that can be categorized and parameterized.