5
5
package io .modelcontextprotocol .client ;
6
6
7
7
import java .time .Duration ;
8
+ import java .util .function .Supplier ;
8
9
9
10
import org .slf4j .Logger ;
10
11
import org .slf4j .LoggerFactory ;
11
12
13
+ import io .modelcontextprotocol .server .McpTransportContext ;
12
14
import io .modelcontextprotocol .spec .McpSchema ;
13
15
import io .modelcontextprotocol .spec .McpSchema .ClientCapabilities ;
14
16
import io .modelcontextprotocol .spec .McpSchema .GetPromptRequest ;
15
17
import io .modelcontextprotocol .spec .McpSchema .GetPromptResult ;
16
18
import io .modelcontextprotocol .spec .McpSchema .ListPromptsResult ;
17
19
import io .modelcontextprotocol .util .Assert ;
20
+ import reactor .core .publisher .Mono ;
18
21
19
22
/**
20
23
* A synchronous client implementation for the Model Context Protocol (MCP) that wraps an
@@ -63,14 +66,20 @@ public class McpSyncClient implements AutoCloseable {
63
66
64
67
private final McpAsyncClient delegate ;
65
68
69
+ private final Supplier <McpTransportContext > contextProvider ;
70
+
66
71
/**
67
72
* Create a new McpSyncClient with the given delegate.
68
73
* @param delegate the asynchronous kernel on top of which this synchronous client
69
74
* provides a blocking API.
75
+ * @param contextProvider the supplier of context before calling any non-blocking
76
+ * operation on underlying delegate
70
77
*/
71
- McpSyncClient (McpAsyncClient delegate ) {
78
+ McpSyncClient (McpAsyncClient delegate , Supplier < McpTransportContext > contextProvider ) {
72
79
Assert .notNull (delegate , "The delegate can not be null" );
80
+ Assert .notNull (contextProvider , "The contextProvider can not be null" );
73
81
this .delegate = delegate ;
82
+ this .contextProvider = contextProvider ;
74
83
}
75
84
76
85
/**
@@ -177,14 +186,14 @@ public boolean closeGracefully() {
177
186
public McpSchema .InitializeResult initialize () {
178
187
// TODO: block takes no argument here as we assume the async client is
179
188
// configured with a requestTimeout at all times
180
- return this .delegate .initialize ().block ();
189
+ return withProvidedContext ( this .delegate .initialize () ).block ();
181
190
}
182
191
183
192
/**
184
193
* Send a roots/list_changed notification.
185
194
*/
186
195
public void rootsListChangedNotification () {
187
- this .delegate .rootsListChangedNotification ().block ();
196
+ withProvidedContext ( this .delegate .rootsListChangedNotification () ).block ();
188
197
}
189
198
190
199
/**
@@ -206,7 +215,7 @@ public void removeRoot(String rootUri) {
206
215
* @return
207
216
*/
208
217
public Object ping () {
209
- return this .delegate .ping ().block ();
218
+ return withProvidedContext ( this .delegate .ping () ).block ();
210
219
}
211
220
212
221
// --------------------------
@@ -224,7 +233,8 @@ public Object ping() {
224
233
* Boolean indicating if the execution failed (true) or succeeded (false/absent)
225
234
*/
226
235
public McpSchema .CallToolResult callTool (McpSchema .CallToolRequest callToolRequest ) {
227
- return this .delegate .callTool (callToolRequest ).block ();
236
+ return withProvidedContext (this .delegate .callTool (callToolRequest )).block ();
237
+
228
238
}
229
239
230
240
/**
@@ -234,7 +244,7 @@ public McpSchema.CallToolResult callTool(McpSchema.CallToolRequest callToolReque
234
244
* pagination if more tools are available
235
245
*/
236
246
public McpSchema .ListToolsResult listTools () {
237
- return this .delegate .listTools ().block ();
247
+ return withProvidedContext ( this .delegate .listTools () ).block ();
238
248
}
239
249
240
250
/**
@@ -245,7 +255,8 @@ public McpSchema.ListToolsResult listTools() {
245
255
* pagination if more tools are available
246
256
*/
247
257
public McpSchema .ListToolsResult listTools (String cursor ) {
248
- return this .delegate .listTools (cursor ).block ();
258
+ return withProvidedContext (this .delegate .listTools (cursor )).block ();
259
+
249
260
}
250
261
251
262
// --------------------------
@@ -257,7 +268,8 @@ public McpSchema.ListToolsResult listTools(String cursor) {
257
268
* @return The list of all resources result
258
269
*/
259
270
public McpSchema .ListResourcesResult listResources () {
260
- return this .delegate .listResources ().block ();
271
+ return withProvidedContext (this .delegate .listResources ()).block ();
272
+
261
273
}
262
274
263
275
/**
@@ -266,7 +278,8 @@ public McpSchema.ListResourcesResult listResources() {
266
278
* @return The list of resources result
267
279
*/
268
280
public McpSchema .ListResourcesResult listResources (String cursor ) {
269
- return this .delegate .listResources (cursor ).block ();
281
+ return withProvidedContext (this .delegate .listResources (cursor )).block ();
282
+
270
283
}
271
284
272
285
/**
@@ -275,7 +288,8 @@ public McpSchema.ListResourcesResult listResources(String cursor) {
275
288
* @return the resource content.
276
289
*/
277
290
public McpSchema .ReadResourceResult readResource (McpSchema .Resource resource ) {
278
- return this .delegate .readResource (resource ).block ();
291
+ return withProvidedContext (this .delegate .readResource (resource )).block ();
292
+
279
293
}
280
294
281
295
/**
@@ -284,15 +298,17 @@ public McpSchema.ReadResourceResult readResource(McpSchema.Resource resource) {
284
298
* @return the resource content.
285
299
*/
286
300
public McpSchema .ReadResourceResult readResource (McpSchema .ReadResourceRequest readResourceRequest ) {
287
- return this .delegate .readResource (readResourceRequest ).block ();
301
+ return withProvidedContext (this .delegate .readResource (readResourceRequest )).block ();
302
+
288
303
}
289
304
290
305
/**
291
306
* Retrieves the list of all resource templates provided by the server.
292
307
* @return The list of all resource templates result.
293
308
*/
294
309
public McpSchema .ListResourceTemplatesResult listResourceTemplates () {
295
- return this .delegate .listResourceTemplates ().block ();
310
+ return withProvidedContext (this .delegate .listResourceTemplates ()).block ();
311
+
296
312
}
297
313
298
314
/**
@@ -304,7 +320,8 @@ public McpSchema.ListResourceTemplatesResult listResourceTemplates() {
304
320
* @return The list of resource templates result.
305
321
*/
306
322
public McpSchema .ListResourceTemplatesResult listResourceTemplates (String cursor ) {
307
- return this .delegate .listResourceTemplates (cursor ).block ();
323
+ return withProvidedContext (this .delegate .listResourceTemplates (cursor )).block ();
324
+
308
325
}
309
326
310
327
/**
@@ -317,7 +334,8 @@ public McpSchema.ListResourceTemplatesResult listResourceTemplates(String cursor
317
334
* subscribe to.
318
335
*/
319
336
public void subscribeResource (McpSchema .SubscribeRequest subscribeRequest ) {
320
- this .delegate .subscribeResource (subscribeRequest ).block ();
337
+ withProvidedContext (this .delegate .subscribeResource (subscribeRequest )).block ();
338
+
321
339
}
322
340
323
341
/**
@@ -326,7 +344,8 @@ public void subscribeResource(McpSchema.SubscribeRequest subscribeRequest) {
326
344
* to unsubscribe from.
327
345
*/
328
346
public void unsubscribeResource (McpSchema .UnsubscribeRequest unsubscribeRequest ) {
329
- this .delegate .unsubscribeResource (unsubscribeRequest ).block ();
347
+ withProvidedContext (this .delegate .unsubscribeResource (unsubscribeRequest )).block ();
348
+
330
349
}
331
350
332
351
// --------------------------
@@ -338,7 +357,7 @@ public void unsubscribeResource(McpSchema.UnsubscribeRequest unsubscribeRequest)
338
357
* @return The list of all prompts result.
339
358
*/
340
359
public ListPromptsResult listPrompts () {
341
- return this .delegate .listPrompts ().block ();
360
+ return withProvidedContext ( this .delegate .listPrompts () ).block ();
342
361
}
343
362
344
363
/**
@@ -347,19 +366,21 @@ public ListPromptsResult listPrompts() {
347
366
* @return The list of prompts result.
348
367
*/
349
368
public ListPromptsResult listPrompts (String cursor ) {
350
- return this .delegate .listPrompts (cursor ).block ();
369
+ return withProvidedContext (this .delegate .listPrompts (cursor )).block ();
370
+
351
371
}
352
372
353
373
public GetPromptResult getPrompt (GetPromptRequest getPromptRequest ) {
354
- return this .delegate .getPrompt (getPromptRequest ).block ();
374
+ return withProvidedContext ( this .delegate .getPrompt (getPromptRequest ) ).block ();
355
375
}
356
376
357
377
/**
358
378
* Client can set the minimum logging level it wants to receive from the server.
359
379
* @param loggingLevel the min logging level
360
380
*/
361
381
public void setLoggingLevel (McpSchema .LoggingLevel loggingLevel ) {
362
- this .delegate .setLoggingLevel (loggingLevel ).block ();
382
+ withProvidedContext (this .delegate .setLoggingLevel (loggingLevel )).block ();
383
+
363
384
}
364
385
365
386
/**
@@ -369,7 +390,18 @@ public void setLoggingLevel(McpSchema.LoggingLevel loggingLevel) {
369
390
* @return the completion result containing suggested values.
370
391
*/
371
392
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 .get ()));
373
405
}
374
406
375
407
}
0 commit comments