Skip to content

Commit b211c78

Browse files
committed
Update summary output section in KeyCloak setup scripts to display all three client configurationsCo-Authored-By: Tonkotsu <tonkotsu-commits@tonkotsu.ai>
1 parent 10c75e7 commit b211c78

2 files changed

Lines changed: 88 additions & 21 deletions

File tree

scripts/Setup-McpKeycloak.ps1

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
Automates Keycloak realm and client setup for McpServer OIDC authentication.
55
66
.DESCRIPTION
7-
Creates the mcpserver realm, configures mcp-director (public client for Device Flow)
8-
and mcp-web (confidential client for web UI) clients with appropriate protocol mappers,
9-
redirect URIs, and audience claims. Displays client secrets in the setup summary.
7+
Creates the mcpserver realm, configures mcp-server-api (confidential client for JWT validation),
8+
mcp-director (public client for Device Flow), and mcp-web (confidential client for web UI)
9+
clients with appropriate protocol mappers, redirect URIs, and audience claims.
10+
Displays client secrets in the setup summary.
1011
1112
.PARAMETER KeycloakUrl
1213
Base URL of the Keycloak server (default: http://localhost:7080)
@@ -85,7 +86,7 @@ function Invoke-KeycloakApi {
8586
}
8687
}
8788

88-
Write-Host "[1/9] Authenticating with Keycloak..." -ForegroundColor Yellow
89+
Write-Host "[1/10] Authenticating with Keycloak..." -ForegroundColor Yellow
8990

