From 7ab511f8f7a5052ec1dd366c382617c790696158 Mon Sep 17 00:00:00 2001 From: Zibran Khan Date: Thu, 15 Oct 2026 20:44:50 +0530 Subject: [PATCH] honour hiddenService in openapi spec and mcp catalog generation --- .../axis2/openapi/OpenApiSpecGenerator.java | 8 +++++ .../openapi/McpCatalogGeneratorTest.java | 20 ++++++++++++ .../openapi/OpenApiSpecGeneratorTest.java | 32 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/modules/openapi/src/main/java/org/apache/axis2/openapi/OpenApiSpecGenerator.java b/modules/openapi/src/main/java/org/apache/axis2/openapi/OpenApiSpecGenerator.java index ad732e8b3c..8069ff82e4 100644 --- a/modules/openapi/src/main/java/org/apache/axis2/openapi/OpenApiSpecGenerator.java +++ b/modules/openapi/src/main/java/org/apache/axis2/openapi/OpenApiSpecGenerator.java @@ -503,6 +503,14 @@ private boolean shouldIncludeService(AxisService service) { return false; } + // hiddenService is the separate control that keeps a service out of the + // /services listing on both HTTP render paths. The spec and the MCP + // catalog enumerate deployed services the same way, so they honour it too. + if (org.apache.axis2.util.Utils.isHiddenService(service)) { + log.debug("Skipping service with hiddenService=true: " + serviceName); + return false; + } + String servicePackage = getServicePackage(service); // If readAllResources is false, check specific resource classes/packages diff --git a/modules/openapi/src/test/java/org/apache/axis2/openapi/McpCatalogGeneratorTest.java b/modules/openapi/src/test/java/org/apache/axis2/openapi/McpCatalogGeneratorTest.java index c8da8f0862..7135c9030f 100644 --- a/modules/openapi/src/test/java/org/apache/axis2/openapi/McpCatalogGeneratorTest.java +++ b/modules/openapi/src/test/java/org/apache/axis2/openapi/McpCatalogGeneratorTest.java @@ -986,6 +986,26 @@ public void testMcpResourcesExcludesSystemServices() throws Exception { assertEquals("PortfolioService", resources.get(0).path("name").asText()); } + public void testHiddenServiceExcludedFromToolsAndResources() throws Exception { + addService("PortfolioService", "getPortfolio"); + AxisService hidden = new AxisService("InternalOpsService"); + hidden.addParameter(new org.apache.axis2.description.Parameter( + org.apache.axis2.Constants.HIDDEN_SERVICE_PARAM_NAME, "true")); + addOperation(hidden, "purgeAll"); + axisConfig.addService(hidden); + + String catalog = generator.generateMcpCatalogJson(mockRequest); + assertFalse("hidden service must not appear in the MCP catalog", + catalog.contains("InternalOpsService")); + assertFalse("hidden service operation must not appear in the MCP catalog", + catalog.contains("purgeAll")); + + JsonNode resources = MAPPER.readTree(generator.generateMcpResourcesJson(mockRequest)) + .path("resources"); + assertEquals("only PortfolioService, not the hidden service", 1, resources.size()); + assertEquals("PortfolioService", resources.get(0).path("name").asText()); + } + public void testMcpResourcesIncludesOperationList() throws Exception { AxisService svc = new AxisService("PortfolioService"); addOperation(svc, "getPortfolio"); diff --git a/modules/openapi/src/test/java/org/apache/axis2/openapi/OpenApiSpecGeneratorTest.java b/modules/openapi/src/test/java/org/apache/axis2/openapi/OpenApiSpecGeneratorTest.java index c8ef81a532..ce5998c601 100644 --- a/modules/openapi/src/test/java/org/apache/axis2/openapi/OpenApiSpecGeneratorTest.java +++ b/modules/openapi/src/test/java/org/apache/axis2/openapi/OpenApiSpecGeneratorTest.java @@ -278,6 +278,38 @@ public void testIgnoredServiceIsExcluded() throws Exception { openApi.getPaths().get("/services/InternalService/secretOp")); } + /** + * Test that a service with hiddenService=true is omitted from the spec, as + * it is from the /services listing. + */ + public void testHiddenServiceIsExcluded() throws Exception { + // Arrange + AxisService visible = new AxisService("PublicService"); + AxisOperation visibleOp = new org.apache.axis2.description.InOutAxisOperation(); + visibleOp.setName(javax.xml.namespace.QName.valueOf("getData")); + visible.addOperation(visibleOp); + + AxisService hidden = new AxisService("InternalService"); + hidden.addParameter(new org.apache.axis2.description.Parameter( + org.apache.axis2.Constants.HIDDEN_SERVICE_PARAM_NAME, "true")); + AxisOperation hiddenOp = new org.apache.axis2.description.InOutAxisOperation(); + hiddenOp.setName(javax.xml.namespace.QName.valueOf("secretOp")); + hidden.addOperation(hiddenOp); + + axisConfiguration.addService(visible); + axisConfiguration.addService(hidden); + + // Act + OpenAPI openApi = generator.generateOpenApiSpec(mockRequest); + + // Assert + assertNotNull(openApi.getPaths()); + assertNotNull("Public service path should be present", + openApi.getPaths().get("/services/PublicService/getData")); + assertNull("Hidden service path must be absent", + openApi.getPaths().get("/services/InternalService/secretOp")); + } + /** * Test that a qualified "ServiceName/operationName" entry in ignoredOperations * removes only that specific operation, leaving other operations on the same