Skip to content

Comments

Fix MCP Auth issues in API to MCP usecase#13574

Open
AnuGayan wants to merge 7 commits intowso2:masterfrom
AnuGayan:master-mcp
Open

Fix MCP Auth issues in API to MCP usecase#13574
AnuGayan wants to merge 7 commits intowso2:masterfrom
AnuGayan:master-mcp

Conversation

@AnuGayan
Copy link
Contributor

@AnuGayan AnuGayan commented Feb 7, 2026

This pull request introduces several improvements and fixes related to MCP (Multi-Channel Protocol) request handling, authentication, and protocol validation in the API Gateway. The changes primarily focus on consistent usage of constants, improving authentication flows for MCP requests, refining error responses, and enhancing protocol version validation. Below are the most important changes grouped by theme:

MCP Request Handling and Protocol Validation:

  • Standardized the usage of the MCP_HTTP_METHOD constant across the codebase for setting and retrieving the MCP HTTP method, improving maintainability and reducing hard-coded string usage. [1] [2] [3] [4] [5] [6] [7]
  • Improved protocol version validation in MCP initialization requests by ensuring that the protocolVersion field is present and non-empty, and removing redundant protocol version checks.
  • Removed the check for allowed methods in MCPUtils.validateRequest, deferring method validation to other parts of the code.
  • Updated the logic to remove the MCP session ID header for INITIALIZE methods, ensuring session management is handled correctly.
  • Adjusted the isNoAuthMCPRequest method to return false for unsupported methods instead of throwing an exception, making the flow more robust.

Authentication Flow and Error Handling:

  • Enhanced the handling of unauthenticated MCP requests by aligning the flow with REST no-auth cases, including invoking handleNoAuthentication, setting API parameters, and calling extension listeners.
  • Refined the construction of the WWW-Authenticate header for authentication failures by directly building the resource metadata URL and optionally including a DCR (Dynamic Client Registration) endpoint if available. This provides better guidance to clients on how to register and obtain tokens.
  • Introduced a new method to retrieve the DCR endpoint based on the key manager configuration, supporting improved interoperability with external identity providers.

Scopes and Resource Management:

  • Ensured the "default" scope is always included in the list of all scopes for an API, both when iterating over resources and as a fallback, to guarantee proper scope assignment.

Test Improvements:

  • Added necessary imports and class preparations in the authentication handler test case to support new logic related to key managers and DCR endpoint retrieval. [1] [2] [3]

These changes collectively improve the reliability, maintainability, and interoperability of MCP request handling and authentication in the API Gateway.

google-labs-jules bot and others added 4 commits February 1, 2026 08:04
- Updated handleRequest to handle MCP no-auth requests.
- Implemented getDcrEndpoint helper to retrieve the DCR endpoint from the associated Key Manager.
- Updated handleAuthFailure to include the dcr parameter in the WWW-Authenticate header for MCP APIs.
- Added test cases to verify the new logic.

Co-authored-by: AnuGayan <19290404+AnuGayan@users.noreply.github.com>
…845' into master-mcp

# Conflicts:
#	components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/APIAuthenticationHandler.java
#	components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/handlers/security/APIAuthenticationHandlerTestCase.java
@coderabbitai
Copy link

coderabbitai bot commented Feb 7, 2026

📝 Walkthrough

Walkthrough

Centralizes MCP_HTTP_METHOD constant and updates MCP handling across gateway: request initialization, auth flow (including DCR endpoint lookup and WWW-Authenticate header construction), validation relaxation, scope aggregation, and added/updated tests for MCP no-auth and DCR scenarios.

Changes

