55package io .modelcontextprotocol .client ;
66
77import java .time .Duration ;
8+ import java .util .function .Supplier ;
89
910import org .slf4j .Logger ;
1011import org .slf4j .LoggerFactory ;
1112
13+ import io .modelcontextprotocol .server .McpTransportContext ;
1214import io .modelcontextprotocol .spec .McpSchema ;
1315import io .modelcontextprotocol .spec .McpSchema .ClientCapabilities ;
1416import io .modelcontextprotocol .spec .McpSchema .GetPromptRequest ;
1517import io .modelcontextprotocol .spec .McpSchema .GetPromptResult ;
1618import io .modelcontextprotocol .spec .McpSchema .ListPromptsResult ;
1719import io .modelcontextprotocol .util .Assert ;
20+ import reactor .core .publisher .Mono ;
1821
1922/**
2023 * A synchronous client implementation for the Model Context Protocol (MCP) that wraps an
@@ -63,14 +66,20 @@ public class McpSyncClient implements AutoCloseable {
6366
6467 private final McpAsyncClient delegate ;
6568
69+ private final Supplier <McpTransportContext > contextProvider ;
70+
6671 /**
6772 * Create a new McpSyncClient with the given delegate.
6873 * @param delegate the asynchronous kernel on top of which this synchronous client
6974 * provides a blocking API.
75+ * @param contextProvider the supplier of context before calling any non-blocking
76+ * operation on underlying delegate
7077 */
71- McpSyncClient (McpAsyncClient delegate ) {
78+ McpSyncClient (McpAsyncClient delegate , Supplier < McpTransportContext > contextProvider ) {
7279 Assert .notNull (delegate , "The delegate can not be null" );
80+ Assert .notNull (contextProvider , "The contextProvider can not be null" );
7381 this .delegate = delegate ;
82+ this .contextProvider = contextProvider ;
7483 }
7584
7685 /**
@@ -177,14 +186,14 @@ public boolean closeGracefully() {
177186 public McpSchema .InitializeResult initialize () {
178187 // TODO: block takes no argument here as we assume the async client is
179188 // configured with a requestTimeout at all times
180- return this .delegate .initialize ().block ();
189+ return withProvidedContext ( this .delegate .initialize () ).block ();
181190 }
182191
183192 /**
184193 * Send a roots/list_changed notification.
185194 */
186195 public void rootsListChangedNotification () {
187- this .delegate .rootsListChangedNotification ().block ();
196+ withProvidedContext ( this .delegate .rootsListChangedNotification () ).block ();
188197 }
189198
190199 /**
@@ -206,7 +215,7 @@ public void removeRoot(String rootUri) {
206215 * @return
207216 */
208217 public Object ping () {
209- return this .delegate .ping ().block ();
218+ return withProvidedContext ( this .delegate .ping () ).block ();
210219 }
211220
212221 // --------------------------
@@ -224,7 +233,8 @@ public Object ping() {
224233 * Boolean indicating if the execution failed (true) or succeeded (false/absent)
225234 */
226235 public McpSchema .CallToolResult callTool (McpSchema .CallToolRequest callToolRequest ) {
227- return this .delegate .callTool (callToolRequest ).block ();
236+ return withProvidedContext (this .delegate .callTool (callToolRequest )).block ();
237+
228238 }
229239
230240 /**
@@ -234,7 +244,7 @@ public McpSchema.CallToolResult callTool(McpSchema.CallToolRequest callToolReque
234244 * pagination if more tools are available
235245 */
236246 public McpSchema .ListToolsResult listTools () {
237- return this .delegate .listTools ().block ();
247+ return withProvidedContext ( this .delegate .listTools () ).block ();
238248 }
239249
240250 /**
@@ -245,7 +255,8 @@ public McpSchema.ListToolsResult listTools() {
245255 * pagination if more tools are available
246256 */
247257 public McpSchema .ListToolsResult listTools (String cursor ) {
248- return this .delegate .listTools (cursor ).block ();
258+ return withProvidedContext (this .delegate .listTools (cursor )).block ();
259+
249260 }
250261
251262 // --------------------------
@@ -257,7 +268,8 @@ public McpSchema.ListToolsResult listTools(String cursor) {
257268 * @return The list of all resources result
258269 */
259270 public McpSchema .ListResourcesResult listResources () {
260- return this .delegate .listResources ().block ();
271+ return withProvidedContext (this .delegate .listResources ()).block ();
272+
261273 }
262274
263275 /**
@@ -266,7 +278,8 @@ public McpSchema.ListResourcesResult listResources() {
266278 * @return The list of resources result
267279 */
268280 public McpSchema .ListResourcesResult listResources (String cursor ) {
269- return this .delegate .listResources (cursor ).block ();
281+ return withProvidedContext (this .delegate .listResources (cursor )).block ();
282+
270283 }
271284
272285 /**
@@ -275,7 +288,8 @@ public McpSchema.ListResourcesResult listResources(String cursor) {
275288 * @return the resource content.
276289 */
277290 public McpSchema .ReadResourceResult readResource (McpSchema .Resource resource ) {
278- return this .delegate .readResource (resource ).block ();
291+ return withProvidedContext (this .delegate .readResource (resource )).block ();
292+
279293 }
280294
281295 /**
@@ -284,15 +298,17 @@ public McpSchema.ReadResourceResult readResource(McpSchema.Resource resource) {
284298 * @return the resource content.
285299 */
286300 public McpSchema .ReadResourceResult readResource (McpSchema .ReadResourceRequest readResourceRequest ) {
287- return this .delegate .readResource (readResourceRequest ).block ();
301+ return withProvidedContext (this .delegate .readResource (readResourceRequest )).block ();
302+
288303 }
289304
290305 /**
291306 * Retrieves the list of all resource templates provided by the server.
292307 * @return The list of all resource templates result.
293308 */
294309 public McpSchema .ListResourceTemplatesResult listResourceTemplates () {
295- return this .delegate .listResourceTemplates ().block ();
310+ return withProvidedContext (this .delegate .listResourceTemplates ()).block ();
311+
296312 }
297313
298314 /**
@@ -304,7 +320,8 @@ public McpSchema.ListResourceTemplatesResult listResourceTemplates() {
304320 * @return The list of resource templates result.
305321 */
306322 public McpSchema .ListResourceTemplatesResult listResourceTemplates (String cursor ) {
307- return this .delegate .listResourceTemplates (cursor ).block ();
323+ return withProvidedContext (this .delegate .listResourceTemplates (cursor )).block ();
324+
308325 }
309326
310327 /**
@@ -317,7 +334,8 @@ public McpSchema.ListResourceTemplatesResult listResourceTemplates(String cursor
317334 * subscribe to.
318335 */
319336 public void subscribeResource (McpSchema .SubscribeRequest subscribeRequest ) {
320- this .delegate .subscribeResource (subscribeRequest ).block ();
337+ withProvidedContext (this .delegate .subscribeResource (subscribeRequest )).block ();
338+
321339 }
322340
323341 /**
@@ -326,7 +344,8 @@ public void subscribeResource(McpSchema.SubscribeRequest subscribeRequest) {
326344 * to unsubscribe from.
327345 */
328346 public void unsubscribeResource (McpSchema .UnsubscribeRequest unsubscribeRequest ) {
329- this .delegate .unsubscribeResource (unsubscribeRequest ).block ();
347+ withProvidedContext (this .delegate .unsubscribeResource (unsubscribeRequest )).block ();
348+
330349 }
331350
332351 // --------------------------
@@ -338,7 +357,7 @@ public void unsubscribeResource(McpSchema.UnsubscribeRequest unsubscribeRequest)
338357 * @return The list of all prompts result.
339358 */
340359 public ListPromptsResult listPrompts () {
341- return this .delegate .listPrompts ().block ();
360+ return withProvidedContext ( this .delegate .listPrompts () ).block ();
342361 }
343362
344363 /**
@@ -347,19 +366,21 @@ public ListPromptsResult listPrompts() {
347366 * @return The list of prompts result.
348367 */
349368 public ListPromptsResult listPrompts (String cursor ) {
350- return this .delegate .listPrompts (cursor ).block ();
369+ return withProvidedContext (this .delegate .listPrompts (cursor )).block ();
370+
351371 }
352372
353373 public GetPromptResult getPrompt (GetPromptRequest getPromptRequest ) {
354- return this .delegate .getPrompt (getPromptRequest ).block ();
374+ return withProvidedContext ( this .delegate .getPrompt (getPromptRequest ) ).block ();
355375 }
356376
357377 /**
358378 * Client can set the minimum logging level it wants to receive from the server.
359379 * @param loggingLevel the min logging level
360380 */
361381 public void setLoggingLevel (McpSchema .LoggingLevel loggingLevel ) {
362- this .delegate .setLoggingLevel (loggingLevel ).block ();
382+ withProvidedContext (this .delegate .setLoggingLevel (loggingLevel )).block ();
383+
363384 }
364385
365386 /**
@@ -369,7 +390,18 @@ public void setLoggingLevel(McpSchema.LoggingLevel loggingLevel) {
369390 * @return the completion result containing suggested values.
370391 */
371392 public McpSchema .CompleteResult completeCompletion (McpSchema .CompleteRequest completeRequest ) {
372- return this .delegate .completeCompletion (completeRequest ).block ();
393+ return withProvidedContext (this .delegate .completeCompletion (completeRequest )).block ();
394+
395+ }
396+
397+ /**
398+ * For a given action, on assembly, capture the "context" via the
399+ * {@link #contextProvider} and store it in the Reactor context.
400+ * @param action the action to perform
401+ * @return the result of the action
402+ */
403+ private <T > Mono <T > withProvidedContext (Mono <T > action ) {
404+ return action .contextWrite (ctx -> ctx .put (McpTransportContext .KEY , this .contextProvider ));
373405 }
374406
375407}
0 commit comments