-
Notifications
You must be signed in to change notification settings - Fork 77
Feature/keycloak vscode redirects #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/keycloak vscode redirects #22
Conversation
- Add "Use Keycloak OAuth MCP server with GitHub Copilot" section to README - Add step-by-step instructions for connecting VS Code to deployed MCP server - Include screenshots for authentication flow (allow access, sign-in, redirect) - Add Spanish translation of the new section to spanish/README.md - Configure VS Code redirect URIs in Keycloak realm for DCR support - Update infra and keycloak configs for VS Code OAuth redirect handling
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request implements comprehensive Keycloak OAuth 2.0 integration for the MCP (Model Context Protocol) server, enabling VS Code and GitHub Copilot Chat to authenticate users dynamically. The changes standardize Keycloak routing under /auth, introduce a custom authentication provider with Dynamic Client Registration (DCR) support, and provide detailed end-user documentation with screenshots.
Key Changes:
- Keycloak now serves all content under
/authpath via--http-relative-path=/authflag, with corresponding updates to all infrastructure and environment configurations - New
KeycloakAuthProviderclass implements a minimal DCR proxy to work around Keycloak's token authentication method limitation - VS Code redirect URIs and a demo test user are pre-configured in the Keycloak realm for seamless integration
Reviewed changes
Copilot reviewed 13 out of 18 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
servers/keycloak_provider.py |
New authentication provider with DCR proxy and debug endpoints for Keycloak integration |
servers/auth_mcp.py |
Refactored to use KeycloakAuthProvider with debug middleware for token claim inspection |
keycloak/realm.json |
Updated with VS Code client configuration, demo user credentials, and expanded trusted hosts |
keycloak/Dockerfile |
Added --http-relative-path=/auth flag to serve Keycloak under /auth path |
infra/main.bicep |
Updated all Keycloak URLs to include /auth prefix for proper routing |
infra/http-routes.bicep |
Removed path rewriting since Keycloak now handles /auth internally |
infra/write_env.sh |
Added KEYCLOAK_AGENT_REALM_URL to environment script |
infra/write_env.ps1 |
Added KEYCLOAK_AGENT_REALM_URL to PowerShell environment script |
agents/agentframework_http.py |
Removed Keycloak authentication headers to simplify agent deployment |
agents/keycloak_auth.py |
Added clarification about using direct container URLs |
README.md |
Added step-by-step guide with screenshots for GitHub Copilot Chat authentication |
spanish/README.md |
Spanish translation of the new Copilot Chat authentication guide |
.vscode/mcp.json |
Added production MCP server configuration |
screenshots/kc-select-tools-4.jpg |
Screenshot for documentation (binary file) |
Comments suppressed due to low confidence (1)
servers/keycloak_provider.py:216
- This import of module json is redundant, as it was previously imported on line 27.
request_data = json.loads(body)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
servers/auth_mcp.py
Outdated
| required_scopes=[], | ||
| # Audience should match the value in Keycloak's mcp:tools scope | ||
| # Default to the base_url for local dev | ||
| audience=None |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting audience=None explicitly disables audience validation for JWT tokens, which reduces security. The comment mentions this should match Keycloak's audience mapper, so consider setting a proper audience value or documenting why audience validation is intentionally disabled.
…de-redirects adding main changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 13 out of 18 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
.vscode/mcp.json
Outdated
| "0.0.0.0:5678", | ||
| "servers/basic_mcp_stdio.py" | ||
| ] | ||
| }, |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a trailing comma after the last server definition (line 30) which is followed by an empty line before the closing brace. While some JSON parsers tolerate trailing commas, this violates the JSON specification and may cause parsing errors in strict JSON parsers. Remove the comma on line 30 or the empty line 31 to ensure valid JSON.
| }, | |
| } |
| "http://127.0.0.1/*", | ||
| "http://localhost/*", |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The redirectUris configuration includes overly permissive wildcards for localhost ("http://127.0.0.1/" and "http://localhost/"). This allows any path on localhost to be used as a redirect URI, which could be exploited in authorization code interception attacks. Consider restricting these to specific ports or paths, such as "http://localhost:*/redirect" or "http://127.0.0.1:*/redirect" to limit the attack surface.
| "http://127.0.0.1/*", | |
| "http://localhost/*", | |
| "http://127.0.0.1:*/redirect", | |
| "http://localhost:*/redirect", |
| except Exception as e: | ||
| logger.error(f"Failed to fetch Keycloak metadata: {e}") | ||
| return JSONResponse( | ||
| { | ||
| "error": "server_error", | ||
| "error_description": f"Failed to fetch Keycloak metadata: {e}", |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message includes the raw exception details using an f-string, which could potentially leak sensitive information such as connection details, internal paths, or stack traces to clients. Consider logging the full exception details server-side but returning a more generic error message to the client, or at minimum sanitizing the exception message before including it in the response.
| except Exception as e: | |
| logger.error(f"Failed to fetch Keycloak metadata: {e}") | |
| return JSONResponse( | |
| { | |
| "error": "server_error", | |
| "error_description": f"Failed to fetch Keycloak metadata: {e}", | |
| except Exception: | |
| logger.exception("Failed to fetch Keycloak metadata") | |
| return JSONResponse( | |
| { | |
| "error": "server_error", | |
| "error_description": "Failed to fetch Keycloak metadata. Please contact the server administrator.", |
| output KEYCLOAK_REALM_URL string = useKeycloak ? '${httpRoutes!.outputs.routeConfigUrl}/auth/realms/${keycloakRealmName}' : '' | ||
| output KEYCLOAK_ADMIN_CONSOLE string = useKeycloak ? '${httpRoutes!.outputs.routeConfigUrl}/auth/admin' : '' | ||
| output KEYCLOAK_ADMIN_CONSOLE string = useKeycloak ? '${httpRoutes!.outputs.routeConfigUrl}/auth/admin/master/console' : '' | ||
| output KEYCLOAK_DIRECT_URL string = keycloak.outputs.uri |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The output KEYCLOAK_DIRECT_URL is not conditional on useKeycloak, which means it will attempt to access keycloak.outputs.uri even when Keycloak is not deployed. This will cause a deployment error when mcpAuthProvider is not set to "keycloak". Consider making this conditional like the other Keycloak outputs: output KEYCLOAK_DIRECT_URL string = useKeycloak ? keycloak.outputs.uri : ''
| output KEYCLOAK_DIRECT_URL string = keycloak.outputs.uri | |
| output KEYCLOAK_DIRECT_URL string = useKeycloak ? keycloak.outputs.uri : '' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 13 out of 18 changed files in this pull request and generated 18 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| Para usar el servidor MCP desplegado con GitHub Copilot Chat: | ||
|
|
||
| 1. Para evitar conflictos, detén los servidores MCP de `mcp.json` y deshabilitá los servidores MCP de gastos en las herramientas de GitHub Copilot Chat. |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The verb form should use "Detenga" instead of "detené" for consistency with formal instructions, and "desactive" instead of "deshabilitá". The instruction mixes formal and informal Spanish (vos/tú forms).
| 1. Para evitar conflictos, detén los servidores MCP de `mcp.json` y deshabilitá los servidores MCP de gastos en las herramientas de GitHub Copilot Chat. | |
| 1. Para evitar conflictos, Detenga los servidores MCP de `mcp.json` y desactive los servidores MCP de gastos en las herramientas de GitHub Copilot Chat. |
|
|
||
| 1. Para evitar conflictos, detén los servidores MCP de `mcp.json` y deshabilitá los servidores MCP de gastos en las herramientas de GitHub Copilot Chat. | ||
| 2. Seleccioná "MCP: Add Server" desde la Paleta de Comandos de VS Code | ||
| 3. Seleccioná "HTTP" como tipo de servidor |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The verb form should use "Seleccione" instead of "Seleccioná" for consistency with formal instructions throughout the documentation.
| 3. Seleccioná "HTTP" como tipo de servidor | |
| 3. Seleccione "HTTP" como tipo de servidor |
| 1. Para evitar conflictos, detén los servidores MCP de `mcp.json` y deshabilitá los servidores MCP de gastos en las herramientas de GitHub Copilot Chat. | ||
| 2. Seleccioná "MCP: Add Server" desde la Paleta de Comandos de VS Code | ||
| 3. Seleccioná "HTTP" como tipo de servidor | ||
| 4. Ingresá la URL del servidor MCP desde `azd env get-value MCP_SERVER_URL` |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The verb form should use "Ingrese" instead of "Ingresá" for consistency with formal instructions throughout the documentation.
| 4. Ingresá la URL del servidor MCP desde `azd env get-value MCP_SERVER_URL` | |
| 4. Ingrese la URL del servidor MCP desde `azd env get-value MCP_SERVER_URL` |
| 2. Seleccioná "MCP: Add Server" desde la Paleta de Comandos de VS Code | ||
| 3. Seleccioná "HTTP" como tipo de servidor | ||
| 4. Ingresá la URL del servidor MCP desde `azd env get-value MCP_SERVER_URL` | ||
| 5. Deberías ver una pantalla de autenticación de Keycloak abrirse en tu navegador. Seleccioná "Allow access": |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The verb form should use "Debería" instead of "Deberías" for consistency with formal instructions throughout the documentation.
| 5. Deberías ver una pantalla de autenticación de Keycloak abrirse en tu navegador. Seleccioná "Allow access": | |
| 5. Debería ver una pantalla de autenticación de Keycloak abrirse en tu navegador. Seleccioná "Allow access": |
| 9. Probálo con una consulta de seguimiento de gastos: | ||
|
|
||
| ```text | ||
| Registrá un gasto de 75 dólares de útiles de oficina en mi visa el viernes pasado |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The verb form should use "Registre" instead of "Registrá" for consistency with formal instructions throughout the documentation.
| Registrá un gasto de 75 dólares de útiles de oficina en mi visa el viernes pasado | |
| Registre un gasto de 75 dólares de útiles de oficina en mi visa el viernes pasado |
|
|
||
|  | ||
|
|
||
| 8. Habilitá el servidor MCP en las herramientas de GitHub Copilot Chat: |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The verb form should use "Habilite" instead of "Habilitá" for consistency with formal instructions throughout the documentation.
| 8. Habilitá el servidor MCP en las herramientas de GitHub Copilot Chat: | |
| 8. Habilite el servidor MCP en las herramientas de GitHub Copilot Chat: |
| "enabled": true, | ||
| "email": "testuser@example.com", | ||
| "firstName": "Test", | ||
| "lastName": "User", | ||
| "credentials": [ | ||
| { | ||
| "type": "password", | ||
| "value": "testpass", | ||
| "temporary": false | ||
| } | ||
| ] |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The demo user has a hardcoded password in plain text. While acceptable for development/demo purposes, this configuration file appears to be used in production deployments based on the infrastructure code. Consider documenting that this user should be removed or the password changed immediately after deployment, or use environment variable substitution for the password value.
| "enabled": true, | |
| "email": "testuser@example.com", | |
| "firstName": "Test", | |
| "lastName": "User", | |
| "credentials": [ | |
| { | |
| "type": "password", | |
| "value": "testpass", | |
| "temporary": false | |
| } | |
| ] | |
| "enabled": false, | |
| "email": "testuser@example.com", | |
| "firstName": "Test", | |
| "lastName": "User", | |
| "attributes": { | |
| "note": [ | |
| "Demo user. Remove this user or set a secure password immediately after deployment." | |
| ] | |
| } |
| body = await request.body() | ||
|
|
||
| # Forward to Keycloak's DCR endpoint | ||
| async with httpx.AsyncClient(timeout=10.0) as client: |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The timeout value of 10.0 seconds is hardcoded. Consider making this configurable through a class parameter or constant, as network conditions and Keycloak response times may vary across different deployment environments.
| 2. Seleccioná "MCP: Add Server" desde la Paleta de Comandos de VS Code | ||
| 3. Seleccioná "HTTP" como tipo de servidor | ||
| 4. Ingresá la URL del servidor MCP desde `azd env get-value MCP_SERVER_URL` | ||
| 5. Deberías ver una pantalla de autenticación de Keycloak abrirse en tu navegador. Seleccioná "Allow access": |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The verb form should use "Seleccione" instead of "Seleccioná" for consistency with formal instructions throughout the documentation.
| 2. Seleccioná "MCP: Add Server" desde la Paleta de Comandos de VS Code | |
| 3. Seleccioná "HTTP" como tipo de servidor | |
| 4. Ingresá la URL del servidor MCP desde `azd env get-value MCP_SERVER_URL` | |
| 5. Deberías ver una pantalla de autenticación de Keycloak abrirse en tu navegador. Seleccioná "Allow access": | |
| 2. Seleccione "MCP: Add Server" desde la Paleta de Comandos de VS Code | |
| 3. Seleccione "HTTP" como tipo de servidor | |
| 4. Ingresá la URL del servidor MCP desde `azd env get-value MCP_SERVER_URL` | |
| 5. Deberías ver una pantalla de autenticación de Keycloak abrirse en tu navegador. Seleccione "Allow access": |
| "http://127.0.0.1/*", | ||
| "http://localhost/*", |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The wildcard redirect URIs for localhost and 127.0.0.1 are overly permissive. Consider restricting to specific port ranges or paths to reduce the attack surface. For example, use specific ports like "http://127.0.0.1:5000/" instead of "http://127.0.0.1/".
This pull request introduces significant improvements to Keycloak integration for OAuth authentication, especially for VS Code and GitHub Copilot Chat users. The changes standardize Keycloak's route under
/auth, simplify and enhance the realm configuration, update deployment scripts and infrastructure to match, and improve documentation for end users. Additionally, the authentication logic is refactored for better maintainability and debugging.Keycloak Integration and Route Standardization:
/authusing the--http-relative-path=/authflag in its Dockerfile, ensuring consistent routing for authentication endpoints./authpath, ensuring correct routing and token issuer values for both server and agent components. [1] [2] [3] [4] [5] [6] [7]Keycloak Realm and Client Configuration Updates:
vscode-mcp-clientwith pre-configured redirect URIs for VS Code, and a demo user for easier testing. Trusted hosts are expanded to include VS Code domains and Docker networking addresses, and additional protocol mappers are added for compatibility. [1] [2] [3] [4] [5]Authentication Logic and Middleware Improvements:
KeycloakAuthProviderwith Dynamic Client Registration (DCR) support, replacing direct JWT verification, and introduces a debug middleware to log token claims for easier troubleshooting. [1] [2] [3]Documentation and Developer Experience: