Class AbstractMcpRestServlet

java.lang.Object
jakarta.servlet.GenericServlet
jakarta.servlet.http.HttpServlet
All Implemented Interfaces:
jakarta.servlet.Servlet, jakarta.servlet.ServletConfig, Serializable, BasicUniversalConfig, DefaultConfig, DefaultHtmlConfig, ReadinessStateAware
Direct Known Subclasses:
McpRestServlet, McpRestServlet

public abstract class AbstractMcpRestServlet extends BasicRestServlet implements ReadinessStateAware
Drop-in BasicRestServlet subclass that exposes a single MCP JSON-RPC endpoint at POST /.

Subclasses provide their McpServerConfig by overriding createMcpConfig() (called once at init time), or by registering an McpServerConfig bean in their RestContext bean store.

Example:
  • Constructor Details

  • Method Details

    • getMcpConfig

      Returns the McpServerConfig backing this servlet.

      The default implementation lazily caches the value of createMcpConfig(); subclasses needing per-request reconfiguration may override.

      This is invoked on every request, so the cache is published via a lock-free AtomicReference.compareAndSet(V, V) rather than a synchronized block, avoiding monitor contention on the hot path. Under a first-access race, createMcpConfig() may be invoked by more than one thread, but only one resulting instance is ever published to config and returned to any caller; the others are discarded. This is safe as long as createMcpConfig() is side-effect-free and idempotent (i.e. simply constructs and returns a new config), which is the documented contract of that method.

      Returns:
      The config. Never null.
    • createMcpConfig

      protected abstract McpServerConfig createMcpConfig()
      Factory method for the McpServerConfig backing this servlet.

      Subclasses must override this method to declare their tools, prompts, and resources.

      Returns:
      A non-null server config.
    • revision

      protected abstract McpRevision revision()
      The MCP protocol revision this servlet speaks.

      Supplied by the revision-specific subclass a consumer extends (for example org.apache.juneau.rest.server.mcp.v20250618.McpRestServlet); consumers do not normally implement this themselves.

      Returns:
      The bound revision. Never null.
    • getSubscriptionBroker

      Optional subscription broker backing this servlet's subscriptions/listen support.

      Returning null (the default) means this servlet does not support subscriptions: no McpSubscriptionBroker or McpSubscriptions bean is added to the request-scoped BeanStore that handleMcp(org.apache.juneau.bean.jsonrpc.JsonRpcRequest, org.apache.juneau.rest.server.RestRequest) builds, so any handler or dispatch branch that looks one up via ctx.getBean(McpSubscriptionBroker.class) sees Optional.empty().

      A revision binding that implements subscriptions/listen (for example org.apache.juneau.rest.server.mcp.v20260728.McpRestServlet) overrides this to return a memoized broker instance so every request sees the same live subscription registry.

      Returns:
      The subscription broker, or null if this servlet does not support subscriptions.
    • acceptReadinessState

      public void acceptReadinessState(ReadinessState state)
      Closes this servlet's open subscription streams as soon as the embedded server begins shutting down.

      A subscriptions/listen stream never finishes on its own, so without this the server's graceful drain would wait out its entire stop timeout (30s by default) for every connected subscriber before it could stop. Closing the subscriptions makes each stream send its terminal frame and complete, letting the drain finish immediately.

      Specified by:
      acceptReadinessState in interface ReadinessStateAware
      Parameters:
      state - The per-service readiness state published by the embedded-server lifecycle component.
    • handleMcp

      MCP JSON-RPC endpoint.
      Parameters:
      req - The parsed JSON-RPC request envelope.
      restReq - The HTTP request (used to surface the bean store to handlers).
      Returns:
      The JSON-RPC response, or null for notifications (which the framework renders as an empty body).