1+ import { Client } from '../../client/index.js' ;
2+ import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js' ;
3+ import {
4+ ListToolsRequest ,
5+ ListToolsResultSchema ,
6+ CallToolRequest ,
7+ CallToolResultSchema ,
8+ LoggingMessageNotificationSchema ,
9+ } from '../../types.js' ;
10+
11+ /**
12+ * Parallel Tool Calls MCP Client
13+ *
14+ * This client demonstrates how to:
15+ * 1. Start multiple tool calls in parallel
16+ * 2. Track notifications from each tool call using a caller parameter
17+ */
18+
19+ // Command line args processing
20+ const args = process . argv . slice ( 2 ) ;
21+ const serverUrl = args [ 0 ] || 'http://localhost:3000/mcp' ;
22+
23+ async function main ( ) : Promise < void > {
24+ console . log ( 'MCP Parallel Tool Calls Client' ) ;
25+ console . log ( '==============================' ) ;
26+ console . log ( `Connecting to server at: ${ serverUrl } ` ) ;
27+
28+ let client : Client ;
29+ let transport : StreamableHTTPClientTransport ;
30+
31+ try {
32+ // Create client with streamable HTTP transport
33+ client = new Client ( {
34+ name : 'parallel-tool-calls-client' ,
35+ version : '1.0.0'
36+ } ) ;
37+
38+ client . onerror = ( error ) => {
39+ console . error ( 'Client error:' , error ) ;
40+ } ;
41+
42+ // Connect to the server
43+ transport = new StreamableHTTPClientTransport ( new URL ( serverUrl ) ) ;
44+ await client . connect ( transport ) ;
45+ console . log ( 'Successfully connected to MCP server' ) ;
46+
47+ // Set up notification handler with caller identification
48+ client . setNotificationHandler ( LoggingMessageNotificationSchema , ( notification ) => {
49+ console . log ( `Notification: ${ notification . params . data } ` ) ;
50+ } ) ;
51+
52+ console . log ( "List tools" )
53+ const toolsRequest = await listTools ( client ) ;
54+ console . log ( "Tools: " , toolsRequest )
55+
56+
57+ // 2. Start multiple notification tools in parallel
58+ console . log ( '\n=== Starting Multiple Notification Streams in Parallel ===' ) ;
59+ const toolResults = await startParallelNotificationTools ( client ) ;
60+
61+ // Log the results from each tool call
62+ for ( const [ caller , result ] of Object . entries ( toolResults ) ) {
63+ console . log ( `\n=== Tool result for ${ caller } ===` ) ;
64+ result . content . forEach ( ( item : { type : string ; text : any ; } ) => {
65+ if ( item . type === 'text' ) {
66+ console . log ( ` ${ item . text } ` ) ;
67+ } else {
68+ console . log ( ` ${ item . type } content:` , item ) ;
69+ }
70+ } ) ;
71+ }
72+
73+ // 3. Wait for all notifications (10 seconds)
74+ console . log ( '\n=== Waiting for all notifications ===' ) ;
75+ await new Promise ( resolve => setTimeout ( resolve , 10000 ) ) ;
76+
77+ // 4. Disconnect
78+ console . log ( '\n=== Disconnecting ===' ) ;
79+ await transport . close ( ) ;
80+ console . log ( 'Disconnected from MCP server' ) ;
81+
82+ } catch ( error ) {
83+ console . error ( 'Error running client:' , error ) ;
84+ process . exit ( 1 ) ;
85+ }
86+ }
87+
88+ /**
89+ * List available tools on the server
90+ */
91+ async function listTools ( client : Client ) : Promise < void > {
92+ try {
93+ const toolsRequest : ListToolsRequest = {
94+ method : 'tools/list' ,
95+ params : { }
96+ } ;
97+ const toolsResult = await client . request ( toolsRequest , ListToolsResultSchema ) ;
98+
99+ console . log ( 'Available tools:' ) ;
100+ if ( toolsResult . tools . length === 0 ) {
101+ console . log ( ' No tools available' ) ;
102+ } else {
103+ for ( const tool of toolsResult . tools ) {
104+ console . log ( ` - ${ tool . name } : ${ tool . description } ` ) ;
105+ }
106+ }
107+ } catch ( error ) {
108+ console . log ( `Tools not supported by this server: ${ error } ` ) ;
109+ }
110+ }
111+
112+ /**
113+ * Start multiple notification tools in parallel with different configurations
114+ * Each tool call includes a caller parameter to identify its notifications
115+ */
116+ async function startParallelNotificationTools ( client : Client ) : Promise < Record < string , any > > {
117+ try {
118+ // Define multiple tool calls with different configurations
119+ const toolCalls = [
120+ {
121+ caller : 'fast-notifier' ,
122+ request : {
123+ method : 'tools/call' ,
124+ params : {
125+ name : 'start-notification-stream' ,
126+ arguments : {
127+ interval : 2 , // 0.5 second between notifications
128+ count : 10 , // Send 10 notifications
129+ caller : 'fast-notifier' // Identify this tool call
130+ }
131+ }
132+ }
133+ } ,
134+ {
135+ caller : 'slow-notifier' ,
136+ request : {
137+ method : 'tools/call' ,
138+ params : {
139+ name : 'start-notification-stream' ,
140+ arguments : {
141+ interval : 5 , // 2 seconds between notifications
142+ count : 5 , // Send 5 notifications
143+ caller : 'slow-notifier' // Identify this tool call
144+ }
145+ }
146+ }
147+ } ,
148+ {
149+ caller : 'burst-notifier' ,
150+ request : {
151+ method : 'tools/call' ,
152+ params : {
153+ name : 'start-notification-stream' ,
154+ arguments : {
155+ interval : 1 , // 0.1 second between notifications
156+ count : 3 , // Send just 3 notifications
157+ caller : 'burst-notifier' // Identify this tool call
158+ }
159+ }
160+ }
161+ }
162+ ] ;
163+
164+ console . log ( `Starting ${ toolCalls . length } notification tools in parallel...` ) ;
165+
166+ // Start all tool calls in parallel
167+ const toolPromises = toolCalls . map ( ( { caller, request } ) => {
168+ console . log ( `Starting tool call for ${ caller } ...` ) ;
169+ return client . request ( request , CallToolResultSchema )
170+ . then ( result => ( { caller, result } ) )
171+ . catch ( error => {
172+ console . error ( `Error in tool call for ${ caller } :` , error ) ;
173+ throw error ;
174+ } ) ;
175+ } ) ;
176+
177+ // Wait for all tool calls to complete
178+ const results = await Promise . all ( toolPromises ) ;
179+
180+ // Organize results by caller
181+ const resultsByTool : Record < string , any > = { } ;
182+ results . forEach ( ( { caller, result } ) => {
183+ resultsByTool [ caller ] = result ;
184+ } ) ;
185+
186+ return resultsByTool ;
187+ } catch ( error ) {
188+ console . error ( `Error starting parallel notification tools:` , error ) ;
189+ throw error ;
190+ }
191+ }
192+
193+ // Start the client
194+ main ( ) . catch ( ( error : unknown ) => {
195+ console . error ( 'Error running MCP client:' , error ) ;
196+ process . exit ( 1 ) ;
197+ } ) ;
0 commit comments