package ai.dynamixs.mcp; import java.io.Serializable; import java.util.List; import java.util.logging.Logger; import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; import jakarta.inject.Named; import jakarta.json.Json; import jakarta.json.JsonArrayBuilder; import jakarta.json.JsonObject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.UriInfo; /** * Test endpoint for MCP server discovery and debugging Similar to A2A Agent * Card but for MCP protocol * * @author rsoika */ @Named @RequestScoped @Path("/mcp/debug/") @Produces({ MediaType.APPLICATION_JSON }) public class MCPTestEndpoint implements Serializable { private static final long serialVersionUID = 1L; private static Logger logger = Logger.getLogger(MCPTestEndpoint.class.getSimpleName()); @Context UriInfo uriInfo; @Inject MCPService mcpService; /** * MCP Server Information Endpoint (similar to A2A Agent Card) URL: * /mcp/server-info */ @GET @Path("/server-info") public Response getServerInfo() { try { JsonObject serverInfo = buildServerInfo(); return Response.ok(serverInfo).build(); } catch (Exception e) { logger.severe("Error creating MCP server info: " + e.getMessage()); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity(Json.createObjectBuilder() .add("error", "Internal server error") .add("message", e.getMessage()) .build()) .build(); } } /** * Quick test endpoint to list all available resources URL: /mcp/test/resources */ @GET @Path("/test/resources") public Response testResources() { try { List resources = mcpService.parseResources(); JsonArrayBuilder resourcesBuilder = Json.createArrayBuilder(); for (MCPResource resource : resources) { if (resource.isValid()) { resourcesBuilder.add(resource.toJsonObject()); } } JsonObject result = Json.createObjectBuilder() .add("status", "success") .add("count", resources.size()) .add("resources", resourcesBuilder.build()) .build(); return Response.ok(result).build(); } catch (Exception e) { logger.severe("Error testing resources: " + e.getMessage()); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity(Json.createObjectBuilder() .add("error", "Failed to parse resources") .add("message", e.getMessage()) .build()) .build(); } } /** * Quick test endpoint to list all available tools URL: /mcp/test/tools */ @GET @Path("/test/tools") public Response testTools() { try { List tools = mcpService.parseTools(); JsonArrayBuilder toolsBuilder = Json.createArrayBuilder(); for (MCPTool tool : tools) { if (tool.isValid()) { toolsBuilder.add(tool.toJsonObject()); } } JsonObject result = Json.createObjectBuilder() .add("status", "success") .add("count", tools.size()) .add("tools", toolsBuilder.build()) .build(); return Response.ok(result).build(); } catch (Exception e) { logger.severe("Error testing tools: " + e.getMessage()); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity(Json.createObjectBuilder() .add("error", "Failed to parse tools") .add("message", e.getMessage()) .build()) .build(); } } /** * Health check endpoint URL: /mcp/health */ @GET @Path("/health") public Response healthCheck() { try { List resources = mcpService.parseResources(); List tools = mcpService.parseTools(); JsonObject health = Json.createObjectBuilder() .add("status", "healthy") .add("timestamp", java.time.Instant.now().toString()) .add("server", "Dynamixs.AI MCP Server") .add("version", "1.0.0") .add("protocol", "MCP 2024-11-05") .add("endpoint", getBaseUrl() + "mcp/v1") .add("resources_count", resources.size()) .add("tools_count", tools.size()) .build(); return Response.ok(health).build(); } catch (Exception e) { logger.severe("Health check failed: " + e.getMessage()); return Response.status(Response.Status.SERVICE_UNAVAILABLE) .entity(Json.createObjectBuilder() .add("status", "unhealthy") .add("error", e.getMessage()) .build()) .build(); } } /** * Builds comprehensive server information (MCP equivalent of A2A Agent Card) */ private JsonObject buildServerInfo() { List resources = mcpService.parseResources(); List tools = mcpService.parseTools(); // Server capabilities JsonObject capabilities = Json.createObjectBuilder() .add("resources", Json.createObjectBuilder() .add("subscribe", false) .add("listChanged", false) .build()) .add("tools", Json.createObjectBuilder().build()) .add("logging", Json.createObjectBuilder().build()) .build(); // Protocol information JsonObject protocol = Json.createObjectBuilder() .add("name", "Model Context Protocol") .add("version", "2024-11-05") .add("transport", "HTTP/JSON-RPC 2.0") .build(); // Server metadata JsonObject server = Json.createObjectBuilder() .add("name", "Dynamixs.AI MCP Server") .add("version", "1.0.0") .add("description", "MCP server for Imixs-Workflow BPM platform") .add("vendor", "Dynamixs.AI") .add("platform", "Jakarta EE 10 / Imixs-Workflow") .build(); // Endpoints JsonObject endpoints = Json.createObjectBuilder() .add("jsonrpc", getBaseUrl() + "mcp/v1") .add("health", getBaseUrl() + "mcp/health") .add("server_info", getBaseUrl() + "mcp/server-info") .add("test_resources", getBaseUrl() + "mcp/test/resources") .add("test_tools", getBaseUrl() + "mcp/test/tools") .build(); // Statistics JsonObject statistics = Json.createObjectBuilder() .add("resources_available", resources.size()) .add("tools_available", tools.size()) .add("last_updated", java.time.Instant.now().toString()) .build(); // Resource summary JsonArrayBuilder resourceSummary = Json.createArrayBuilder(); for (MCPResource resource : resources) { if (resource.isValid()) { resourceSummary.add(Json.createObjectBuilder() .add("uri", resource.getUri()) .add("name", resource.getName()) .add("mimeType", resource.getMimeType() != null ? resource.getMimeType() : "text/plain") .build()); } } // Tool summary JsonArrayBuilder toolSummary = Json.createArrayBuilder(); for (MCPTool tool : tools) { if (tool.isValid()) { toolSummary.add(Json.createObjectBuilder() .add("name", tool.getName()) .add("description", tool.getDescription()) .build()); } } // Build complete server info return Json.createObjectBuilder() .add("protocol", protocol) .add("server", server) .add("capabilities", capabilities) .add("endpoints", endpoints) .add("statistics", statistics) .add("resource_summary", resourceSummary.build()) .add("tool_summary", toolSummary.build()) .build(); } private String getBaseUrl() { return uriInfo.getBaseUri().toString(); } }