This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git


The following commit(s) were added to refs/heads/master by this push:
     new c2ad0487 chore(mcp-server-contribution): project was moved
c2ad0487 is described below

commit c2ad0487b498c2a30ba96f780ee3818bb421c3dc
Author: Robert Munteanu <[email protected]>
AuthorDate: Mon May 4 15:06:00 2026 +0200

    chore(mcp-server-contribution): project was moved
---
 mcp-server-contributions/README.md                 |   4 +-
 mcp-server-contributions/bnd.bnd                   |   1 -
 mcp-server-contributions/pom.xml                   | 164 -------
 .../server/impl/contribs/LogToolContribution.java  | 228 ---------
 .../contribs/OsgiBundleDiagnosticContribution.java | 524 ---------------------
 .../impl/contribs/RecentRequestsContribution.java  | 108 -----
 .../server/impl/contribs/internal/LogSnapshot.java |  42 --
 .../contribs/internal/StructuredLogBuffer.java     | 100 ----
 .../internal/StructuredLogBufferAppender.java      | 173 -------
 .../libs/sling/mcp/prompts/new-sling-servlet.md    |  17 -
 .../libs/sling/mcp/prompts/troubleshoot.md         |  45 --
 .../internal/StructuredLogBufferAppenderTest.java  |  62 ---
 .../contribs/internal/StructuredLogBufferTest.java |  64 ---
 13 files changed, 1 insertion(+), 1531 deletions(-)

