Skip to content

Custom Scanners

shvquu edited this page Jun 13, 2026 · 1 revision

Custom Scanners

ServerDoctor's analysis is fully extensible. Any plugin can register its own scanner by implementing AnalysisModule — your scanner then runs as part of every diagnostic pass alongside the built-in ones.

The AnalysisModule interface

public interface AnalysisModule {
    String id();
    default Set<Capability> requiredCapabilities() { return Set.of(); }
    AnalysisResult analyze(ServerContext context);
}
  • id() — a unique identifier (also used to unregister).
  • requiredCapabilities() — which platform capabilities your scanner needs. The engine skips your module on platforms that don't provide them (see Architecture). Default: none (runs everywhere).
  • analyze(...) — your logic. Receives a read-only ServerContext and returns an AnalysisResult.

Building a result

Use the builder — it automatically raises the result's overall severity to the highest entry you add:

public final class EntityScanner implements AnalysisModule {

    @Override public String id() { return "entity"; }

    @Override public Set<Capability> requiredCapabilities() {
        return Set.of(Capability.HAS_ENTITIES);
    }

    @Override public AnalysisResult analyze(ServerContext ctx) {
        return AnalysisResult.builder(id())
                .finding(new Finding(id(), Severity.INFO, ctx.plugins().size() + " plugins present"))
                .build();
    }
}

You can add finding(...), conflict(...), and risk(...) entries to a result.

Registering

ServerDoctorApi api = ServerDoctorProvider.get();
api.registerModule(new EntityScanner());
// later, if needed:
api.unregisterModule("entity");

What ServerContext gives you

Method Description
capabilities() / has(Capability) Platform capabilities
plugins() List<PluginInfo> of installed plugins
performance() The PerformanceSnapshot for this run
serverInfo() Platform name, version, Java version

ServerContext is read-only by design — there is no way to mutate the server through it.

Capabilities

Capability Meaning
HAS_PLUGINS A plugin manager is available
HAS_TICK_LOOP The platform ticks a world (not a proxy)
HAS_ENTITIES Entities exist
HAS_REGIONS Region-threaded scheduling (Folia)
IS_PROXY Proxy platform (Velocity/BungeeCord)

Declaring requiredCapabilities() is how you keep one scanner correct across servers and proxies — a TPS scanner declaring HAS_TICK_LOOP simply won't run on a proxy.

Clone this wiki locally