Cohort / File(s) Summary
MCP Constant
components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java
Added public constant MCP_HTTP_METHOD.
MCP HTTP Method Adoption
components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/.../jwt/JWTValidator.java, components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/.../oauth/OAuthAuthenticator.java
Replaced hard-coded "MCP_HTTP_METHOD" keys with MCP_HTTP_METHOD constant; removed an unused import in JWTValidator.
MCP Init & Routing
components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/.../mcp/McpInitHandler.java
Set MCP_HTTP_METHOD property alongside other MCP props; added METHOD_INITIALIZE branch to strip MCP_SESSION_ID; changed unknown-method handling to return false instead of throwing.
Authentication & No-Auth Flow
components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/.../security/APIAuthenticationHandler.java
For MCP no-auth: call handleNoAuthentication, set API params on message context, invoke ExtensionListenerUtil.postProcessRequest; construct WWW-Authenticate resource_metadata header using HTTPS, host, contextPath and optionally include DCR via new getDcrEndpoint() helper; conditionalized debug logs.
MCP Validation Relaxation
components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/.../utils/MCPUtils.java
Removed allowed-methods validation and relaxed protocolVersion check to require presence only (unsupported versions are accepted).
Scope Aggregation
components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/.../mediators/McpMediator.java
Appended "default" scope to aggregated allScopes result.
Tests: MCP & DCR
components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/.../APIAuthenticationHandlerTestCase.java
Added testHandleRequestForMCPNoAuth and testHandleAuthFailureForMCPWithDCR; updated exception constant usage; adjusted metric/timer verifications; expanded PrepareForTest/imports for KeyManagerHolder, DataHolder, and DTOs.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Auth as APIAuthenticationHandler
    participant KMHolder as KeyManagerHolder
    participant KMDto as KeyManagerDto
    participant Ext as ExtensionListenerUtil

    Client->>Auth: Send MCP request
    Auth->>Auth: Detect MCP path and MCP_HTTP_METHOD
    alt No-Auth or auth failure
        Auth->>Auth: handleNoAuthentication(messageContext)
        Auth->>Auth: setAPIParametersToMessageContext()
        Auth->>KMHolder: lookup KeyManager for apiUUID
        KMHolder-->>KMDto: return KeyManagerDto (may include DCR endpoint)
        Auth->>Auth: build WWW-Authenticate header (resource_metadata + optional dcr)
        Auth->>Ext: postProcessRequest(messageContext, type)
        Ext-->>Auth: post-processing complete
        Auth-->>Client: return response (with WWW-Authenticate header if applicable)
    else Authenticated
        Auth-->>Client: continue normal auth flow
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix MCP Auth issues in API to MCP usecase' accurately describes the primary focus of the changeset on MCP authentication handling improvements.
Description check ✅ Passed The description thoroughly documents the changes across MCP request handling, authentication flows, protocol validation, and test improvements, directly relating to the changeset modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@@ -159,6 +161,7 @@ private String buildMCPRequest(MessageContext messageContext) throws McpExceptio

method = request.getMethod();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 1

Suggested change
method = request.getMethod();
method = request.getMethod();
log.info("MCP request received with method: " + method);