diff --git a/mcp-server-contributions/README.md 
b/mcp-server-contributions/README.md
index 0f037be0..2cb8c933 100644
--- a/mcp-server-contributions/README.md
+++ b/mcp-server-contributions/README.md
@@ -1,3 +1 @@
-# Apache Sling MCP Server contributions
-
-This project contains contributions ( tools, resources, prompts) for the 
Apache Sling MCP Server. See [the Sling MCP Server 
repository](https://github.com/apache/sling-org-apache-sling-mcp-server) for 
details on how to set up and run the MCP Server itself.
+Moved to 
[https://github.com/apache/sling-org-apache-sling-mcp-server-contributions](https://github.com/apache/sling-org-apache-sling-mcp-server-contributions)
diff --git a/mcp-server-contributions/bnd.bnd b/mcp-server-contributions/bnd.bnd
deleted file mode 100644
index 5a8e9c40..00000000
--- a/mcp-server-contributions/bnd.bnd
+++ /dev/null
@@ -1 +0,0 @@
-Sling-Initial-Content: 
SLING-INF/libs/sling/mcp/prompts;path:=/libs/sling/mcp/prompts;overwrite:=true
diff --git a/mcp-server-contributions/pom.xml b/mcp-server-contributions/pom.xml
deleted file mode 100644
index e5bbd31c..00000000
--- a/mcp-server-contributions/pom.xml
+++ /dev/null
@@ -1,164 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
-
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.apache.sling</groupId>
-        <artifactId>sling-bundle-parent</artifactId>
-        <version>65</version>
-        <relativePath />
-    </parent>
-
-    <artifactId>org.apache.sling.mcp-server-contributions</artifactId>
-    <version>0.1.0-SNAPSHOT</version>
-
-    <name>Apache Sling MCP Server Contributions</name>
-
-    <properties>
-        <sling.java.version>17</sling.java.version>
-        <!-- Run with 
-Dslingfeature.app.vmOption=-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=30303
 for debug mode-->
-        <slingfeature.app.vmOption />
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.framework</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.resource</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.annotation.bundle</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.annotation.versioning</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.service.component.annotations</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.service.component</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.service.metatype.annotations</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.servlets.annotations</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.jetbrains</groupId>
-            <artifactId>annotations</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.api</artifactId>
-            <version>3.0.2</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.engine</artifactId>
-            <version>2.10.2</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>jakarta.servlet</groupId>
-            <artifactId>jakarta.servlet-api</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>io.modelcontextprotocol.sdk</groupId>
-            <artifactId>mcp-core</artifactId>
-            <version>1.0.0</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>1.7.32</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-core</artifactId>
-            <version>1.2.13</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-classic</artifactId>
-            <version>1.2.13</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.mcp-server</artifactId>
-            <version>0.1.2</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-api</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-engine</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.util.converter</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <plugins>
-            <!-- Configure bnd-baseline to skip when no previous version 
exists. Remove after first release -->
-            <plugin>
-                <groupId>biz.aQute.bnd</groupId>
-                <artifactId>bnd-baseline-maven-plugin</artifactId>
-                <configuration>
-                    <failOnMissing>false</failOnMissing>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-</project>
diff --git 
a/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/LogToolContribution.java
 
b/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/LogToolContribution.java
deleted file mode 100644
index 0ec2db36..00000000
--- 
a/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/LogToolContribution.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl.contribs;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-
-import ch.qos.logback.classic.Level;
-import io.modelcontextprotocol.json.McpJsonMapperSupplier;
-import 
io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncToolSpecification;
-import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
-import io.modelcontextprotocol.spec.McpSchema.Tool;
-import org.apache.sling.mcp.server.impl.contribs.internal.LogSnapshot;
-import 
org.apache.sling.mcp.server.impl.contribs.internal.StructuredLogBufferAppender;
-import org.apache.sling.mcp.server.spi.McpServerContribution;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Reference;
-
-/**
- * MCP Tool that provides access to logs with filtering capabilities.
- * Allows filtering by regex pattern, log level, and maximum number of entries.
- */
-@Component
-public class LogToolContribution implements McpServerContribution {
-
-    @Reference
-    private StructuredLogBufferAppender structuredLogBufferAppender;
-
-    @Reference
-    private McpJsonMapperSupplier jsonMapper;
-
-    private static final int DEFAULT_MAX_LOGS = 200;
-    private static final SimpleDateFormat DATE_FORMAT = new 
SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
-
-    @Override
-    public List<SyncToolSpecification> getSyncToolSpecification() {
-
-        var schema = """
-                {
-                  "type" : "object",
-                  "id" : "urn:jsonschema:LogFilterInput",
-                  "properties" : {
-                    "regex" : {
-                      "type" : "string",
-                      "description" : "Optional regex pattern to filter log 
messages. If not provided, all logs are returned."
-                    },
-                    "logLevel" : {
-                      "type" : "string",
-                      "description" : "Minimum log level to return. Options: 
ERROR, WARN, INFO, DEBUG, TRACE. Defaults to ERROR.",
-                      "enum" : ["ERROR", "WARN", "INFO", "DEBUG", "TRACE"]
-                    },
-                    "maxEntries" : {
-                      "type" : "integer",
-                      "description" : "Maximum number of log entries to 
return. Defaults to 200.",
-                      "minimum" : 1,
-                      "maximum" : 1000
-                    }
-                  }
-                }
-                """;
-
-        return List.of(new SyncToolSpecification(
-                Tool.builder()
-                        .name("logs")
-                        .description("Retrieve logs with optional filtering. "
-                                + "Supports filtering by regex pattern, log 
level (ERROR, WARN, INFO, DEBUG, TRACE), "
-                                + "and maximum number of entries. Returns most 
recent logs first.")
-                        .inputSchema(jsonMapper.get(), schema)
-                        .build(),
-                (exchange, request) -> {
-                    String regexPattern = (String) 
request.arguments().get("regex");
-                    String logLevelStr = (String) 
request.arguments().get("logLevel");
-                    Object maxEntriesObj = 
request.arguments().get("maxEntries");
-
-                    // Parse parameters
-                    int maxEntries = DEFAULT_MAX_LOGS;
-                    if (maxEntriesObj instanceof Number) {
-                        maxEntries = ((Number) maxEntriesObj).intValue();
-                        maxEntries = Math.min(maxEntries, 1000); // Cap at 1000
-                    }
-
-                    Level minLogLevel = Level.ERROR;
-                    if (logLevelStr != null && !logLevelStr.isEmpty()) {
-                        minLogLevel = parseLogLevel(logLevelStr);
-                        if (minLogLevel == null) {
-                            return CallToolResult.builder()
-                                    .addTextContent("Invalid log level: " + 
logLevelStr
-                                            + ". Valid options are: ERROR, 
WARN, INFO, DEBUG, TRACE")
-                                    .isError(true)
-                                    .build();
-                        }
-                    }
-
-                    // Compile regex pattern if provided
-                    Pattern pattern = null;
-                    if (regexPattern != null && !regexPattern.isEmpty()) {
-                        try {
-                            pattern = Pattern.compile(regexPattern, 
Pattern.CASE_INSENSITIVE);
-                        } catch (PatternSyntaxException e) {
-                            return CallToolResult.builder()
-                                    .addTextContent("Invalid regex pattern: " 
+ e.getMessage())
-                                    .isError(true)
-                                    .build();
-                        }
-                    }
-
-                    List<LogSnapshot> filteredLogs =
-                            
structuredLogBufferAppender.getBuffer().getRecent(pattern, minLogLevel, 
maxEntries);
-
-                    // Format output
-                    String result = formatLogs(filteredLogs, regexPattern, 
minLogLevel, maxEntries);
-
-                    return 
CallToolResult.builder().addTextContent(result).build();
-                }));
-    }
-
-    private Level parseLogLevel(String levelStr) {
-        return switch (levelStr.toUpperCase()) {
-            case "ERROR" -> Level.ERROR;
-            case "WARN", "WARNING" -> Level.WARN;
-            case "INFO" -> Level.INFO;
-            case "DEBUG" -> Level.DEBUG;
-            case "TRACE" -> Level.TRACE;
-            default -> null;
-        };
-    }
-
-    private String formatLogs(List<LogSnapshot> logs, String regexPattern, 
Level minLogLevel, int maxEntries) {
-        StringBuilder result = new StringBuilder();
-
-        result.append("=== Log Entries ===\n\n");
-        result.append("Filter Settings:\n");
-        result.append("  - Log Level: 
").append(getLogLevelName(minLogLevel)).append(" and higher severity\n");
-        result.append("  - Regex Pattern: ")
-                .append(regexPattern != null ? regexPattern : "(none)")
-                .append("\n");
-        result.append("  - Max Entries: ").append(maxEntries).append("\n");
-        result.append("  - Entries Found: 
").append(logs.size()).append("\n\n");
-
-        if (logs.isEmpty()) {
-            result.append("No log entries found matching the criteria.\n");
-            return result.toString();
-        }
-
-        result.append("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n");
-
-        for (int i = 0; i < logs.size(); i++) {
-            LogSnapshot entry = logs.get(i);
-            formatLogEntry(entry, i + 1, result);
-
-            if (i < logs.size() - 1) {
-                result.append("\n");
-            }
-        }
-
-        return result.toString();
-    }
-
-    private void formatLogEntry(LogSnapshot entry, int index, StringBuilder 
result) {
-        result.append("[").append(index).append("] ");
-        result.append(DATE_FORMAT.format(new Date(entry.timeMillis())));
-        result.append(" [").append(getLogLevelName(entry.level())).append("] 
");
-        result.append("[")
-                .append(entry.loggerName() != null ? entry.loggerName() : 
"(unknown logger)")
-                .append("] ");
-
-        String message = entry.formattedMessage();
-        result.append(message != null ? message : "(no message)");
-        result.append("\n");
-
-        if (entry.threadName() != null && !entry.threadName().isEmpty()) {
-            result.append("    Thread: 
").append(entry.threadName()).append("\n");
-        }
-
-        if (!entry.mdc().isEmpty()) {
-            result.append("    MDC: 
").append(formatMdc(entry.mdc())).append("\n");
-        }
-
-        String throwableText = entry.throwableText();
-        if (throwableText != null && !throwableText.isEmpty()) {
-            String[] lines = throwableText.split("\n");
-            int maxLines = Math.min(lines.length, 10);
-            for (int i = 0; i < maxLines; i++) {
-                result.append("      ").append(lines[i]).append("\n");
-            }
-            if (lines.length > maxLines) {
-                result.append("      ... (").append(lines.length - 
maxLines).append(" more lines)\n");
-            }
-        }
-    }
-
-    private String formatMdc(Map<String, String> mdc) {
-        StringBuilder result = new StringBuilder();
-        boolean first = true;
-        for (Map.Entry<String, String> entry : mdc.entrySet()) {
-            if (!first) {
-                result.append(", ");
-            }
-            result.append(entry.getKey()).append('=').append(entry.getValue());
-            first = false;
-        }
-        return result.toString();
-    }
-
-    private String getLogLevelName(Level level) {
-        return level != null ? level.levelStr : "UNKNOWN";
-    }
-}
diff --git 
a/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/OsgiBundleDiagnosticContribution.java
 
b/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/OsgiBundleDiagnosticContribution.java
deleted file mode 100644
index 6abb702d..00000000
--- 
a/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/OsgiBundleDiagnosticContribution.java
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl.contribs;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import io.modelcontextprotocol.json.McpJsonMapperSupplier;
-import 
io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncToolSpecification;
-import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
-import io.modelcontextprotocol.spec.McpSchema.Tool;
-import org.apache.sling.mcp.server.spi.McpServerContribution;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.wiring.BundleRequirement;
-import org.osgi.framework.wiring.BundleWire;
-import org.osgi.framework.wiring.BundleWiring;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.component.runtime.ServiceComponentRuntime;
-import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
-import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
-import org.osgi.service.component.runtime.dto.UnsatisfiedReferenceDTO;
-
-/**
- * MCP Tool that diagnoses why OSGi bundles and components aren't starting.
- * This tool provides detailed diagnostic information about:
- * - Bundle state and resolution issues
- * - Unsatisfied package imports
- * - Missing service dependencies for components
- * - Configuration problems
- */
-@Component
-public class OsgiBundleDiagnosticContribution implements McpServerContribution 
{
-
-    @Reference
-    private McpJsonMapperSupplier jsonMapperSupplier;
-
-    @Reference
-    private ServiceComponentRuntime scr;
-
-    private final BundleContext ctx;
-
-    @Activate
-    public OsgiBundleDiagnosticContribution(BundleContext ctx) {
-        this.ctx = ctx;
-    }
-
-    @Override
-    public List<SyncToolSpecification> getSyncToolSpecification() {
-
-        var schema = """
-                {
-                  "type" : "object",
-                  "id" : "urn:jsonschema:DiagnoseBundleInput",
-                  "properties" : {
-                    "bundleSymbolicName" : {
-                      "type" : "string",
-                      "description" : "The symbolic name of the bundle to 
diagnose. If not provided, will diagnose all problematic bundles."
-                    }
-                  }
-                }
-                """;
-
-        return List.of(new SyncToolSpecification(
-                Tool.builder()
-                        .name("diagnose-osgi-bundle")
-                        .description(
-                                "Diagnose why an OSGi bundle or component 
isn't starting. Provides detailed information about unsatisfied dependencies, 
missing packages, and component configuration issues.")
-                        .inputSchema(jsonMapperSupplier.get(), schema)
-                        .build(),
-                (exchange, request) -> {
-                    String bundleSymbolicName = (String) 
request.arguments().get("bundleSymbolicName");
-
-                    if (bundleSymbolicName != null && 
!bundleSymbolicName.isEmpty()) {
-                        return diagnoseSpecificBundle(bundleSymbolicName);
-                    } else {
-                        return diagnoseAllProblematicBundles();
-                    }
-                }));
-    }
-
-    private CallToolResult diagnoseSpecificBundle(String symbolicName) {
-        Bundle bundle = findBundle(symbolicName);
-        if (bundle == null) {
-            return CallToolResult.builder()
-                    .addTextContent("Bundle '" + symbolicName + "' not found.")
-                    .isError(true)
-                    .build();
-        }
-
-        StringBuilder result = new StringBuilder();
-        result.append("=== Bundle Diagnostic Report ===\n\n");
-        result.append("Bundle: 
").append(bundle.getSymbolicName()).append("\n");
-        result.append("Version: ").append(bundle.getVersion()).append("\n");
-        result.append("State: 
").append(getStateName(bundle.getState())).append("\n\n");
-
-        if (bundle.getState() == Bundle.ACTIVE) {
-            result.append("✓ Bundle is ACTIVE and running normally.\n\n");
-            // Check components
-            appendComponentDiagnostics(bundle, result);
-        } else {
-            result.append("✗ Bundle is NOT active. Analyzing issues...\n\n");
-            analyzeBundleIssues(bundle, result);
-            appendComponentDiagnostics(bundle, result);
-        }
-
-        return 
CallToolResult.builder().addTextContent(result.toString()).build();
-    }
-
-    private CallToolResult diagnoseAllProblematicBundles() {
-        StringBuilder result = new StringBuilder();
-        result.append("=== OSGi System Diagnostic Report ===\n\n");
-
-        List<Bundle> problematicBundles = Arrays.stream(ctx.getBundles())
-                .filter(b -> b.getState() != Bundle.ACTIVE && b.getState() != 
Bundle.UNINSTALLED)
-                .collect(Collectors.toList());
-
-        if (problematicBundles.isEmpty()) {
-            result.append("✓ All bundles are active!\n\n");
-        } else {
-            result.append("Found ").append(problematicBundles.size()).append(" 
problematic bundle(s):\n\n");
-
-            for (Bundle bundle : problematicBundles) {
-                result.append("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
-                result.append("Bundle: 
").append(bundle.getSymbolicName()).append("\n");
-                result.append("State: 
").append(getStateName(bundle.getState())).append("\n");
-                analyzeBundleIssues(bundle, result);
-                result.append("\n");
-            }
-        }
-
-        // Check for components with issues
-        appendAllComponentIssues(result);
-
-        return 
CallToolResult.builder().addTextContent(result.toString()).build();
-    }
-
-    private void analyzeBundleIssues(Bundle bundle, StringBuilder result) {
-        if (bundle.getState() == Bundle.INSTALLED) {
-            result.append("\n⚠ Bundle is INSTALLED but not RESOLVED\n");
-            result.append("This typically means there are unsatisfied 
dependencies.\n\n");
-
-            boolean foundIssues = false;
-
-            // First try to get info from BundleWiring (for resolved 
requirements)
-            BundleWiring wiring = bundle.adapt(BundleWiring.class);
-            if (wiring != null) {
-                List<BundleRequirement> requirements = 
wiring.getRequirements(null);
-
-                for (BundleRequirement req : requirements) {
-                    List<BundleWire> wires = 
wiring.getRequiredWires(req.getNamespace());
-                    if (wires == null || wires.isEmpty()) {
-                        if (!foundIssues) {
-                            result.append("Unsatisfied Requirements:\n");
-                            foundIssues = true;
-                        }
-                        result.append("  ✗ ")
-                                .append(req.getNamespace())
-                                .append(": ")
-                                .append(req.getDirectives())
-                                .append("\n");
-
-                        // For package imports, show which package is missing
-                        if ("osgi.wiring.package".equals(req.getNamespace())) {
-                            String filter = req.getDirectives().get("filter");
-                            result.append("    Missing package: ")
-                                    .append(filter)
-                                    .append("\n");
-                        }
-                    }
-                }
-            }
-
-            // If no issues found via wiring, check manifest directly and 
compare with available exports
-            if (!foundIssues) {
-                String importPackage = 
bundle.getHeaders().get(Constants.IMPORT_PACKAGE);
-
-                if (importPackage != null && !importPackage.isEmpty()) {
-                    result.append("Analyzing Package Dependencies:\n\n");
-                    analyzePackageImports(importPackage, result);
-                    foundIssues = true;
-                }
-
-                String requireBundle = 
bundle.getHeaders().get(Constants.REQUIRE_BUNDLE);
-                if (requireBundle != null && !requireBundle.isEmpty()) {
-                    result.append("\nRequired Bundles (from manifest):\n");
-                    result.append("  ")
-                            .append(requireBundle.replace(",", ",\n  "))
-                            .append("\n\n");
-                    result.append("⚠ One or more of these bundles are not 
available or not in the correct state.\n");
-                    foundIssues = true;
-                }
-            }
-
-            if (!foundIssues) {
-                result.append("No dependency information found. Bundle may 
have internal errors.\n");
-            }
-        } else if (bundle.getState() == Bundle.RESOLVED) {
-            result.append("\n✓ Bundle is RESOLVED (all dependencies 
satisfied)\n");
-            result.append("Bundle can be started manually if it's not a 
fragment.\n");
-        } else if (bundle.getState() == Bundle.STARTING) {
-            result.append("\n⚠ Bundle is STARTING (stuck during 
activation)\n");
-            result.append("Check for errors in bundle activator or circular 
dependencies.\n");
-        }
-
-        // Check for fragment information
-        if ((bundle.getHeaders().get(Constants.FRAGMENT_HOST)) != null) {
-            result.append("\nNote: This is a fragment bundle (attached to: ")
-                    .append(bundle.getHeaders().get(Constants.FRAGMENT_HOST))
-                    .append(")\n");
-        }
-    }
-
-    /**
-     * Analyzes imported packages by checking if they are available in the 
OSGi environment.
-     * Scans all bundles to find which packages are exported and matches them 
against imports.
-     */
-    private void analyzePackageImports(String importPackageHeader, 
StringBuilder result) {
-        // Build a map of all exported packages in the system
-        java.util.Map<String, List<PackageExport>> exportedPackages = new 
java.util.HashMap<>();
-
-        for (Bundle b : ctx.getBundles()) {
-            if (b.getState() == Bundle.UNINSTALLED) {
-                continue;
-            }
-
-            String exportPackage = 
b.getHeaders().get(Constants.EXPORT_PACKAGE);
-            if (exportPackage != null && !exportPackage.isEmpty()) {
-                List<PackageInfo> exports = parsePackages(exportPackage);
-                for (PackageInfo pkg : exports) {
-                    if (pkg.name != null && !pkg.name.isEmpty() && 
pkg.name.contains(".")) {
-                        exportedPackages
-                                .computeIfAbsent(pkg.name, k -> new 
ArrayList<>())
-                                .add(new PackageExport(b, pkg.name, 
pkg.version));
-                    }
-                }
-            }
-        }
-
-        // Parse and check each imported package
-        List<PackageInfo> imports = parsePackages(importPackageHeader);
-        int missingCount = 0;
-        int availableCount = 0;
-        List<String> missingPackages = new ArrayList<>();
-
-        for (PackageInfo importPkg : imports) {
-            // Skip invalid package names
-            if (importPkg.name == null || importPkg.name.isEmpty() || 
!importPkg.name.contains(".")) {
-                continue;
-            }
-
-            List<PackageExport> availableExports = 
exportedPackages.get(importPkg.name);
-
-            if (availableExports == null || availableExports.isEmpty()) {
-                missingCount++;
-                missingPackages.add("  ✗ " + importPkg.name
-                        + (importPkg.version.isEmpty() ? "" : " " + 
importPkg.version)
-                        + (importPkg.optional ? " (optional)" : "") + "\n");
-            } else {
-                availableCount++;
-            }
-        }
-
-        // Only show missing packages
-        if (missingCount > 0) {
-            result.append("Missing Packages (")
-                    .append(missingCount)
-                    .append(" of ")
-                    .append(imports.size())
-                    .append(" imports):\n\n");
-            for (String missing : missingPackages) {
-                result.append(missing);
-            }
-            result.append(
-                    "\n⚠ Action Required: Install bundles that provide the 
missing packages, or downgrade / change the dependencies.\n");
-        } else {
-            result.append("✓ All ").append(imports.size()).append(" imported 
packages are available.\n");
-            result.append("Bundle should be resolvable. Check for other 
issues.\n");
-        }
-    }
-
-    /**
-     * Parse OSGi package header (Import-Package or Export-Package).
-     * Handles complex cases with version ranges, attributes, and directives.
-     */
-    private List<PackageInfo> parsePackages(String header) {
-        List<PackageInfo> packages = new ArrayList<>();
-        if (header == null || header.isEmpty()) {
-            return packages;
-        }
-
-        // State machine for parsing
-        StringBuilder current = new StringBuilder();
-        int depth = 0; // Track depth of quotes and brackets
-        boolean inQuotes = false;
-
-        for (int i = 0; i < header.length(); i++) {
-            char c = header.charAt(i);
-
-            if (c == '"') {
-                inQuotes = !inQuotes;
-                current.append(c);
-            } else if (!inQuotes && (c == '[' || c == '(')) {
-                depth++;
-                current.append(c);
-            } else if (!inQuotes && (c == ']' || c == ')')) {
-                depth--;
-                current.append(c);
-            } else if (c == ',' && depth == 0 && !inQuotes) {
-                // This is a package separator
-                String pkg = current.toString().trim();
-                if (!pkg.isEmpty()) {
-                    packages.add(parsePackageEntry(pkg));
-                }
-                current = new StringBuilder();
-            } else {
-                current.append(c);
-            }
-        }
-
-        // Don't forget the last package
-        String pkg = current.toString().trim();
-        if (!pkg.isEmpty()) {
-            packages.add(parsePackageEntry(pkg));
-        }
-
-        return packages;
-    }
-
-    /**
-     * Parse a single package entry like 
"com.example.pkg;version="[1.0,2.0)";resolution:=optional"
-     */
-    private PackageInfo parsePackageEntry(String entry) {
-        // Split on first semicolon to separate package name from attributes
-        int semicolonPos = entry.indexOf(';');
-        String packageName;
-        String attributes;
-
-        if (semicolonPos > 0) {
-            packageName = entry.substring(0, semicolonPos).trim();
-            attributes = entry.substring(semicolonPos + 1);
-        } else {
-            packageName = entry.trim();
-            attributes = "";
-        }
-
-        // Extract version
-        String version = "";
-        if (attributes.contains("version=")) {
-            int vStart = attributes.indexOf("version=") + 8;
-            int vEnd = attributes.length();
-            // Find the end of the version value (next semicolon outside 
quotes)
-            boolean inQuote = false;
-            for (int i = vStart; i < attributes.length(); i++) {
-                char c = attributes.charAt(i);
-                if (c == '"') {
-                    inQuote = !inQuote;
-                } else if (c == ';' && !inQuote) {
-                    vEnd = i;
-                    break;
-                }
-            }
-            version = attributes.substring(vStart, 
vEnd).trim().replaceAll("\"", "");
-        }
-
-        boolean optional = attributes.contains("resolution:=optional");
-
-        return new PackageInfo(packageName, version, optional);
-    }
-
-    private String extractVersion(String exportEntry) {
-        if (exportEntry.contains("version=")) {
-            int start = exportEntry.indexOf("version=") + 8;
-            int end = exportEntry.indexOf(";", start);
-            if (end == -1) {
-                end = exportEntry.length();
-            }
-            return exportEntry.substring(start, end).replaceAll("\"", 
"").trim();
-        }
-        return "0.0.0";
-    }
-
-    private static class PackageInfo {
-        final String name;
-        final String version;
-        final boolean optional;
-
-        PackageInfo(String name, String version, boolean optional) {
-            this.name = name;
-            this.version = version;
-            this.optional = optional;
-        }
-    }
-
-    private static class PackageExport {
-        final Bundle bundle;
-        final String packageName;
-        final String version;
-
-        PackageExport(Bundle bundle, String packageName, String version) {
-            this.bundle = bundle;
-            this.packageName = packageName;
-            this.version = version;
-        }
-    }
-
-    private void appendComponentDiagnostics(Bundle bundle, StringBuilder 
result) {
-        Collection<ComponentDescriptionDTO> components = 
scr.getComponentDescriptionDTOs(bundle);
-
-        if (components.isEmpty()) {
-            return;
-        }
-
-        result.append("\n--- Declarative Services Components ---\n\n");
-
-        for (ComponentDescriptionDTO desc : components) {
-            Collection<ComponentConfigurationDTO> configs = 
scr.getComponentConfigurationDTOs(desc);
-
-            result.append("Component: ").append(desc.name).append("\n");
-
-            if (configs.isEmpty()) {
-                result.append("  Status: Not configured/instantiated\n");
-            }
-
-            for (ComponentConfigurationDTO config : configs) {
-                result.append("  State: ")
-                        .append(getComponentStateName(config.state))
-                        .append("\n");
-
-                if (config.state == 
ComponentConfigurationDTO.UNSATISFIED_REFERENCE) {
-                    result.append("  ✗ Unsatisfied Service References:\n");
-                    for (UnsatisfiedReferenceDTO ref : 
config.unsatisfiedReferences) {
-                        result.append("    - ")
-                                .append(ref.name)
-                                .append(" (")
-                                .append(ref.target)
-                                .append(")\n");
-                    }
-                } else if (config.state == 
ComponentConfigurationDTO.UNSATISFIED_CONFIGURATION) {
-                    result.append("  ✗ Missing required configuration\n");
-                } else if (config.state == ComponentConfigurationDTO.SATISFIED
-                        || config.state == ComponentConfigurationDTO.ACTIVE) {
-                    result.append("  ✓ Component is working correctly\n");
-                }
-            }
-            result.append("\n");
-        }
-    }
-
-    private void appendAllComponentIssues(StringBuilder result) {
-        List<ComponentDescriptionDTO> allComponents = new 
ArrayList<>(scr.getComponentDescriptionDTOs());
-        List<String> problematicComponents = new ArrayList<>();
-
-        for (ComponentDescriptionDTO desc : allComponents) {
-            Collection<ComponentConfigurationDTO> configs = 
scr.getComponentConfigurationDTOs(desc);
-
-            for (ComponentConfigurationDTO config : configs) {
-                if (config.state == 
ComponentConfigurationDTO.UNSATISFIED_REFERENCE
-                        || config.state == 
ComponentConfigurationDTO.UNSATISFIED_CONFIGURATION) {
-                    problematicComponents.add(desc.name + " (" + 
getComponentStateName(config.state) + ")");
-                }
-            }
-        }
-
-        if (!problematicComponents.isEmpty()) {
-            result.append("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
-            result.append("Problematic Components:\n\n");
-            for (String comp : problematicComponents) {
-                result.append("  ✗ ").append(comp).append("\n");
-            }
-        }
-    }
-
-    private Bundle findBundle(String symbolicName) {
-        return Arrays.stream(ctx.getBundles())
-                .filter(b -> b.getSymbolicName().equals(symbolicName))
-                .findFirst()
-                .orElse(null);
-    }
-
-    private String getStateName(int state) {
-        return switch (state) {
-            case Bundle.UNINSTALLED -> "UNINSTALLED";
-            case Bundle.INSTALLED -> "INSTALLED";
-            case Bundle.RESOLVED -> "RESOLVED";
-            case Bundle.STARTING -> "STARTING";
-            case Bundle.STOPPING -> "STOPPING";
-            case Bundle.ACTIVE -> "ACTIVE";
-            default -> "UNKNOWN (" + state + ")";
-        };
-    }
-
-    private String getComponentStateName(int state) {
-        return switch (state) {
-            case ComponentConfigurationDTO.UNSATISFIED_CONFIGURATION -> 
"UNSATISFIED_CONFIGURATION";
-            case ComponentConfigurationDTO.UNSATISFIED_REFERENCE -> 
"UNSATISFIED_REFERENCE";
-            case ComponentConfigurationDTO.SATISFIED -> "SATISFIED";
-            case ComponentConfigurationDTO.ACTIVE -> "ACTIVE";
-            default -> "UNKNOWN (" + state + ")";
-        };
-    }
-}
diff --git 
a/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/RecentRequestsContribution.java
 
b/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/RecentRequestsContribution.java
deleted file mode 100644
index 148b6cc9..00000000
--- 
a/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/RecentRequestsContribution.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl.contribs;
-
-import java.util.List;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
-
-import io.modelcontextprotocol.json.McpJsonMapperSupplier;
-import 
io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncToolSpecification;
-import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
-import io.modelcontextprotocol.spec.McpSchema.Tool;
-import org.apache.sling.engine.RequestInfo;
-import org.apache.sling.engine.RequestInfoProvider;
-import org.apache.sling.mcp.server.spi.McpServerContribution;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Reference;
-
-@Component
-public class RecentRequestsContribution implements McpServerContribution {
-
-    private final RequestInfoProvider requestInfoProvider;
-    private final McpJsonMapperSupplier jsonMapperSupplier;
-
-    @Activate
-    public RecentRequestsContribution(
-            @Reference RequestInfoProvider requestInfoProvider, @Reference 
McpJsonMapperSupplier jsonMapperSupplier) {
-        this.requestInfoProvider = requestInfoProvider;
-        this.jsonMapperSupplier = jsonMapperSupplier;
-    }
-
-    private String describe(RequestInfo ri) {
-        return "Id: " + ri.getId() + "\n" + "Method: "
-                + ri.getMethod() + "\n" + "Path: " + ri.getPath() + "\n" + 
"User id: " + ri.getUserId() + "\n"
-                + ":\n" + ri.getLog();
-    }
-
-    @Override
-    public List<SyncToolSpecification> getSyncToolSpecification() {
-
-        var schema = """
-                {
-                  "type" : "object",
-                  "id" : "urn:jsonschema:RecentRequestsInput",
-                  "properties" : {
-                    "path" : {
-                      "type" : "string",
-                      "description" : "Optional regex pattern to filter 
requests by path. If not provided, all recent requests are returned."
-                    }
-                  }
-                }
-                """;
-
-        return List.of(new SyncToolSpecification(
-                Tool.builder()
-                        .name("recent-requests")
-                        .description(
-                                "Returns all recent requests matching the 
specified path regex. "
-                                        + "Contains information about method, 
path, user id and a verbose log of internal operations, "
-                                        + "including authentication, resource 
resolution, script resolution, nested scripts/servlets and filters.")
-                        .inputSchema(jsonMapperSupplier.get(), schema)
-                        .build(),
-                (exchange, request) -> {
-                    String pathRegex = (String) 
request.arguments().get("path");
-
-                    Pattern pattern = null;
-                    if (pathRegex != null && !pathRegex.isEmpty()) {
-                        try {
-                            pattern = Pattern.compile(pathRegex, 
Pattern.CASE_INSENSITIVE);
-                        } catch (PatternSyntaxException e) {
-                            return CallToolResult.builder()
-                                    .addTextContent("Invalid regex pattern: " 
+ e.getMessage())
-                                    .isError(true)
-                                    .build();
-                        }
-                    }
-
-                    final Pattern finalPattern = pattern;
-                    String allRequests = StreamSupport.stream(
-                                    
requestInfoProvider.getRequestInfos().spliterator(), false)
-                            .filter(ri -> finalPattern == null
-                                    || 
finalPattern.matcher(ri.getPath()).find())
-                            .map(this::describe)
-                            .collect(Collectors.joining("\n\n" + 
"-".repeat(20) + "\n\n"));
-
-                    return 
CallToolResult.builder().addTextContent(allRequests).build();
-                }));
-    }
-}
diff --git 
a/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshot.java
 
b/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshot.java
deleted file mode 100644
index 80dce2f5..00000000
--- 
a/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshot.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl.contribs.internal;
-
-import java.util.Collections;
-import java.util.Map;
-
-import ch.qos.logback.classic.Level;
-
-/**
- * Stores only the lightweight, stable parts of a log event so the in-memory 
buffer
- * does not retain full {@code ILoggingEvent} object graphs.
- */
-public record LogSnapshot(
-        long timeMillis,
-        Level level,
-        String loggerName,
-        String threadName,
-        String formattedMessage,
-        String throwableText,
-        Map<String, String> mdc) {
-
-    public LogSnapshot {
-        mdc = mdc == null ? Collections.emptyMap() : 
Collections.unmodifiableMap(mdc);
-    }
-}
diff --git 
a/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBuffer.java
 
b/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBuffer.java
deleted file mode 100644
index 80c64fe3..00000000
--- 
a/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBuffer.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl.contribs.internal;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.List;
-import java.util.regex.Pattern;
-
-import ch.qos.logback.classic.Level;
-
-public class StructuredLogBuffer {
-
-    private final Object lock = new Object();
-    private final Deque<LogSnapshot> entries = new ArrayDeque<>();
-    private int maxEntriesKept;
-
-    public StructuredLogBuffer(int maxEntriesKept) {
-        this.maxEntriesKept = Math.max(1, maxEntriesKept);
-    }
-
-    public void append(LogSnapshot snapshot) {
-        synchronized (lock) {
-            entries.addLast(snapshot);
-            trimToSize();
-        }
-    }
-
-    public List<LogSnapshot> getRecent(Pattern pattern, Level minLevel, int 
maxEntries) {
-        synchronized (lock) {
-            List<LogSnapshot> matches = new ArrayList<>();
-            int remaining = Math.max(1, maxEntries);
-
-            for (var iterator = entries.descendingIterator(); 
iterator.hasNext() && remaining > 0; ) {
-                LogSnapshot snapshot = iterator.next();
-                if (!matches(snapshot, pattern, minLevel)) {
-                    continue;
-                }
-                matches.add(snapshot);
-                remaining--;
-            }
-
-            return matches;
-        }
-    }
-
-    private boolean matches(LogSnapshot snapshot, Pattern pattern, Level 
minLevel) {
-        if (snapshot.level().isGreaterOrEqual(minLevel)) {
-            if (pattern == null) {
-                return true;
-            }
-            return matchesField(pattern, snapshot.level() != null ? 
snapshot.level().levelStr : null)
-                    || matchesField(pattern, snapshot.loggerName())
-                    || matchesField(pattern, snapshot.threadName())
-                    || matchesField(pattern, snapshot.formattedMessage())
-                    || matchesField(pattern, snapshot.throwableText())
-                    || matchesMdc(pattern, snapshot);
-        }
-        return false;
-    }
-
-    private boolean matchesMdc(Pattern pattern, LogSnapshot snapshot) {
-        if (snapshot.mdc().isEmpty()) {
-            return false;
-        }
-        for (var entry : snapshot.mdc().entrySet()) {
-            if (matchesField(pattern, entry.getKey()) || matchesField(pattern, 
entry.getValue())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean matchesField(Pattern pattern, String value) {
-        return value != null && !value.isEmpty() && 
pattern.matcher(value).find();
-    }
-
-    private void trimToSize() {
-        while (entries.size() > maxEntriesKept) {
-            entries.removeFirst();
-        }
-    }
-}
diff --git 
a/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferAppender.java
 
b/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferAppender.java
deleted file mode 100644
index 95a02db0..00000000
--- 
a/mcp-server-contributions/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferAppender.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl.contribs.internal;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.classic.spi.IThrowableProxy;
-import ch.qos.logback.classic.spi.StackTraceElementProxy;
-import ch.qos.logback.core.Appender;
-import ch.qos.logback.core.AppenderBase;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.metatype.annotations.AttributeDefinition;
-import org.osgi.service.metatype.annotations.Designate;
-import org.osgi.service.metatype.annotations.ObjectClassDefinition;
-
-@Component(
-        service = {Appender.class, StructuredLogBufferAppender.class},
-        property = {
-            "loggers=ROOT",
-            "service.description=Structured in-memory MCP log appender",
-            "service.vendor=The Apache Software Foundation"
-        })
-@Designate(ocd = StructuredLogBufferAppender.Configuration.class)
-public class StructuredLogBufferAppender extends AppenderBase<ILoggingEvent> {
-
-    // Forward compatibility with logback 1.5+, where IThrowableProxy may 
expose getOverridingMessage().
-    private static final MethodHandle GET_OVERRIDING_MESSAGE = 
findGetOverridingMessage();
-
-    @ObjectClassDefinition(name = "Apache Sling MCP Structured Log Buffer")
-    public @interface Configuration {
-
-        @AttributeDefinition(name = "Max entries")
-        int maxEntries() default 10000;
-    }
-
-    private final StructuredLogBuffer buffer;
-
-    @Activate
-    public StructuredLogBufferAppender(Configuration configuration) {
-        buffer = new StructuredLogBuffer(configuration.maxEntries());
-        setName("mcp-structured-log-buffer");
-    }
-
-    public StructuredLogBuffer getBuffer() {
-        return buffer;
-    }
-
-    @Override
-    protected void append(ILoggingEvent eventObject) {
-        if (eventObject == null) {
-            return;
-        }
-
-        buffer.append(new LogSnapshot(
-                eventObject.getTimeStamp(),
-                eventObject.getLevel(),
-                eventObject.getLoggerName(),
-                eventObject.getThreadName(),
-                eventObject.getFormattedMessage(),
-                getThrowableText(eventObject),
-                copyMdc(eventObject)));
-    }
-
-    private Map<String, String> copyMdc(ILoggingEvent eventObject) {
-        Map<String, String> mdc = eventObject.getMDCPropertyMap();
-        if (mdc == null || mdc.isEmpty()) {
-            return Map.of();
-        }
-        return new LinkedHashMap<>(mdc);
-    }
-
-    private String getThrowableText(ILoggingEvent eventObject) {
-        IThrowableProxy throwableProxy = eventObject.getThrowableProxy();
-        if (throwableProxy == null) {
-            return null;
-        }
-
-        StringBuilder text = new StringBuilder();
-        appendThrowable(text, throwableProxy, null);
-        return text.toString();
-    }
-
-    private void appendThrowable(StringBuilder text, IThrowableProxy 
throwableProxy, String prefix) {
-        if (prefix != null) {
-            text.append(prefix);
-        }
-        text.append(getThrowableHeader(throwableProxy)).append('\n');
-
-        StackTraceElementProxy[] stackTrace = 
throwableProxy.getStackTraceElementProxyArray();
-        if (stackTrace != null) {
-            int framesToRender = Math.max(0, stackTrace.length - Math.max(0, 
throwableProxy.getCommonFrames()));
-            for (int i = 0; i < framesToRender; i++) {
-                text.append('\t').append(stackTrace[i]).append('\n');
-            }
-            if (throwableProxy.getCommonFrames() > 0) {
-                text.append("\t... ")
-                        .append(throwableProxy.getCommonFrames())
-                        .append(" common frames omitted")
-                        .append('\n');
-            }
-        }
-
-        IThrowableProxy[] suppressed = throwableProxy.getSuppressed();
-        if (suppressed != null) {
-            for (IThrowableProxy suppressedThrowable : suppressed) {
-                appendThrowable(text, suppressedThrowable, "Suppressed: ");
-            }
-        }
-
-        IThrowableProxy cause = throwableProxy.getCause();
-        if (cause != null) {
-            appendThrowable(text, cause, "Caused by: ");
-        }
-    }
-
-    private String getThrowableHeader(IThrowableProxy throwableProxy) {
-        String overridingMessage = getOverridingMessage(throwableProxy);
-        if (overridingMessage != null && !overridingMessage.isEmpty()) {
-            return overridingMessage;
-        }
-
-        StringBuilder header = new 
StringBuilder(throwableProxy.getClassName());
-        String message = throwableProxy.getMessage();
-        if (message != null && !message.isEmpty()) {
-            header.append(": ").append(message);
-        }
-        return header.toString();
-    }
-
-    private String getOverridingMessage(IThrowableProxy throwableProxy) {
-        if (GET_OVERRIDING_MESSAGE == null) {
-            return null;
-        }
-
-        try {
-            Object overridingMessage = 
GET_OVERRIDING_MESSAGE.invoke(throwableProxy);
-            return overridingMessage instanceof String ? (String) 
overridingMessage : null;
-        } catch (Throwable e) {
-            return null;
-        }
-    }
-
-    private static MethodHandle findGetOverridingMessage() {
-        try {
-            return MethodHandles.publicLookup()
-                    .findVirtual(IThrowableProxy.class, 
"getOverridingMessage", MethodType.methodType(String.class));
-        } catch (NoSuchMethodException | IllegalAccessException e) {
-            return null;
-        }
-    }
-}
diff --git 
a/mcp-server-contributions/src/main/resources/SLING-INF/libs/sling/mcp/prompts/new-sling-servlet.md
 
b/mcp-server-contributions/src/main/resources/SLING-INF/libs/sling/mcp/prompts/new-sling-servlet.md
deleted file mode 100644
index c92cb837..00000000
--- 
a/mcp-server-contributions/src/main/resources/SLING-INF/libs/sling/mcp/prompts/new-sling-servlet.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: "Create new Sling Servlet"
-description: "Creates a new Sling Servlet in the current project using 
annotations"
-argument.resource-type:
-  - title: Resource Type
-  - required: true
-  - description: The Sling resource type to bind this servlet to
----
-
-# Create a new Sling Servlet
-
- Create a new Sling Servlet for resource type: `{resource-type}`
- 
- Use the Sling-specific OSGi declarative services annotations - 
`@SlingServletResourceTypes` and `@Component` . 
- Configure by default with the GET method and the json extension.
- Provide a basic implementation of the doGet method that returns a JSON 
response with a message 'Hello from Sling Servlet at resource type 
{resource-type}'.
- 
\ No newline at end of file
diff --git 
a/mcp-server-contributions/src/main/resources/SLING-INF/libs/sling/mcp/prompts/troubleshoot.md
 
b/mcp-server-contributions/src/main/resources/SLING-INF/libs/sling/mcp/prompts/troubleshoot.md
deleted file mode 100644
index d5e95874..00000000
--- 
a/mcp-server-contributions/src/main/resources/SLING-INF/libs/sling/mcp/prompts/troubleshoot.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: "Troubleshooting guide"
-description: "Guide to troubleshoot common issues with Apache Sling 
applications"
----
-# Troubleshooting Guide
-
-## Overview
-This guide helps you diagnose and resolve common issues with Apache Sling MCP 
Server.
-
-## Common Issues
-
-### MCP Server Not Responding
-- Verify the MCP servlet is registered and active
-- Check OSGi component status
-- Review log files for errors
-
-### Bundle Issues
-- Check bundle state (ACTIVE, RESOLVED, INSTALLED)
-- Verify all dependencies are satisfied
-- Use the OSGi diagnostic tools
-
-### Performance Problems
-- Review recent requests and response times
-- Check system resources
-- Analyze thread dumps if available
-
-### Component Registration Issues
-- Verify component configurations
-- Check service dependencies
-- Review component lifecycle logs
-
-## Diagnostic Tools
-The MCP Server provides several diagnostic tools:
-- Bundle state inspection
-- Component resource analysis
-- Recent request tracking
-- Log file access
-- OSGi diagnostic reports
-
-## Getting Help
-If you continue to experience issues:
-1. Gather diagnostic information using the MCP tools
-2. Review the Apache Sling documentation
-3. Check the Apache Sling mailing lists
-4. File an issue in the Apache Sling JIRA
diff --git 
a/mcp-server-contributions/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferAppenderTest.java
 
b/mcp-server-contributions/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferAppenderTest.java
deleted file mode 100644
index c9064e72..00000000
--- 
a/mcp-server-contributions/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferAppenderTest.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl.contribs.internal;
-
-import java.util.List;
-import java.util.Map;
-
-import ch.qos.logback.classic.Level;
-import ch.qos.logback.classic.Logger;
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.spi.LoggingEvent;
-import org.junit.jupiter.api.Test;
-import org.osgi.util.converter.Converters;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-class StructuredLogBufferAppenderTest {
-
-    @Test
-    void appenderSnapshotsFormattedMessageAndThrowable() {
-        StructuredLogBufferAppender appender = new 
StructuredLogBufferAppender(configuration(5));
-
-        LoggerContext context = new LoggerContext();
-        appender.setContext(context);
-        Logger logger = context.getLogger("test.logger");
-        RuntimeException failure = new RuntimeException("error");
-        LoggingEvent event = new LoggingEvent(getClass().getName(), logger, 
Level.ERROR, "message", failure, null);
-        event.setMDCPropertyMap(java.util.Map.of());
-        event.setThreadName("worker-1");
-
-        appender.append(event);
-
-        List<LogSnapshot> logs = appender.getBuffer().getRecent(null, 
Level.TRACE, 10);
-        assertEquals(1, logs.size());
-        assertEquals("message", logs.get(0).formattedMessage());
-        assertEquals("worker-1", logs.get(0).threadName());
-        assertNotNull(logs.get(0).throwableText());
-    }
-
-    private StructuredLogBufferAppender.Configuration configuration(int 
maxEntries) {
-        return Converters.standardConverter()
-                .convert(Map.of("maxEntries", maxEntries))
-                .to(StructuredLogBufferAppender.Configuration.class);
-    }
-}
diff --git 
a/mcp-server-contributions/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferTest.java
 
b/mcp-server-contributions/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferTest.java
deleted file mode 100644
index d92efced..00000000
--- 
a/mcp-server-contributions/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl.contribs.internal;
-
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import ch.qos.logback.classic.Level;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-class StructuredLogBufferTest {
-
-    @Test
-    void keepsOnlyNewestEntriesWithinCapacity() {
-        StructuredLogBuffer buffer = new StructuredLogBuffer(2);
-
-        buffer.append(snapshot(1L, Level.INFO, "first"));
-        buffer.append(snapshot(2L, Level.INFO, "second"));
-        buffer.append(snapshot(3L, Level.INFO, "third"));
-
-        List<LogSnapshot> logs = buffer.getRecent(null, Level.TRACE, 10);
-        assertEquals(
-                List.of("third", "second"),
-                logs.stream().map(LogSnapshot::formattedMessage).toList());
-    }
-
-    @Test
-    void filtersByLevelAndRegex() {
-        StructuredLogBuffer buffer = new StructuredLogBuffer(10);
-
-        buffer.append(snapshot(1L, Level.DEBUG, "debug trace"));
-        buffer.append(snapshot(2L, Level.INFO, "first user ok"));
-        buffer.append(snapshot(3L, Level.ERROR, "first user failure"));
-
-        List<LogSnapshot> logs = buffer.getRecent(Pattern.compile("first", 
Pattern.CASE_INSENSITIVE), Level.INFO, 10);
-
-        assertEquals(
-                List.of("first user failure", "first user ok"),
-                logs.stream().map(LogSnapshot::formattedMessage).toList());
-    }
-
-    private LogSnapshot snapshot(long timeMillis, Level level, String message) 
{
-        return new LogSnapshot(timeMillis, level, "logger", "thread", message, 
null, Map.of());
-    }
-}

Reply via email to