Clarify McpTransportContext javadoc
See #1075 Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
This commit is contained in:
parent
e7b389f846
commit
bb0ca87da5
3 changed files with 45 additions and 6 deletions
|
|
@ -494,9 +494,10 @@ public interface McpClient {
|
|||
* calling any client operation. This allows to extract thread-locals and hand
|
||||
* them over to the underlying transport.
|
||||
* <p>
|
||||
* There is no direct equivalent in {@link AsyncSpec}. To achieve the same result,
|
||||
* append {@code contextWrite(McpTransportContext.KEY, context)} to any
|
||||
* {@link McpAsyncClient} call.
|
||||
* The supplier is invoked at subscription time, on the calling thread, and the
|
||||
* resulting context is visible to the transport for every leg of the operation,
|
||||
* including connections opened on other threads, such as the SSE stream started
|
||||
* during initialization.
|
||||
* @param contextProvider A supplier to create a context
|
||||
* @return This builder for method chaining
|
||||
*/
|
||||
|
|
@ -580,6 +581,21 @@ public interface McpClient {
|
|||
* <li>Change notification handlers for tools, resources, and prompts
|
||||
* <li>Custom message sampling logic
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Unlike {@link SyncSpec}, this specification has no
|
||||
* {@code transportContextProvider}. This is deliberate: in a reactive pipeline the
|
||||
* caller owns the Reactor context, and whatever the transport needs, such as an
|
||||
* {@link McpTransportContext}, can be written into it directly. Write it once where
|
||||
* the reactive chain starts, rather than at every call site, and every
|
||||
* {@link McpAsyncClient} call downstream inherits it, including the connections
|
||||
* opened during initialization: <pre>{@code
|
||||
* chain.filter(exchange)
|
||||
* .contextWrite(ctx -> ctx.put(McpTransportContext.KEY, context));
|
||||
* }</pre> To bridge thread-locals into the chain, use Reactor's context propagation
|
||||
* support.
|
||||
*
|
||||
* @see SyncSpec#transportContextProvider(Supplier)
|
||||
*/
|
||||
class AsyncSpec {
|
||||
|
||||
|
|
|
|||
|
|
@ -7,18 +7,26 @@ package io.modelcontextprotocol.client.transport.customizer;
|
|||
import java.net.URI;
|
||||
import java.net.http.HttpRequest;
|
||||
|
||||
import io.modelcontextprotocol.client.McpClient.SyncSpec;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import reactor.util.annotation.Nullable;
|
||||
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
|
||||
/**
|
||||
* Customize {@link HttpRequest.Builder} before executing the request, in either SSE or
|
||||
* Streamable HTTP transport.
|
||||
* <p>
|
||||
* When used in a non-blocking context, implementations MUST be non-blocking.
|
||||
* <p>
|
||||
* The {@link McpTransportContext} handed to {@code customize} is read from the Reactor
|
||||
* context, under {@link McpTransportContext#KEY}, and is
|
||||
* {@link McpTransportContext#EMPTY} when the caller wrote nothing there. Write it once
|
||||
* where the reactive chain starts, with
|
||||
* {@code contextWrite(ctx -> ctx.put(McpTransportContext.KEY, context))}, rather than at
|
||||
* every call site. With a synchronous client, configure
|
||||
* {@link SyncSpec#transportContextProvider} instead.
|
||||
*
|
||||
* @author Daniel Garnier-Moiroux
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -11,13 +11,28 @@ import java.util.Map;
|
|||
* Context associated with the transport layer. It allows to add transport-level metadata
|
||||
* for use further down the line. Specifically, it can be beneficial to extract HTTP
|
||||
* request metadata for use in MCP feature implementations.
|
||||
* <p>
|
||||
* The context travels in the Reactor context, under {@link #KEY}. On the server side, the
|
||||
* transports populate it from the incoming request. On the client side, writing it is the
|
||||
* caller's responsibility:
|
||||
* <ul>
|
||||
* <li>with a synchronous client, configure
|
||||
* {@code McpClient.SyncSpec#transportContextProvider(Supplier)}, which is invoked on the
|
||||
* calling thread before every operation;
|
||||
* <li>with an asynchronous client, write it into the Reactor context once, where the
|
||||
* reactive chain starts, using
|
||||
* {@code contextWrite(ctx -> ctx.put(McpTransportContext.KEY, context))}. Every client
|
||||
* call downstream inherits it, so there is no need to repeat it at each call site.
|
||||
* </ul>
|
||||
*
|
||||
* @author Dariusz Jędrzejczyk
|
||||
*/
|
||||
public interface McpTransportContext {
|
||||
|
||||
/**
|
||||
* Key for use in Reactor Context to transport the context to user land.
|
||||
* Key for use in Reactor Context to transport the context to user land. Write the
|
||||
* context under this key to make it visible to the transport, for example
|
||||
* {@code contextWrite(ctx -> ctx.put(McpTransportContext.KEY, context))}.
|
||||
*/
|
||||
String KEY = "MCP_TRANSPORT_CONTEXT";
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue