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