9091
$tokenResponse = Invoke-RestMethod -Uri "$KeycloakUrl/realms/master/protocol/openid-connect/token" -Method Post -Body @{
9192
grant_type = "password"
@@ -97,7 +98,7 @@ $tokenResponse = Invoke-RestMethod -Uri "$KeycloakUrl/realms/master/protocol/ope
9798
$token = $tokenResponse.access_token
9899
Write-Host " ✓ Authenticated as $AdminUser" -ForegroundColor Green
99100

100-
Write-Host "[2/9] Creating realm '$RealmName'..." -ForegroundColor Yellow
101+
Write-Host "[2/10] Creating realm '$RealmName'..." -ForegroundColor Yellow
101102

102103
$existingRealm = try {
103104
Invoke-KeycloakApi -Method Get -Path "/admin/realms/$RealmName" -Token $token
@@ -120,7 +121,32 @@ if ($existingRealm) {
120121
Write-Host " ✓ Realm '$RealmName' created" -ForegroundColor Green
121122
}
122123

123-
Write-Host "[3/9] Creating mcp-director client (public, Device Flow)..." -ForegroundColor Yellow
124+
Write-Host "[3/10] Creating mcp-server-api client (confidential, JWT validation)..." -ForegroundColor Yellow
125+
126+
$apiClientConfig = @{
127+
clientId = "mcp-server-api"
128+
publicClient = $false
129+
serviceAccountsEnabled = $true
130+
standardFlowEnabled = $false
131+
directAccessGrantsEnabled = $false
132+
attributes = @{
133+
"oauth2.device.authorization.grant.enabled" = "false"
134+
}
135+
}
136+
137+
$apiClient = Invoke-KeycloakApi -Method Post -Path "/admin/realms/$RealmName/clients" -Token $token -Body $apiClientConfig
138+
Write-Host " ✓ Client 'mcp-server-api' created" -ForegroundColor Green
139+
140+
$apiClients = Invoke-KeycloakApi -Method Get -Path "/admin/realms/$RealmName/clients?clientId=mcp-server-api" -Token $token
141+
$apiClientId = $apiClients[0].id
142+
143+
Write-Host "[4/10] Retrieving mcp-server-api client secret..." -ForegroundColor Yellow
144+
145+
$apiClientSecret = Invoke-KeycloakApi -Method Get -Path "/admin/realms/$RealmName/clients/$apiClientId/client-secret" -Token $token
146+
$apiSecretValue = $apiClientSecret.value
147+
Write-Host " ✓ Client secret retrieved" -ForegroundColor Green
148+
149+
Write-Host "[5/10] Creating mcp-director client (public, Device Flow)..." -ForegroundColor Yellow
124150

125151
$directorClientConfig = @{
126152
clientId = "mcp-director"
@@ -140,7 +166,7 @@ Write-Host " ✓ Client 'mcp-director' created" -ForegroundColor Green
140166
$directorClients = Invoke-KeycloakApi -Method Get -Path "/admin/realms/$RealmName/clients?clientId=mcp-director" -Token $token
141167
$directorClientId = $directorClients[0].id
142168

143-
Write-Host "[4/9] Adding protocol mappers to mcp-director..." -ForegroundColor Yellow
169+
Write-Host "[6/10] Adding protocol mappers to mcp-director..." -ForegroundColor Yellow
144170

145171
$audienceMapper = @{
146172
name = "mcp-server-api-audience"
@@ -173,7 +199,7 @@ $realmRolesMapper = @{
173199
Invoke-KeycloakApi -Method Post -Path "/admin/realms/$RealmName/clients/$directorClientId/protocol-mappers/models" -Token $token -Body $realmRolesMapper
174200
Write-Host " ✓ Added realm-roles mapper" -ForegroundColor Green
175201

176-
Write-Host "[5/9] Creating mcp-web client (confidential, Standard Flow)..." -ForegroundColor Yellow
202+
Write-Host "[7/10] Creating mcp-web client (confidential, Standard Flow)..." -ForegroundColor Yellow
177203

178204
$webClientConfig = @{
179205
clientId = "mcp-web"
@@ -197,13 +223,13 @@ Write-Host " ✓ Client 'mcp-web' created" -ForegroundColor Green
197223
$webClients = Invoke-KeycloakApi -Method Get -Path "/admin/realms/$RealmName/clients?clientId=mcp-web" -Token $token
198224
$webClientId = $webClients[0].id
199225

200-
Write-Host "[6/9] Retrieving mcp-web client secret..." -ForegroundColor Yellow
226+
Write-Host "[8/10] Retrieving mcp-web client secret..." -ForegroundColor Yellow
201227

202228
$webClientSecret = Invoke-KeycloakApi -Method Get -Path "/admin/realms/$RealmName/clients/$webClientId/client-secret" -Token $token
203229
$webSecretValue = $webClientSecret.value
204230
Write-Host " ✓ Client secret retrieved" -ForegroundColor Green
205231

206-
Write-Host "[7/9] Adding protocol mappers to mcp-web..." -ForegroundColor Yellow
232+
Write-Host "[9/10] Adding protocol mappers to mcp-web..." -ForegroundColor Yellow
207233

208234
$webAudienceMapper = @{
209235
name = "mcp-server-api-audience"
@@ -236,7 +262,7 @@ $webRealmRolesMapper = @{
236262
Invoke-KeycloakApi -Method Post -Path "/admin/realms/$RealmName/clients/$webClientId/protocol-mappers/models" -Token $token -Body $webRealmRolesMapper
237263
Write-Host " ✓ Added realm-roles mapper" -ForegroundColor Green
238264

239-
Write-Host "[8/9] Creating realm roles..." -ForegroundColor Yellow
265+
Write-Host "[10/10] Creating realm roles..." -ForegroundColor Yellow
240266

241267
$roles = @("admin", "agent-manager", "viewer")
242268

@@ -256,7 +282,7 @@ foreach ($role in $roles) {
256282
}
257283
}
258284

259-
Write-Host "[9/9] Setup complete!" -ForegroundColor Green
285+
Write-Host "[10/10] Setup complete!" -ForegroundColor Green
260286
Write-Host ""
261287
Write-Host "========================================" -ForegroundColor Cyan
262288
Write-Host "Setup Summary" -ForegroundColor Cyan
@@ -266,9 +292,13 @@ Write-Host "Realm: $RealmName" -ForegroundColor White
266292
Write-Host "Authority: $KeycloakUrl/realms/$RealmName" -ForegroundColor White
267293
Write-Host ""
268294
Write-Host "Clients configured:" -ForegroundColor White
295+
Write-Host " • mcp-server-api (confidential, JWT validation)" -ForegroundColor White
269296
Write-Host " • mcp-director (public, Device Flow)" -ForegroundColor White
270297
Write-Host " • mcp-web (confidential, Standard Flow)" -ForegroundColor White
271298
Write-Host ""
299+
Write-Host "mcp-server-api client secret:" -ForegroundColor Yellow
300+
Write-Host " $apiSecretValue" -ForegroundColor Cyan
301+
Write-Host ""
272302
Write-Host "mcp-web client secret:" -ForegroundColor Yellow
273303
Write-Host " $webSecretValue" -ForegroundColor Cyan
274304
Write-Host ""
@@ -291,6 +321,7 @@ Write-Host ' "Mcp": {' -ForegroundColor DarkGray
291321
Write-Host ' "Auth": {' -ForegroundColor DarkGray
292322
Write-Host " `"Authority`": `"$KeycloakUrl/realms/$RealmName`"," -ForegroundColor DarkGray
293323
Write-Host ' "Audience": "mcp-server-api",' -ForegroundColor DarkGray
324+
Write-Host " `"ClientSecret`": `"$apiSecretValue`"," -ForegroundColor DarkGray
294325
Write-Host ' "RequireHttpsMetadata": false,' -ForegroundColor DarkGray
295326
Write-Host ' "DirectorClientId": "mcp-director"' -ForegroundColor DarkGray
296327
Write-Host ' }' -ForegroundColor DarkGray

scripts/setup-mcp-keycloak.sh

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ set -euo pipefail
33

44
# McpServer Keycloak Setup Script
55
# Automates Keycloak realm and client setup for McpServer OIDC authentication.
6+
# Creates the mcpserver realm, configures mcp-server-api (confidential client for JWT validation),
7+
# mcp-director (public client for Device Flow), and mcp-web (confidential client for web UI)
8+
# clients with appropriate protocol mappers, redirect URIs, and audience claims.
69

710
KEYCLOAK_URL="${KEYCLOAK_URL:-http://localhost:7080}"
811
ADMIN_USER="${ADMIN_USER:-admin}"
@@ -41,7 +44,7 @@ keycloak_api() {
4144
fi
4245
}
4346

44-
echo "[1/9] Authenticating with Keycloak..."
47+
echo "[1/10] Authenticating with Keycloak..."
4548

4649
TOKEN_RESPONSE=$(curl -s -X POST "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" \
4750
-H "Content-Type: application/x-www-form-urlencoded" \
@@ -59,7 +62,7 @@ fi
5962

6063
echo " ✓ Authenticated as $ADMIN_USER"
6164

62-
echo "[2/9] Creating realm '$REALM_NAME'..."
65+
echo "[2/10] Creating realm '$REALM_NAME'..."
6366

6467
EXISTING_REALM=$(keycloak_api GET "/admin/realms/$REALM_NAME" "$TOKEN" 2>/dev/null || echo "")
6568

@@ -83,7 +86,35 @@ EOF
8386
echo " ✓ Realm '$REALM_NAME' created"
8487
fi
8588

86-
echo "[3/9] Creating mcp-director client (public, Device Flow)..."
89+
echo "[3/10] Creating mcp-server-api client (confidential, JWT validation)..."
90+
91+
API_CLIENT_CONFIG=$(cat <<EOF
92+
{
93+
"clientId": "mcp-server-api",
94+
"publicClient": false,
95+
"serviceAccountsEnabled": true,
96+
"standardFlowEnabled": false,
97+
"directAccessGrantsEnabled": false,
98+
"attributes": {
99+
"oauth2.device.authorization.grant.enabled": "false"
100+
}
101+
}
102+
EOF
103+
)
104+
105+
keycloak_api POST "/admin/realms/$REALM_NAME/clients" "$TOKEN" "$API_CLIENT_CONFIG" > /dev/null
106+
echo " ✓ Client 'mcp-server-api' created"
107+
108+
API_CLIENTS=$(keycloak_api GET "/admin/realms/$REALM_NAME/clients?clientId=mcp-server-api" "$TOKEN")
109+
API_CLIENT_ID=$(echo "$API_CLIENTS" | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4)
110+
111+
echo "[4/10] Retrieving mcp-server-api client secret..."
112+
113+
API_CLIENT_SECRET=$(keycloak_api GET "/admin/realms/$REALM_NAME/clients/$API_CLIENT_ID/client-secret" "$TOKEN")
114+
API_SECRET_VALUE=$(echo "$API_CLIENT_SECRET" | grep -o '"value":"[^"]*"' | cut -d'"' -f4)
115+
echo " ✓ Client secret retrieved"
116+
117+
echo "[5/10] Creating mcp-director client (public, Device Flow)..."
87118

88119
DIRECTOR_CLIENT_CONFIG=$(cat <<EOF
89120
{
@@ -106,7 +137,7 @@ echo " ✓ Client 'mcp-director' created"
106137
DIRECTOR_CLIENTS=$(keycloak_api GET "/admin/realms/$REALM_NAME/clients?clientId=mcp-director" "$TOKEN")
107138
DIRECTOR_CLIENT_ID=$(echo "$DIRECTOR_CLIENTS" | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4)
108139

109-
echo "[4/9] Adding protocol mappers to mcp-director..."
140+
echo "[6/10] Adding protocol mappers to mcp-director..."
110141

111142
AUDIENCE_MAPPER=$(cat <<EOF
112143
{
@@ -145,7 +176,7 @@ EOF
145176
keycloak_api POST "/admin/realms/$REALM_NAME/clients/$DIRECTOR_CLIENT_ID/protocol-mappers/models" "$TOKEN" "$REALM_ROLES_MAPPER" > /dev/null
146177
echo " ✓ Added realm-roles mapper"
147178

148-
echo "[5/9] Creating mcp-web client (confidential, Standard Flow)..."
179+
echo "[7/10] Creating mcp-web client (confidential, Standard Flow)..."
149180

150181
WEB_CLIENT_CONFIG=$(cat <<EOF
151182
{
@@ -172,13 +203,13 @@ echo " ✓ Client 'mcp-web' created"
172203
WEB_CLIENTS=$(keycloak_api GET "/admin/realms/$REALM_NAME/clients?clientId=mcp-web" "$TOKEN")
173204
WEB_CLIENT_ID=$(echo "$WEB_CLIENTS" | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4)
174205

175-
echo "[6/9] Retrieving mcp-web client secret..."
206+
echo "[8/10] Retrieving mcp-web client secret..."
176207

177208
WEB_CLIENT_SECRET=$(keycloak_api GET "/admin/realms/$REALM_NAME/clients/$WEB_CLIENT_ID/client-secret" "$TOKEN")
178209
WEB_SECRET_VALUE=$(echo "$WEB_CLIENT_SECRET" | grep -o '"value":"[^"]*"' | cut -d'"' -f4)
179210
echo " ✓ Client secret retrieved"
180211

181-
echo "[7/9] Adding protocol mappers to mcp-web..."
212+
echo "[9/10] Adding protocol mappers to mcp-web..."
182213

183214
WEB_AUDIENCE_MAPPER=$(cat <<EOF
184215
{
@@ -217,7 +248,7 @@ EOF
217248
keycloak_api POST "/admin/realms/$REALM_NAME/clients/$WEB_CLIENT_ID/protocol-mappers/models" "$TOKEN" "$WEB_REALM_ROLES_MAPPER" > /dev/null
218249
echo " ✓ Added realm-roles mapper"
219250

220-
echo "[8/9] Creating realm roles..."
251+
echo "[10/10] Creating realm roles..."
221252

222253
for role in admin agent-manager viewer; do
223254
EXISTING_ROLE=$(keycloak_api GET "/admin/realms/$REALM_NAME/roles/$role" "$TOKEN" 2>/dev/null || echo "")
@@ -236,7 +267,7 @@ EOF
236267
fi
237268
done
238269

239-
echo "[9/9] Setup complete!"
270+
echo "[10/10] Setup complete!"
240271
echo ""
241272
echo "========================================"
242273
echo "Setup Summary"
@@ -246,9 +277,13 @@ echo "Realm: $REALM_NAME"
246277
echo "Authority: $KEYCLOAK_URL/realms/$REALM_NAME"
247278
echo ""
248279
echo "Clients configured:"
280+
echo " • mcp-server-api (confidential, JWT validation)"
249281
echo " • mcp-director (public, Device Flow)"
250282
echo " • mcp-web (confidential, Standard Flow)"
251283
echo ""
284+
echo "mcp-server-api client secret:"
285+
echo " $API_SECRET_VALUE"
286+
echo ""
252287
echo "mcp-web client secret:"
253288
echo " $WEB_SECRET_VALUE"
254289
echo ""
@@ -271,6 +306,7 @@ echo ' "Mcp": {'
271306
echo ' "Auth": {'
272307
echo " \"Authority\": \"$KEYCLOAK_URL/realms/$REALM_NAME\","
273308
echo ' "Audience": "mcp-server-api",'
309+
echo " \"ClientSecret\": \"$API_SECRET_VALUE\","
274310
echo ' "RequireHttpsMetadata": false,'
275311
echo ' "DirectorClientId": "mcp-director"'
276312
echo ' }'

0 commit comments

Comments
 (0)