Class McpRestServlet
- All Implemented Interfaces:
jakarta.servlet.Servlet,jakarta.servlet.ServletConfig,Serializable,BasicUniversalConfig,DefaultConfig,DefaultHtmlConfig,ReadinessStateAware
- Direct Known Subclasses:
ExampleMcpServer
2026-07-28.
Subclass this (rather than the neutral AbstractMcpRestServlet) to
expose a 2026-07-28 endpoint at POST /; the revision binding is a compile-time choice
made by which class you extend.
URI and polymorphic-type serializer policy (addBeanTypes and uriResolution="NONE") is
inherited centrally from the neutral AbstractMcpRestServlet; the only
revision-specific behavior added here is notification empty-body processing, below.
Registers McpNotificationResponseProcessor so a null dispatch result (a JSON-RPC
notification) renders as a genuinely empty HTTP body instead of the framework's default four-byte
null JSON literal.
Example:
-
Nested Class Summary
Nested classes/interfaces inherited from class org.apache.juneau.rest.server.servlet.RestServlet
RestServlet.Builder<R extends RestServlet,SELF extends RestServlet.Builder<R, SELF>>, RestServlet.DefaultBuilder<R extends RestServlet> -
Field Summary
Fields inherited from class jakarta.servlet.http.HttpServlet
LEGACY_DO_HEAD -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprotected McpOptionsFactory method for the behavior configuration published bygetMcpOptions().final McpOptionsReturns this servlet's binding-ownedMcpOptions, built eagerly during initialization.final McpSubscriptionBrokerReturns this servlet's lazily-published, binding-owned subscription broker.Serves the RFC 9728 Protected Resource Metadata document at the path-inserted well-known location (SEP-2351), but only when the requested suffix matches this resource's expected well-known path; otherwise404.Serves the RFC 9728 Protected Resource Metadata document at the root well-known location (SEP-2351 fallback).final voidmcpResourceServerAuth(jakarta.servlet.http.HttpServletRequest req, jakarta.servlet.http.HttpServletResponse res) OAuth 2.1 resource-server bearer gate for the MCPPOST /endpoint.final TraceContextExtractorPublishes this revision's stableTraceContextExtractorso an activeTracerHook(viaRestOpInvoker) recognizes this endpoint's resolvedJsonRpcRequestargument and itsparams._metacarrier before span creation.protected final McpRevisionrevision()The MCP protocol revision this servlet speaks.Methods inherited from class org.apache.juneau.rest.server.mcp.AbstractMcpRestServlet
acceptReadinessState, createMcpConfig, getMcpConfig, handleMcpMethods inherited from class org.apache.juneau.rest.server.servlet.RestServlet
builder, createAuthenticator, destroy, doLog, getContext, getPath, getPaths, getRequest, getResponse, getRestBuilder, init, log, log, service, setContextMethods inherited from class jakarta.servlet.http.HttpServlet
doDelete, doGet, doHead, doOptions, doPatch, doPost, doPut, doTrace, getLastModified, isSensitiveHeader, serviceMethods inherited from class jakarta.servlet.GenericServlet
getInitParameter, getInitParameterNames, getServletConfig, getServletContext, getServletInfo, getServletName, init, log, log
-
Constructor Details
-
McpRestServlet
public McpRestServlet()
-
-
Method Details
-
revision
Description copied from class:AbstractMcpRestServletThe 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.- Specified by:
revisionin classAbstractMcpRestServlet- Returns:
- The bound revision. Never
null.
-
mcpTraceContextExtractor
Publishes this revision's stableTraceContextExtractorso an activeTracerHook(viaRestOpInvoker) recognizes this endpoint's resolvedJsonRpcRequestargument and itsparams._metacarrier before span creation.A no-op when no
TracerHookbean is registered — see the no-tracer fast-path contract documented onTracerHook.- Returns:
- This revision's shared
TraceContextExtractor. Nevernull .
-
createMcpOptions
Factory method for the behavior configuration published bygetMcpOptions().Override to customize any of capabilities/instructions/cache/mrtr/subscriptions/broker in one place. The default returns a plain
McpOptions(all defaults).Runs eagerly during servlet/
RestContextinitialization, not lazily on first request:getMcpOptions()is itself a@Beanhook, soRestContext's constructor invokes it — and therefore this method — while walking the resource's@Beanmethods at startup, strictly before the embedded server'sstart()returns. Do not write an override that depends on runtime request state or on a port/address only known afterstart()(e.g. a Jetty ephemeral port); that state does not exist yet when this hook runs.Must be side-effect-free and idempotent, exactly like
AbstractMcpRestServlet.createMcpConfig():getMcpOptions()calls this hook at most once per servlet instance and publishes the result via a lock-freeAtomicReference.compareAndSet(V, V), so under a first-access race it may be invoked by more than one thread, but only one resulting instance is ever published and returned.- Returns:
- A non-
null options instance.
-
getMcpOptions
Returns this servlet's binding-ownedMcpOptions, built eagerly during initialization.Because this method is annotated
@Bean,RestContext's constructor invokes it (and thereforecreateMcpOptions()) while the servlet is initializing — strictly before the embedded server'sstart()returns. This is not deferred to the first incoming HTTP request, despite the internal caching below; acreateMcpOptions()override must not depend on runtime request/port state, since none exists yet at that point. TheAtomicReference-backed publish below exists only to make repeat/racing invocations of this@Beanmethod idempotent — every call after the first returns the same instance, mirroring exactly howgetMcpConfig()memoizes — not to defer construction itself. Also published as a@Beanso downstream plumbing (getSubscriptionBroker(),subscriptions/listendispatch) can resolve it uniformly through theBeanStore. This@Beanpublication is authoritative and takes precedence over any Spring@Bean McpOptionsin the app context: a Spring user who wants their configuration honored must inject it INTOcreateMcpOptions()'s override (for example an@Autowiredfield read from there), not publish a bare@Bean McpOptionsin their Spring context and expect it to be picked up instead.- Returns:
- The options. Never
null . - Throws:
IllegalStateException- IfcreateMcpOptions()returnsnull .
-
getSubscriptionBroker
Returns this servlet's lazily-published, binding-owned subscription broker.Reads
getMcpOptions()'s memoizedMcpOptions.getSubscriptionBroker(): an explicitly configured broker is returned as-is; otherwise one is derived and memoized per-binding, sized fromMcpOptions.getSubscriptions()'s queue bound (seeMcpOptions.resolveSubscriptionBroker()).- Overrides:
getSubscriptionBrokerin classAbstractMcpRestServlet- Returns:
- The subscription broker. Never
null .
-
mcpResourceServerAuth
public final void mcpResourceServerAuth(jakarta.servlet.http.HttpServletRequest req, jakarta.servlet.http.HttpServletResponse res) OAuth 2.1 resource-server bearer gate for the MCPPOST /endpoint.A no-op unless
RS auth is enabled; when enabled, every request that is aPOST, or that claims one (the dedicated MCP servlet's only writable surface) must present a valid bearer token or it is rejected with401/403and aWWW-Authenticate: Bearer ...challenge (seeMcpResourceServerSupport.gateMcpServlet(McpResourceServerConfig, HttpServletRequest, HttpServletResponse)). The gate treats aPOSTclaim on any override channel (?method=or any of the four override headers, any value) as aPOST, rather than reading only the raw servlet method, so a method-override cannot slip past it. The well-knownGETroutes below are intentionally left unauthenticated so a client can discover the PRM document.- Parameters:
req- The raw HTTP request.res- The raw HTTP response (used to emit the challenge header on rejection).
-
mcpProtectedResourceMetadataRoot
Serves the RFC 9728 Protected Resource Metadata document at the root well-known location (SEP-2351 fallback).This route (and its path-inserted sibling) is registered unconditionally, but returns
404whenever RS auth isdisabled— so a non-opted-in servlet claims the well-known namespace but exposes no observable metadata.- Parameters:
req- The REST request.- Returns:
- The PRM document.
-
mcpProtectedResourceMetadataPathInserted
Serves the RFC 9728 Protected Resource Metadata document at the path-inserted well-known location (SEP-2351), but only when the requested suffix matches this resource's expected well-known path; otherwise404.- Parameters:
req- The REST request.- Returns:
- The PRM document.
-