@@ -183,10 +186,14 @@ private String buildMCPRequest(MessageContext messageContext) throws McpExceptio
}
}
if (backendOperation != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 2

Suggested change
if (backendOperation != null) {
if (backendOperation != null) {
log.debug("Backend operation found for tool: " + toolName + ", HTTP method: " + backendOperation.getVerb() + ", target: " + backendOperation.getTarget());

Comment on lines +485 to +487
handleNoAuthentication(messageContext);
setAPIParametersToMessageContext(messageContext);
return ExtensionListenerUtil.postProcessRequest(messageContext, type);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 3

Suggested change
handleNoAuthentication(messageContext);
setAPIParametersToMessageContext(messageContext);
return ExtensionListenerUtil.postProcessRequest(messageContext, type);
handleNoAuthentication(messageContext);
setAPIParametersToMessageContext(messageContext);
log.info("Authentication skipped for MCP no-auth request");
return ExtensionListenerUtil.postProcessRequest(messageContext, type);

Comment on lines +989 to +995

if (keyManagerDto != null && keyManagerDto.getKeyManager() != null) {
try {
org.wso2.carbon.apimgt.api.model.KeyManagerConfiguration config =
keyManagerDto.getKeyManager().getKeyManagerConfiguration();
return (String) config.getParameter(APIConstants.KeyManager.CLIENT_REGISTRATION_ENDPOINT);
} catch (APIManagementException e) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 4

Suggested change
if (keyManagerDto != null && keyManagerDto.getKeyManager() != null) {
try {
org.wso2.carbon.apimgt.api.model.KeyManagerConfiguration config =
keyManagerDto.getKeyManager().getKeyManagerConfiguration();
return (String) config.getParameter(APIConstants.KeyManager.CLIENT_REGISTRATION_ENDPOINT);
} catch (APIManagementException e) {
if (keyManagerDto != null && keyManagerDto.getKeyManager() != null) {
try {
if (log.isDebugEnabled()) {
log.debug("Retrieving DCR endpoint from key manager: " + keyManagerDto.getName());
}
org.wso2.carbon.apimgt.api.model.KeyManagerConfiguration config =
keyManagerDto.getKeyManager().getKeyManagerConfiguration();
return (String) config.getParameter(APIConstants.KeyManager.CLIENT_REGISTRATION_ENDPOINT);
} catch (APIManagementException e) {
log.error("Error while retrieving key manager configuration for MCP DCR support", e);

Comment on lines 175 to +177
String apiType = (String) synCtx.getProperty(APIMgtGatewayConstants.API_TYPE);
if (org.apache.commons.lang3.StringUtils.equals(APIConstants.API_TYPE_MCP, apiType)) {
Object mcpMethodProperty = synCtx.getProperty("MCP_HTTP_METHOD");
Object mcpMethodProperty = synCtx.getProperty(MCP_HTTP_METHOD);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 5

Suggested change
String apiType = (String) synCtx.getProperty(APIMgtGatewayConstants.API_TYPE);
if (org.apache.commons.lang3.StringUtils.equals(APIConstants.API_TYPE_MCP, apiType)) {
Object mcpMethodProperty = synCtx.getProperty("MCP_HTTP_METHOD");
Object mcpMethodProperty = synCtx.getProperty(MCP_HTTP_METHOD);
String apiType = (String) synCtx.getProperty(APIMgtGatewayConstants.API_TYPE);
if (org.apache.commons.lang3.StringUtils.equals(APIConstants.API_TYPE_MCP, apiType)) {
log.debug("Processing MCP API type request");

Comment on lines +177 to 180
Object mcpMethodProperty = synCtx.getProperty(MCP_HTTP_METHOD);
if (mcpMethodProperty != null) {
httpMethod = mcpMethodProperty.toString();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 6

Suggested change
Object mcpMethodProperty = synCtx.getProperty(MCP_HTTP_METHOD);
if (mcpMethodProperty != null) {
httpMethod = mcpMethodProperty.toString();
}
Object mcpMethodProperty = synCtx.getProperty(MCP_HTTP_METHOD);
if (mcpMethodProperty != null) {
httpMethod = mcpMethodProperty.toString();
log.debug("MCP HTTP method set to: " + httpMethod);

Comment on lines 228 to 231
if (StringUtils.equals(APIConstants.API_TYPE_MCP, apiType)) {
httpMethod = synCtx.getProperty("MCP_HTTP_METHOD").toString();
httpMethod = synCtx.getProperty(MCP_HTTP_METHOD).toString();
matchingResource = (String) synCtx.getProperty("MCP_API_ELECTED_RESOURCE");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 7

Suggested change
if (StringUtils.equals(APIConstants.API_TYPE_MCP, apiType)) {
httpMethod = synCtx.getProperty("MCP_HTTP_METHOD").toString();
httpMethod = synCtx.getProperty(MCP_HTTP_METHOD).toString();
matchingResource = (String) synCtx.getProperty("MCP_API_ELECTED_RESOURCE");
}
if (StringUtils.equals(APIConstants.API_TYPE_MCP, apiType)) {
httpMethod = synCtx.getProperty(MCP_HTTP_METHOD).toString();
matchingResource = (String) synCtx.getProperty("MCP_API_ELECTED_RESOURCE");
log.debug("Processing MCP API request with HTTP method: " + httpMethod + " and resource: " + matchingResource);

Comment on lines +149 to 152
if (StringUtils.isEmpty(protocolVersion)) {
throw new McpException(APIConstants.MCP.RpcConstants.INVALID_REQUEST_CODE,
APIConstants.MCP.RpcConstants.INVALID_REQUEST_MESSAGE, "Missing protocolVersion field");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 9

Suggested change
if (StringUtils.isEmpty(protocolVersion)) {
throw new McpException(APIConstants.MCP.RpcConstants.INVALID_REQUEST_CODE,
APIConstants.MCP.RpcConstants.INVALID_REQUEST_MESSAGE, "Missing protocolVersion field");
}
if (StringUtils.isEmpty(protocolVersion)) {
log.error("Validation failed: Missing protocolVersion field in initialize request");
throw new McpException(APIConstants.MCP.RpcConstants.INVALID_REQUEST_CODE,
APIConstants.MCP.RpcConstants.INVALID_REQUEST_MESSAGE, "Missing protocolVersion field");
}

Copy link
Contributor

@wso2-engineering wso2-engineering bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Agent Log Improvement Checklist

⚠️ Warning: AI-Generated Review Comments

  • The log-related comments and suggestions in this review were generated by an AI tool to assist with identifying potential improvements. Purpose of reviewing the code for log improvements is to improve the troubleshooting capabilities of our products.
  • Please make sure to manually review and validate all suggestions before applying any changes. Not every code suggestion would make sense or add value to our purpose. Therefore, you have the freedom to decide which of the suggestions are helpful.

✅ Before merging this pull request:

  • Review all AI-generated comments for accuracy and relevance.
  • Complete and verify the table below. We need your feedback to measure the accuracy of these suggestions and the value they add. If you are rejecting a certain code suggestion, please mention the reason briefly in the suggestion for us to capture it.
Comment Accepted (Y/N) Reason
#### Log Improvement Suggestion No: 1
#### Log Improvement Suggestion No: 2
#### Log Improvement Suggestion No: 3
#### Log Improvement Suggestion No: 4
#### Log Improvement Suggestion No: 5
#### Log Improvement Suggestion No: 6
#### Log Improvement Suggestion No: 7
#### Log Improvement Suggestion No: 9

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/mediators/McpMediator.java (1)

331-343: ⚠️ Potential issue | 🟠 Major

"default" is added multiple times — once per scoped URLMapping and once more unconditionally.

Line 337 adds "default" inside the loop for every URLMapping that has scopes, and line 341 adds it again after the loop. For an API with N scoped resources, the returned list will contain "default" N+1 times. Since line 341 already guarantees "default" is always present, the in-loop addition on line 337 is redundant and introduces duplicates into the scopes_supported metadata.

Additionally, the method never deduplicates scopes in general — if two URLMappings share a scope, it will appear multiple times.

Proposed fix: remove the in-loop add and deduplicate
     public static List<String> getAllScopes(API api) {
-        List<String> allScopes = new ArrayList<>();
+        Set<String> allScopes = new LinkedHashSet<>();
         if (api != null && api.getResources() != null) {
             for (URLMapping urlMapping : api.getResources()) {
                 if (urlMapping.getScopes() != null) {
                     allScopes.addAll(urlMapping.getScopes());
-                    allScopes.add("default");
                 }
             }
         }
         allScopes.add("default");
-        return allScopes;
+        return new ArrayList<>(allScopes);
     }

This requires adding import java.util.LinkedHashSet; and import java.util.Set;.

🧹 Nitpick comments (1)
components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/handlers/security/APIAuthenticationHandlerTestCase.java (1)

276-318: Good end-to-end test for MCP auth failure with DCR endpoint.

The test correctly mocks the full chain: DataHolder → key manager list → KeyManagerHolderKeyManagerDtoKeyManagerConfiguration → DCR endpoint, and validates the WWW-Authenticate header contains both dcr and resource_metadata parameters.

One thing to watch: GatewayUtils.getTenantDomain() (called by getDcrEndpoint) isn't explicitly mocked, so it returns null from the static mock. Line 293 uses Mockito.anyString() to match the tenant domain parameter — this works with Mockito 1.x (which matches null for anyString()), but would break if the project migrates to Mockito 2+. Consider explicitly stubbing GatewayUtils.getTenantDomain() for clarity and forward-compatibility.

Proposed improvement for forward-compatibility
         Mockito.when(dataHolder.getKeyManagersFromUUID(apiUUID)).thenReturn(keyManagers);
 
         PowerMockito.mockStatic(KeyManagerHolder.class);
+        PowerMockito.when(GatewayUtils.getTenantDomain()).thenReturn("carbon.super");
         KeyManagerDto keyManagerDto = Mockito.mock(KeyManagerDto.class);
-        Mockito.when(KeyManagerHolder.getKeyManagerByName(Mockito.anyString(), Mockito.eq("default"))).thenReturn(keyManagerDto);
+        Mockito.when(KeyManagerHolder.getKeyManagerByName("carbon.super", "default")).thenReturn(keyManagerDto);

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 7, 2026
Copy link
Contributor

Copilot AI left a 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 PR improves MCP (Model Context Protocol) request handling in the API Gateway by standardizing MCP method propagation via a shared constant, refining MCP no-auth authentication flow, and enhancing MCP auth failure responses with better WWW-Authenticate metadata (including optional DCR endpoint discovery).

Changes:

  • Introduces APIConstants.MCP_HTTP_METHOD and updates MCP/JWT/OAuth flows to use it consistently.
  • Updates MCP auth/no-auth handling and MCP auth-failure WWW-Authenticate header construction (adds optional DCR endpoint).
  • Adjusts MCP request validation and MCP protected resource metadata scope population; adds/updates related tests.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java Adds MCP_HTTP_METHOD constant for consistent MCP “HTTP method” property usage.
components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/handlers/security/APIAuthenticationHandlerTestCase.java Adds MCP no-auth and MCP DCR-related auth-failure tests; adjusts metric timer assertions.
components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/utils/MCPUtils.java Removes allowed-method validation and relaxes initialize protocol version validation.
components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/mediators/McpMediator.java Ensures “default” scope is included in scopes_supported generation.
components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/oauth/OAuthAuthenticator.java Uses MCP_HTTP_METHOD constant instead of hard-coded string.
components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/jwt/JWTValidator.java Uses MCP_HTTP_METHOD constant instead of hard-coded string.
components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/APIAuthenticationHandler.java Aligns MCP no-auth handling with REST no-auth flow; improves MCP WWW-Authenticate header and adds DCR endpoint lookup.
components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/mcp/McpInitHandler.java Sets MCP_HTTP_METHOD consistently and removes MCP session header on initialize.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +194 to +195
Map<String, String> transportHeaderMap = (Map<String, String>) axis2MC.getProperty
(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In METHOD_INITIALIZE branch, transportHeaderMap can be null if TRANSPORT_HEADERS property is absent, causing a NullPointerException on remove(...). Please null-check (and initialize a new map + set it back) before removing the session header, or guard the removal when headers are missing.

Suggested change
Map<String, String> transportHeaderMap = (Map<String, String>) axis2MC.getProperty
(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
Map<String, String> transportHeaderMap = (Map<String, String>) axis2MC.getProperty(
org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
if (transportHeaderMap == null) {
transportHeaderMap = new HashMap<>();
axis2MC.setProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS, transportHeaderMap);
}

Copilot uses AI. Check for mistakes.
if (StringUtils.isEmpty(protocolVersion)) {
throw new McpException(APIConstants.MCP.RpcConstants.INVALID_REQUEST_CODE,
APIConstants.MCP.RpcConstants.INVALID_REQUEST_MESSAGE, "Missing protocolVersion field");
}
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validateInitializeRequest no longer validates protocolVersion against APIConstants.MCP.SUPPORTED_PROTOCOL_VERSIONS, so unsupported protocol versions will now be accepted. If protocol negotiation is required, reintroduce the supported-version check (and return the existing protocol-mismatch error payload) rather than only checking for non-empty.

Suggested change
}
}
if (!APIConstants.MCP.SUPPORTED_PROTOCOL_VERSIONS.contains(protocolVersion)) {
throw new McpException(APIConstants.MCP.RpcConstants.INVALID_REQUEST_CODE,
APIConstants.MCP.RpcConstants.INVALID_REQUEST_MESSAGE,
"Unsupported protocolVersion: " + protocolVersion);
}

Copilot uses AI. Check for mistakes.
Comment on lines 336 to 342
allScopes.addAll(urlMapping.getScopes());
allScopes.add("default");
}
}
}
allScopes.add("default");
return allScopes;
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getAllScopes now unconditionally adds the literal "default" inside the loop and again after the loop, which can create duplicates (and repeats it once per resource that has scopes). Consider using a Set or only adding "default" once to avoid duplicating values in the published scopes_supported list.

Copilot uses AI. Check for mistakes.
Comment on lines +481 to +487
if (log.isDebugEnabled()) {
log.debug("Skipping authentication for MCP request"
+ ", method: " + messageContext.getProperty(APIMgtGatewayConstants.MCP_METHOD));
}
handleNoAuthentication(messageContext);
setAPIParametersToMessageContext(messageContext);
return ExtensionListenerUtil.postProcessRequest(messageContext, type);
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MCP no-auth short-circuit returns postProcessRequest(...) without invoking ExtensionListenerUtil.preProcessRequest(...), unlike the normal request path. This changes extension listener behavior for MCP no-auth requests; consider calling preProcessRequest (and honoring its return) before handleNoAuthentication(...) to keep the listener lifecycle consistent.

Suggested change
if (log.isDebugEnabled()) {
log.debug("Skipping authentication for MCP request"
+ ", method: " + messageContext.getProperty(APIMgtGatewayConstants.MCP_METHOD));
}
handleNoAuthentication(messageContext);
setAPIParametersToMessageContext(messageContext);
return ExtensionListenerUtil.postProcessRequest(messageContext, type);
if (ExtensionListenerUtil.preProcessRequest(messageContext, type)) {
if (log.isDebugEnabled()) {
log.debug("Skipping authentication for MCP request"
+ ", method: " + messageContext.getProperty(APIMgtGatewayConstants.MCP_METHOD));
}
handleNoAuthentication(messageContext);
setAPIParametersToMessageContext(messageContext);
return ExtensionListenerUtil.postProcessRequest(messageContext, type);
}
return false;

Copilot uses AI. Check for mistakes.
Comment on lines +802 to +806
String resourceMetadata = APIConstants.HTTPS_PROTOCOL + APIConstants.URL_SCHEME_SEPARATOR +
hostHeader + contextPath + APIMgtGatewayConstants.MCP_WELL_KNOWN_RESOURCE;
String dcrEndpoint = getDcrEndpoint();
String wwwAuthenticate = "Bearer resource_metadata=\"" + resourceMetadata + "\"";
if (StringUtils.isNotEmpty(dcrEndpoint)) {
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resource_metadata URL construction now hardcodes https:// and uses hostHeader directly, which can omit the gateway port when the Host header is missing/invalid and you fall back to APIUtil.getHostAddress(). Previously MCPUtils.getGatewayServerURL(...) used vhost httpsUrl (including port). Consider restoring vhost-based resolution or appending the configured HTTPS port/offset when building the URL.

Copilot uses AI. Check for mistakes.
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;

import java.util.ArrayList;
import java.util.Collections;
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import java.util.Collections will fail compilation (unused imports are errors in Java). Please remove it or use it.

Suggested change
import java.util.Collections;

Copilot uses AI. Check for mistakes.

PowerMockito.mockStatic(KeyManagerHolder.class);
KeyManagerDto keyManagerDto = Mockito.mock(KeyManagerDto.class);
Mockito.when(KeyManagerHolder.getKeyManagerByName(Mockito.anyString(), Mockito.eq("default"))).thenReturn(keyManagerDto);
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test stubs KeyManagerHolder.getKeyManagerByName(anyString(), "default"), but GatewayUtils is statically mocked in setup() so GatewayUtils.getTenantDomain() returns null; anyString() won’t match null and the stub won’t apply, causing getDcrEndpoint() to return null and the assertion to fail. Either stub GatewayUtils.getTenantDomain() to a non-null tenant domain, or change the matcher to accept null (e.g., Mockito.any() for the first arg).

Suggested change
Mockito.when(KeyManagerHolder.getKeyManagerByName(Mockito.anyString(), Mockito.eq("default"))).thenReturn(keyManagerDto);
Mockito.when(KeyManagerHolder.getKeyManagerByName(Mockito.any(), Mockito.eq("default"))).thenReturn(keyManagerDto);

Copilot uses AI. Check for mistakes.
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 9, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/handlers/security/APIAuthenticationHandlerTestCase.java`:
- Around line 276-318: The test method testHandleAuthFailureForMCPWithDCR sets
up a DCR endpoint in the kmConfig.dcrEndpoint variable but never asserts it
appears in the WWW-Authenticate header; update the test (in
testHandleAuthFailureForMCPWithDCR) to add an assertion that the computed header
(from transportHeaders "WWW-Authenticate") contains the dcrEndpoint string (use
the existing dcrEndpoint local variable) so the DCR-related header construction
is actually validated.

@AnuGayan AnuGayan removed the React-UI label Feb 10, 2026
@AnuGayan AnuGayan requested a review from PasanT9 as a code owner February 19, 2026 16:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant